diff options
author | Flavio Cruz <flaviocruz@gmail.com> | 2024-02-19 23:58:00 -0500 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2024-03-11 23:48:10 +0100 |
commit | 661835c91d14a41755c5f340ba0257c6ca8db1a1 (patch) | |
tree | fe1a18724d73eede6bc5c7c72858b74a8efe4bdd /ipc/ipc_kmsg.c | |
parent | afec41f9d80cb1f923d0d4f76af832b036dc2f4f (diff) | |
download | gnumach-661835c91d14a41755c5f340ba0257c6ca8db1a1.tar.gz gnumach-661835c91d14a41755c5f340ba0257c6ca8db1a1.tar.bz2 gnumach-661835c91d14a41755c5f340ba0257c6ca8db1a1.zip |
x86_64: avoid iterating over the message twice in copyoutmsg/copyinmsg for faster RPCs.
This is a follow up to
https://git.savannah.gnu.org/cgit/hurd/gnumach.git/commit/?id=69620634858b2992e1a362e33c95d9a8ee57bce7
where we made inlined ports 8 bytes long to avoid resizing.
The last thing that copy{in,out}msg were doing was just updating
msgt_size field since that's required for kernel stub code and implicitly
assumed by IPC code. This was moved into ipc_kmsg_copy{in,out}_body.
For a 32 bit userland, the code also stops updating
msgt_size for out of line ports, same as the 64 bit userland.
Message-ID: <ZdQxWNSieTHcpM1b@jupiter.tail36e24.ts.net>
Diffstat (limited to 'ipc/ipc_kmsg.c')
-rw-r--r-- | ipc/ipc_kmsg.c | 52 |
1 files changed, 37 insertions, 15 deletions
diff --git a/ipc/ipc_kmsg.c b/ipc/ipc_kmsg.c index 8bd645ff..179c43fa 100644 --- a/ipc/ipc_kmsg.c +++ b/ipc/ipc_kmsg.c @@ -1321,7 +1321,7 @@ ipc_kmsg_copyin_body( mach_msg_type_number_t number; boolean_t is_inline, longform, dealloc, is_port; vm_offset_t data; - uint64_t length; + vm_size_t length; kern_return_t kr; type = (mach_msg_type_long_t *) saddr; @@ -1355,7 +1355,8 @@ ipc_kmsg_copyin_body( is_port = MACH_MSG_TYPE_PORT_ANY(name); - if ((is_port && (size != PORT_T_SIZE_IN_BITS)) || + if ((is_port && !is_inline && (size != PORT_NAME_T_SIZE_IN_BITS)) || + (is_port && is_inline && (size != PORT_T_SIZE_IN_BITS)) || #ifndef __x86_64__ (longform && ((type->msgtl_header.msgt_name != 0) || (type->msgtl_header.msgt_size != 0) || @@ -1396,11 +1397,22 @@ ipc_kmsg_copyin_body( if (length == 0) data = 0; else if (is_port) { + const vm_size_t user_length = length; + /* + * In 64 bit architectures, out of line port names are + * represented as an array of mach_port_name_t which are + * smaller than mach_port_t. + */ + if (sizeof(mach_port_name_t) != sizeof(mach_port_t)) { + length = sizeof(mach_port_t) * number; + type->msgtl_size = sizeof(mach_port_t) * 8; + } + data = kalloc(length); if (data == 0) goto invalid_memory; - if (sizeof(mach_port_name_t) != sizeof(mach_port_t)) + if (user_length != length) { mach_port_name_t *src = (mach_port_name_t*)addr; mach_port_t *dst = (mach_port_t*)data; @@ -1416,7 +1428,7 @@ ipc_kmsg_copyin_body( goto invalid_memory; } if (dealloc && - (vm_deallocate(map, addr, length) != KERN_SUCCESS)) { + (vm_deallocate(map, addr, user_length) != KERN_SUCCESS)) { kfree(data, length); goto invalid_memory; } @@ -2372,7 +2384,7 @@ ipc_kmsg_copyout_body( mach_msg_type_size_t size; mach_msg_type_number_t number; boolean_t is_inline, longform, is_port; - uint64_t length; + vm_size_t length; vm_offset_t addr; type = (mach_msg_type_long_t *) saddr; @@ -2406,18 +2418,28 @@ ipc_kmsg_copyout_body( ipc_object_t *objects; mach_msg_type_number_t i; - if (!is_inline && (length != 0)) { - /* first allocate memory in the map */ - uint64_t allocated = length; + if (!is_inline) { + if (length != 0) { + vm_size_t user_length = length; - _Static_assert(sizeof(mach_port_name_t) <= sizeof(mach_port_t), - "Size of mach_port_t should be equal or larger than mach_port_name_t."); - allocated -= (sizeof(mach_port_t) - sizeof(mach_port_name_t)) * number; + if (sizeof(mach_port_name_t) != sizeof(mach_port_t)) { + user_length = sizeof(mach_port_name_t) * number; + } - kr = vm_allocate(map, &addr, allocated, TRUE); - if (kr != KERN_SUCCESS) { - ipc_kmsg_clean_body(taddr, saddr); - goto vm_copyout_failure; + /* first allocate memory in the map */ + kr = vm_allocate(map, &addr, user_length, TRUE); + if (kr != KERN_SUCCESS) { + ipc_kmsg_clean_body(taddr, saddr); + goto vm_copyout_failure; + } + } + + if (sizeof(mach_port_name_t) != sizeof(mach_port_t)) { + /* Out of line ports are always returned as mach_port_name_t. + * Note: we have to do this after ipc_kmsg_clean_body, otherwise + * the cleanup function will not work correctly. + */ + type->msgtl_size = sizeof(mach_port_name_t) * 8; } } |