[kernel][vm] Add ZX_INFO_VMO to zx_object_get_info.
Adds ZX_INFO_VMO option to zx_object_get_info(). Returning back
the various vmo attributes.
ZX-2327.
Test: Added a unit test to query vmo attributes with ZX_INFO_VMO
to the vmo-test.
Change-Id: Ic16452aea3b71061b21141fa5c7a17b5a1f277ff
diff --git a/docs/syscalls/object_get_info.md b/docs/syscalls/object_get_info.md
index 007cfbc..2b4c440 100644
--- a/docs/syscalls/object_get_info.md
+++ b/docs/syscalls/object_get_info.md
@@ -298,6 +298,57 @@
This returns a single *zx_info_vmar_t* that describes the range of address
space that the VMAR occupies.
+### ZX_INFO_VMO
+
+*handle* type: **VM Object**
+
+*buffer* type: **zx_info_vmo_t[1]**
+
+```
+typedef struct zx_info_vmo {
+ // The koid of this VMO.
+ zx_koid_t koid;
+
+ // The name of this VMO.
+ char name[ZX_MAX_NAME_LEN];
+
+ // The size of this VMO.
+ uint64_t size_bytes;
+
+ // If this VMO is a clone, the koid of its parent. Otherwise, zero.
+ zx_koid_t parent_koid;
+
+ // The number of clones of this VMO, if any.
+ size_t num_children;
+
+ // The number of times this VMO is currently mapped into VMARs.
+ size_t num_mappings;
+
+ // An estimate of the number of unique address spaces that
+ // this VMO is mapped into.
+ size_t share_count;
+
+ // Bitwise OR of ZX_INFO_VMO_* values.
+ uint32_t flags;
+
+ // If |ZX_INFO_VMO_TYPE(flags) == ZX_INFO_VMO_TYPE_PAGED|, the amount of
+ // memory currently allocated to this VMO.
+ uint64_t committed_bytes;
+
+ // If |flags & ZX_INFO_VMO_VIA_HANDLE|, the handle rights.
+ // Undefined otherwise.
+ zx_rights_t handle_rights;
+
+ // VMO creation options. This is a bitmask of
+ // kResizable = (1u << 0);
+ // kContiguous = (1u << 1);
+ uint32_t create_options;
+} zx_info_vmo_t;
+```
+
+This returns a single *zx_info_vmo_t* that describes various attrubutes of
+the VMO.
+
### ZX_INFO_SOCKET
*handle* type: **Socket**
diff --git a/kernel/object/diagnostics.cpp b/kernel/object/diagnostics.cpp
index 666ae7e..3cbc009 100644
--- a/kernel/object/diagnostics.cpp
+++ b/kernel/object/diagnostics.cpp
@@ -553,29 +553,6 @@
}
namespace {
-zx_info_vmo_t VmoToInfoEntry(const VmObject* vmo,
- bool is_handle, zx_rights_t handle_rights) {
- zx_info_vmo_t entry = {};
- entry.koid = vmo->user_id();
- vmo->get_name(entry.name, sizeof(entry.name));
- entry.size_bytes = vmo->size();
- entry.parent_koid = vmo->parent_user_id();
- entry.num_children = vmo->num_children();
- entry.num_mappings = vmo->num_mappings();
- entry.share_count = vmo->share_count();
- entry.flags =
- (vmo->is_paged() ? ZX_INFO_VMO_TYPE_PAGED : ZX_INFO_VMO_TYPE_PHYSICAL) |
- (vmo->is_cow_clone() ? ZX_INFO_VMO_IS_COW_CLONE : 0);
- entry.committed_bytes = vmo->AllocatedPages() * PAGE_SIZE;
- if (is_handle) {
- entry.flags |= ZX_INFO_VMO_VIA_HANDLE;
- entry.handle_rights = handle_rights;
- } else {
- entry.flags |= ZX_INFO_VMO_VIA_MAPPING;
- }
- return entry;
-}
-
// Builds a list of all VMOs mapped into a VmAspace.
class AspaceVmoEnumerator final : public VmEnumerator {
public:
diff --git a/kernel/object/include/object/vm_object_dispatcher.h b/kernel/object/include/object/vm_object_dispatcher.h
index 22b5687..0bfca36 100644
--- a/kernel/object/include/object/vm_object_dispatcher.h
+++ b/kernel/object/include/object/vm_object_dispatcher.h
@@ -49,6 +49,8 @@
zx_status_t SetMappingCachePolicy(uint32_t cache_policy);
+ zx_info_vmo_t GetVmoInfo();
+
const fbl::RefPtr<VmObject>& vmo() const { return vmo_; }
private:
@@ -66,3 +68,6 @@
// shares the same lock.
CookieJar cookie_jar_;
};
+
+zx_info_vmo_t VmoToInfoEntry(const VmObject* vmo,
+ bool is_handle, zx_rights_t handle_rights);
diff --git a/kernel/object/vm_object_dispatcher.cpp b/kernel/object/vm_object_dispatcher.cpp
index 69c6161..807a44b 100644
--- a/kernel/object/vm_object_dispatcher.cpp
+++ b/kernel/object/vm_object_dispatcher.cpp
@@ -95,6 +95,35 @@
return ZX_OK;
}
+zx_info_vmo_t VmoToInfoEntry(const VmObject* vmo,
+ bool is_handle, zx_rights_t handle_rights) {
+ zx_info_vmo_t entry = {};
+ entry.koid = vmo->user_id();
+ vmo->get_name(entry.name, sizeof(entry.name));
+ entry.size_bytes = vmo->size();
+ entry.create_options = vmo->create_options();
+ entry.parent_koid = vmo->parent_user_id();
+ entry.num_children = vmo->num_children();
+ entry.num_mappings = vmo->num_mappings();
+ entry.share_count = vmo->share_count();
+ entry.flags =
+ (vmo->is_paged() ? ZX_INFO_VMO_TYPE_PAGED : ZX_INFO_VMO_TYPE_PHYSICAL) |
+ (vmo->is_cow_clone() ? ZX_INFO_VMO_IS_COW_CLONE : 0);
+ entry.committed_bytes = vmo->AllocatedPages() * PAGE_SIZE;
+ if (is_handle) {
+ entry.flags |= ZX_INFO_VMO_VIA_HANDLE;
+ entry.handle_rights = handle_rights;
+ } else {
+ entry.flags |= ZX_INFO_VMO_VIA_MAPPING;
+ }
+ return entry;
+}
+
+zx_info_vmo_t VmObjectDispatcher::GetVmoInfo(void)
+{
+ return VmoToInfoEntry(vmo().get(), true, 0);
+}
+
zx_status_t VmObjectDispatcher::RangeOp(uint32_t op, uint64_t offset, uint64_t size,
user_inout_ptr<void> buffer, size_t buffer_size,
zx_rights_t rights) {
diff --git a/kernel/syscalls/object.cpp b/kernel/syscalls/object.cpp
index c9d28b3..fe83a25 100644
--- a/kernel/syscalls/object.cpp
+++ b/kernel/syscalls/object.cpp
@@ -28,6 +28,7 @@
#include <object/socket_dispatcher.h>
#include <object/thread_dispatcher.h>
#include <object/vm_address_region_dispatcher.h>
+#include <object/vm_object_dispatcher.h>
#include <fbl/ref_ptr.h>
@@ -386,6 +387,35 @@
}
return status;
}
+ case ZX_INFO_VMO: {
+ // lookup the dispatcher from handle
+ fbl::RefPtr<VmObjectDispatcher> vmo;
+ zx_status_t status = up->GetDispatcher(handle, &vmo);
+ if (status < 0)
+ return status;
+ auto vmos = _buffer.reinterpret<zx_info_vmo_t>();
+ zx_info_vmo_t entry;
+
+ entry = vmo->GetVmoInfo();
+ if (vmos.copy_array_to_user(&entry, 1, 0) != ZX_OK) {
+ return ZX_ERR_INVALID_ARGS;
+ }
+ if (_actual) {
+ size_t count = 1;
+ zx_status_t status = _actual.copy_to_user(count);
+ if (status != ZX_OK)
+ return status;
+ }
+ // Avail returned is 0, since we were just asked to read
+ // the info for a single vmo, hence nothing more is available (?)
+ if (_avail) {
+ size_t count = 0;
+ zx_status_t status = _avail.copy_to_user(count);
+ if (status != ZX_OK)
+ return status;
+ }
+ return status;
+ }
case ZX_INFO_VMAR: {
fbl::RefPtr<VmAddressRegionDispatcher> vmar;
zx_status_t status = up->GetDispatcher(handle, &vmar);
diff --git a/kernel/vm/include/vm/vm_object.h b/kernel/vm/include/vm/vm_object.h
index b492b01..ad90330 100644
--- a/kernel/vm/include/vm/vm_object.h
+++ b/kernel/vm/include/vm/vm_object.h
@@ -47,6 +47,7 @@
virtual zx_status_t ResizeLocked(uint64_t size) TA_REQ(lock_) { return ZX_ERR_NOT_SUPPORTED; }
virtual uint64_t size() const { return 0; }
+ virtual uint32_t create_options() const { return 0; }
// Returns true if the object is backed by RAM.
virtual bool is_paged() const { return false; }
diff --git a/kernel/vm/include/vm/vm_object_paged.h b/kernel/vm/include/vm/vm_object_paged.h
index 00bacf5..e5c02fd 100644
--- a/kernel/vm/include/vm/vm_object_paged.h
+++ b/kernel/vm/include/vm/vm_object_paged.h
@@ -46,6 +46,7 @@
zx_status_t Resize(uint64_t size) override;
zx_status_t ResizeLocked(uint64_t size) override TA_REQ(lock_);
+ uint32_t create_options() const override { return options_; }
uint64_t size() const override
// TODO: Figure out whether it's safe to lock here without causing
// any deadlocks.
diff --git a/system/public/zircon/syscalls/object.h b/system/public/zircon/syscalls/object.h
index 7ef8df6..59ed23d 100644
--- a/system/public/zircon/syscalls/object.h
+++ b/system/public/zircon/syscalls/object.h
@@ -34,6 +34,7 @@
ZX_INFO_BTI = 20, // zx_info_bti_t[1]
ZX_INFO_PROCESS_HANDLE_STATS = 21, // zx_info_process_handle_stats_t[1]
ZX_INFO_SOCKET = 22, // zx_info_socket_t[1]
+ ZX_INFO_VMO = 23, // zx_info_vmo_t[1]
} zx_object_info_topic_t;
typedef uint32_t zx_obj_props_t;
@@ -292,6 +293,11 @@
// If |flags & ZX_INFO_VMO_VIA_HANDLE|, the handle rights.
// Undefined otherwise.
zx_rights_t handle_rights;
+
+ // VMO creation options. This is a bitmask of
+ // kResizable = (1u << 0);
+ // kContiguous = (1u << 1);
+ uint32_t create_options;
} zx_info_vmo_t;
// kernel statistics per cpu
diff --git a/system/utest/vmo/vmo.cpp b/system/utest/vmo/vmo.cpp
index f731fcb..2fabe3d 100644
--- a/system/utest/vmo/vmo.cpp
+++ b/system/utest/vmo/vmo.cpp
@@ -407,6 +407,51 @@
return vmo_no_resize_helper(vmo, len);
}
+bool vmo_info_test() {
+ size_t len = PAGE_SIZE * 4;
+ zx_handle_t vmo = ZX_HANDLE_INVALID;
+ zx_info_vmo_t info;
+ zx_status_t status;
+
+ // Create a non-resizeable VMO, query the INFO on it
+ // and dump it.
+ status = zx_vmo_create(len, ZX_VMO_NON_RESIZABLE, &vmo);
+ EXPECT_EQ(ZX_OK, status, "vm_info_test: vmo_create");
+
+ status = zx_object_get_info(vmo, ZX_INFO_VMO, &info,
+ sizeof(info), nullptr, nullptr);
+ EXPECT_EQ(ZX_OK, status, "vm_info_test: info_vmo");
+
+ status = zx_handle_close(vmo);
+ EXPECT_EQ(ZX_OK, status, "vm_info_test: handle_close");
+
+ EXPECT_EQ(info.size_bytes, len, "vm_info_test: info_vmo.size_bytes");
+ EXPECT_NE(info.create_options, (1u << 0),
+ "vm_info_test: info_vmo.create_options");
+// printf("NON_Resizeable VMO, size = %lu, create_options = %ux\n",
+// info.size_bytes, info.create_options);
+
+ // Create a resizeable VMO, query the INFO on it and dump it.
+ len = PAGE_SIZE * 8;
+ zx_vmo_create(len, 0, &vmo);
+ EXPECT_EQ(ZX_OK, status, "vm_info_test: vmo_create");
+
+ status = zx_object_get_info(vmo, ZX_INFO_VMO, &info,
+ sizeof(info), nullptr, nullptr);
+ EXPECT_EQ(ZX_OK, status, "vm_info_test: info_vmo");
+
+ status = zx_handle_close(vmo);
+ EXPECT_EQ(ZX_OK, status, "vm_info_test: handle_close");
+
+ EXPECT_EQ(info.size_bytes, len, "vm_info_test: info_vmo.size_bytes");
+ EXPECT_EQ(info.create_options, (1u << 0),
+ "vm_info_test: info_vmo.create_options");
+// printf("Resizeable VMO, size = %lu, create_options = %ux\n",
+// info.size_bytes, info.create_options);
+
+ END_TEST;
+}
+
bool vmo_no_resize_clone_test() {
const size_t len = PAGE_SIZE * 4;
zx_handle_t vmo = ZX_HANDLE_INVALID;
@@ -1748,6 +1793,7 @@
RUN_TEST(vmo_resize_hazard);
RUN_TEST(vmo_clone_resize_clone_hazard);
RUN_TEST(vmo_clone_resize_parent_ok);
+RUN_TEST(vmo_info_test);
RUN_TEST_LARGE(vmo_unmap_coherency);
END_TEST_CASE(vmo_tests)