aboutsummaryrefslogtreecommitdiff
path: root/ipc/ipc_kmsg.c
diff options
context:
space:
mode:
authorFlavio Cruz <flaviocruz@gmail.com>2024-02-19 23:58:00 -0500
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2024-03-11 23:48:10 +0100
commit661835c91d14a41755c5f340ba0257c6ca8db1a1 (patch)
treefe1a18724d73eede6bc5c7c72858b74a8efe4bdd /ipc/ipc_kmsg.c
parentafec41f9d80cb1f923d0d4f76af832b036dc2f4f (diff)
downloadgnumach-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.c52
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;
}
}