aboutsummaryrefslogtreecommitdiffstats
path: root/fs/read_write.c
diff options
context:
space:
mode:
authorChristopher Yeoh <cyeoh@au1.ibm.com>2011-10-31 20:06:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-10-31 20:30:44 -0400
commitfcf634098c00dd9cd247447368495f0b79be12d1 (patch)
tree77fc98cd461bd52ba3b14e833d54a115ffbbd7bc /fs/read_write.c
parent32ea845d5bafc37b7406bea1aee3005407cb0900 (diff)
Cross Memory Attach
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>
Diffstat (limited to 'fs/read_write.c')
-rw-r--r--fs/read_write.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/fs/read_write.c b/fs/read_write.c
index dfd125798791..5ad4248b0cd8 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -633,7 +633,8 @@ ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
633ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, 633ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
634 unsigned long nr_segs, unsigned long fast_segs, 634 unsigned long nr_segs, unsigned long fast_segs,
635 struct iovec *fast_pointer, 635 struct iovec *fast_pointer,
636 struct iovec **ret_pointer) 636 struct iovec **ret_pointer,
637 int check_access)
637{ 638{
638 unsigned long seg; 639 unsigned long seg;
639 ssize_t ret; 640 ssize_t ret;
@@ -689,7 +690,8 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
689 ret = -EINVAL; 690 ret = -EINVAL;
690 goto out; 691 goto out;
691 } 692 }
692 if (unlikely(!access_ok(vrfy_dir(type), buf, len))) { 693 if (check_access
694 && unlikely(!access_ok(vrfy_dir(type), buf, len))) {
693 ret = -EFAULT; 695 ret = -EFAULT;
694 goto out; 696 goto out;
695 } 697 }
@@ -721,7 +723,7 @@ static ssize_t do_readv_writev(int type, struct file *file,
721 } 723 }
722 724
723 ret = rw_copy_check_uvector(type, uvector, nr_segs, 725 ret = rw_copy_check_uvector(type, uvector, nr_segs,
724 ARRAY_SIZE(iovstack), iovstack, &iov); 726 ARRAY_SIZE(iovstack), iovstack, &iov, 1);
725 if (ret <= 0) 727 if (ret <= 0)
726 goto out; 728 goto out;
727 729