mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
fcf634098c
The basic idea behind cross memory attach is to allow MPI programs doing intra-node communication to do a single copy of the message rather than a double copy of the message via shared memory. The following patch attempts to achieve this by allowing a destination process, given an address and size from a source process, to copy memory directly from the source process into its own address space via a system call. There is also a symmetrical ability to copy from the current process's address space into a destination process's address space. - Use of /proc/pid/mem has been considered, but there are issues with using it: - Does not allow for specifying iovecs for both src and dest, assuming preadv or pwritev was implemented either the area read from or written to would need to be contiguous. - Currently mem_read allows only processes who are currently ptrace'ing the target and are still able to ptrace the target to read from the target. This check could possibly be moved to the open call, but its not clear exactly what race this restriction is stopping (reason appears to have been lost) - Having to send the fd of /proc/self/mem via SCM_RIGHTS on unix domain socket is a bit ugly from a userspace point of view, especially when you may have hundreds if not (eventually) thousands of processes that all need to do this with each other - Doesn't allow for some future use of the interface we would like to consider adding in the future (see below) - Interestingly reading from /proc/pid/mem currently actually involves two copies! (But this could be fixed pretty easily) As mentioned previously use of vmsplice instead was considered, but has problems. Since you need the reader and writer working co-operatively if the pipe is not drained then you block. Which requires some wrapping to do non blocking on the send side or polling on the receive. In all to all communication it requires ordering otherwise you can deadlock. And in the example of many MPI tasks writing to one MPI task vmsplice serialises the copying. There are some cases of MPI collectives where even a single copy interface does not get us the performance gain we could. For example in an MPI_Reduce rather than copy the data from the source we would like to instead use it directly in a mathops (say the reduce is doing a sum) as this would save us doing a copy. We don't need to keep a copy of the data from the source. I haven't implemented this, but I think this interface could in the future do all this through the use of the flags - eg could specify the math operation and type and the kernel rather than just copying the data would apply the specified operation between the source and destination and store it in the destination. Although we don't have a "second user" of the interface (though I've had some nibbles from people who may be interested in using it for intra process messaging which is not MPI). This interface is something which hardware vendors are already doing for their custom drivers to implement fast local communication. And so in addition to this being useful for OpenMPI it would mean the driver maintainers don't have to fix things up when the mm changes. There was some discussion about how much faster a true zero copy would go. Here's a link back to the email with some testing I did on that: http://marc.info/?l=linux-mm&m=130105930902915&w=2 There is a basic man page for the proposed interface here: http://ozlabs.org/~cyeoh/cma/process_vm_readv.txt This has been implemented for x86 and powerpc, other architecture should mainly (I think) just need to add syscall numbers for the process_vm_readv and process_vm_writev. There are 32 bit compatibility versions for 64-bit kernels. For arch maintainers there are some simple tests to be able to quickly verify that the syscalls are working correctly here: http://ozlabs.org/~cyeoh/cma/cma-test-20110718.tgz Signed-off-by: Chris Yeoh <yeohc@au1.ibm.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: David Howells <dhowells@redhat.com> Cc: James Morris <jmorris@namei.org> Cc: <linux-man@vger.kernel.org> Cc: <linux-arch@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
142 lines
3.6 KiB
C
142 lines
3.6 KiB
C
/* 32-bit compatibility syscall for 64-bit systems
|
|
*
|
|
* Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*/
|
|
|
|
#include <linux/syscalls.h>
|
|
#include <linux/keyctl.h>
|
|
#include <linux/compat.h>
|
|
#include <linux/slab.h>
|
|
#include "internal.h"
|
|
|
|
/*
|
|
* Instantiate a key with the specified compatibility multipart payload and
|
|
* link the key into the destination keyring if one is given.
|
|
*
|
|
* The caller must have the appropriate instantiation permit set for this to
|
|
* work (see keyctl_assume_authority). No other permissions are required.
|
|
*
|
|
* If successful, 0 will be returned.
|
|
*/
|
|
long compat_keyctl_instantiate_key_iov(
|
|
key_serial_t id,
|
|
const struct compat_iovec __user *_payload_iov,
|
|
unsigned ioc,
|
|
key_serial_t ringid)
|
|
{
|
|
struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
|
|
long ret;
|
|
|
|
if (_payload_iov == 0 || ioc == 0)
|
|
goto no_payload;
|
|
|
|
ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc,
|
|
ARRAY_SIZE(iovstack),
|
|
iovstack, &iov, 1);
|
|
if (ret < 0)
|
|
return ret;
|
|
if (ret == 0)
|
|
goto no_payload_free;
|
|
|
|
ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
|
|
|
|
if (iov != iovstack)
|
|
kfree(iov);
|
|
return ret;
|
|
|
|
no_payload_free:
|
|
if (iov != iovstack)
|
|
kfree(iov);
|
|
no_payload:
|
|
return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
|
|
}
|
|
|
|
/*
|
|
* The key control system call, 32-bit compatibility version for 64-bit archs
|
|
*
|
|
* This should only be called if the 64-bit arch uses weird pointers in 32-bit
|
|
* mode or doesn't guarantee that the top 32-bits of the argument registers on
|
|
* taking a 32-bit syscall are zero. If you can, you should call sys_keyctl()
|
|
* directly.
|
|
*/
|
|
asmlinkage long compat_sys_keyctl(u32 option,
|
|
u32 arg2, u32 arg3, u32 arg4, u32 arg5)
|
|
{
|
|
switch (option) {
|
|
case KEYCTL_GET_KEYRING_ID:
|
|
return keyctl_get_keyring_ID(arg2, arg3);
|
|
|
|
case KEYCTL_JOIN_SESSION_KEYRING:
|
|
return keyctl_join_session_keyring(compat_ptr(arg2));
|
|
|
|
case KEYCTL_UPDATE:
|
|
return keyctl_update_key(arg2, compat_ptr(arg3), arg4);
|
|
|
|
case KEYCTL_REVOKE:
|
|
return keyctl_revoke_key(arg2);
|
|
|
|
case KEYCTL_DESCRIBE:
|
|
return keyctl_describe_key(arg2, compat_ptr(arg3), arg4);
|
|
|
|
case KEYCTL_CLEAR:
|
|
return keyctl_keyring_clear(arg2);
|
|
|
|
case KEYCTL_LINK:
|
|
return keyctl_keyring_link(arg2, arg3);
|
|
|
|
case KEYCTL_UNLINK:
|
|
return keyctl_keyring_unlink(arg2, arg3);
|
|
|
|
case KEYCTL_SEARCH:
|
|
return keyctl_keyring_search(arg2, compat_ptr(arg3),
|
|
compat_ptr(arg4), arg5);
|
|
|
|
case KEYCTL_READ:
|
|
return keyctl_read_key(arg2, compat_ptr(arg3), arg4);
|
|
|
|
case KEYCTL_CHOWN:
|
|
return keyctl_chown_key(arg2, arg3, arg4);
|
|
|
|
case KEYCTL_SETPERM:
|
|
return keyctl_setperm_key(arg2, arg3);
|
|
|
|
case KEYCTL_INSTANTIATE:
|
|
return keyctl_instantiate_key(arg2, compat_ptr(arg3), arg4,
|
|
arg5);
|
|
|
|
case KEYCTL_NEGATE:
|
|
return keyctl_negate_key(arg2, arg3, arg4);
|
|
|
|
case KEYCTL_SET_REQKEY_KEYRING:
|
|
return keyctl_set_reqkey_keyring(arg2);
|
|
|
|
case KEYCTL_SET_TIMEOUT:
|
|
return keyctl_set_timeout(arg2, arg3);
|
|
|
|
case KEYCTL_ASSUME_AUTHORITY:
|
|
return keyctl_assume_authority(arg2);
|
|
|
|
case KEYCTL_GET_SECURITY:
|
|
return keyctl_get_security(arg2, compat_ptr(arg3), arg4);
|
|
|
|
case KEYCTL_SESSION_TO_PARENT:
|
|
return keyctl_session_to_parent();
|
|
|
|
case KEYCTL_REJECT:
|
|
return keyctl_reject_key(arg2, arg3, arg4, arg5);
|
|
|
|
case KEYCTL_INSTANTIATE_IOV:
|
|
return compat_keyctl_instantiate_key_iov(
|
|
arg2, compat_ptr(arg3), arg4, arg5);
|
|
|
|
default:
|
|
return -EOPNOTSUPP;
|
|
}
|
|
}
|