diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-10-13 02:40:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-10-13 02:40:10 -0400 |
commit | a2e2725541fad72416326798c2d7fa4dafb7d337 (patch) | |
tree | 6174be11da607e83eb8efb3775114ad4d6e0ca3a /net/compat.c | |
parent | c05e85a06e376f6b6d59e71e5333d707e956d78b (diff) |
net: Introduce recvmmsg socket syscall
Meaning receive multiple messages, reducing the number of syscalls and
net stack entry/exit operations.
Next patches will introduce mechanisms where protocols that want to
optimize this operation will provide an unlocked_recvmsg operation.
This takes into account comments made by:
. Paul Moore: sock_recvmsg is called only for the first datagram,
sock_recvmsg_nosec is used for the rest.
. Caitlin Bestler: recvmmsg now has a struct timespec timeout, that
works in the same fashion as the ppoll one.
If the underlying protocol returns a datagram with MSG_OOB set, this
will make recvmmsg return right away with as many datagrams (+ the OOB
one) it has received so far.
. RĂ©mi Denis-Courmont & Steven Whitehouse: If we receive N < vlen
datagrams and then recvmsg returns an error, recvmmsg will return
the successfully received datagrams, store the error and return it
in the next call.
This paves the way for a subsequent optimization, sk_prot->unlocked_recvmsg,
where we will be able to acquire the lock only at batch start and end, not at
every underlying recvmsg call.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/compat.c')
-rw-r--r-- | net/compat.c | 33 |
1 files changed, 30 insertions, 3 deletions
diff --git a/net/compat.c b/net/compat.c index a407c3addbae..e13f5256fd20 100644 --- a/net/compat.c +++ b/net/compat.c | |||
@@ -727,10 +727,10 @@ EXPORT_SYMBOL(compat_mc_getsockopt); | |||
727 | 727 | ||
728 | /* Argument list sizes for compat_sys_socketcall */ | 728 | /* Argument list sizes for compat_sys_socketcall */ |
729 | #define AL(x) ((x) * sizeof(u32)) | 729 | #define AL(x) ((x) * sizeof(u32)) |
730 | static unsigned char nas[19]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), | 730 | static unsigned char nas[20]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), |
731 | AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), | 731 | AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), |
732 | AL(6),AL(2),AL(5),AL(5),AL(3),AL(3), | 732 | AL(6),AL(2),AL(5),AL(5),AL(3),AL(3), |
733 | AL(4)}; | 733 | AL(4),AL(5)}; |
734 | #undef AL | 734 | #undef AL |
735 | 735 | ||
736 | asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags) | 736 | asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags) |
@@ -755,13 +755,36 @@ asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len, | |||
755 | return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen); | 755 | return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen); |
756 | } | 756 | } |
757 | 757 | ||
758 | asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, | ||
759 | unsigned vlen, unsigned int flags, | ||
760 | struct timespec __user *timeout) | ||
761 | { | ||
762 | int datagrams; | ||
763 | struct timespec ktspec; | ||
764 | struct compat_timespec __user *utspec = | ||
765 | (struct compat_timespec __user *)timeout; | ||
766 | |||
767 | if (get_user(ktspec.tv_sec, &utspec->tv_sec) || | ||
768 | get_user(ktspec.tv_nsec, &utspec->tv_nsec)) | ||
769 | return -EFAULT; | ||
770 | |||
771 | datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, | ||
772 | flags | MSG_CMSG_COMPAT, &ktspec); | ||
773 | if (datagrams > 0 && | ||
774 | (put_user(ktspec.tv_sec, &utspec->tv_sec) || | ||
775 | put_user(ktspec.tv_nsec, &utspec->tv_nsec))) | ||
776 | datagrams = -EFAULT; | ||
777 | |||
778 | return datagrams; | ||
779 | } | ||
780 | |||
758 | asmlinkage long compat_sys_socketcall(int call, u32 __user *args) | 781 | asmlinkage long compat_sys_socketcall(int call, u32 __user *args) |
759 | { | 782 | { |
760 | int ret; | 783 | int ret; |
761 | u32 a[6]; | 784 | u32 a[6]; |
762 | u32 a0, a1; | 785 | u32 a0, a1; |
763 | 786 | ||
764 | if (call < SYS_SOCKET || call > SYS_ACCEPT4) | 787 | if (call < SYS_SOCKET || call > SYS_RECVMMSG) |
765 | return -EINVAL; | 788 | return -EINVAL; |
766 | if (copy_from_user(a, args, nas[call])) | 789 | if (copy_from_user(a, args, nas[call])) |
767 | return -EFAULT; | 790 | return -EFAULT; |
@@ -823,6 +846,10 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args) | |||
823 | case SYS_RECVMSG: | 846 | case SYS_RECVMSG: |
824 | ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]); | 847 | ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]); |
825 | break; | 848 | break; |
849 | case SYS_RECVMMSG: | ||
850 | ret = compat_sys_recvmmsg(a0, compat_ptr(a1), a[2], a[3], | ||
851 | compat_ptr(a[4])); | ||
852 | break; | ||
826 | case SYS_ACCEPT4: | 853 | case SYS_ACCEPT4: |
827 | ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]); | 854 | ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]); |
828 | break; | 855 | break; |