]> Pileus Git - ~andy/linux/blobdiff - net/socket.c
net: sctp: confirm route during forward progress
[~andy/linux] / net / socket.c
index 9ff6366fee13d1bb2e889fcf5726b39299feaf8a..45afa648364a1c79a7f90209e6d376fa16a3492a 100644 (file)
 #include <linux/route.h>
 #include <linux/sockios.h>
 #include <linux/atalk.h>
+#include <net/ll_poll.h>
+
+#ifdef CONFIG_NET_LL_RX_POLL
+unsigned int sysctl_net_ll_read __read_mostly;
+unsigned int sysctl_net_ll_poll __read_mostly;
+#endif
 
 static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
 static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
@@ -1142,13 +1148,24 @@ EXPORT_SYMBOL(sock_create_lite);
 /* No kernel lock held - perfect */
 static unsigned int sock_poll(struct file *file, poll_table *wait)
 {
+       unsigned int busy_flag = 0;
        struct socket *sock;
 
        /*
         *      We can't return errors to poll, so it's either yes or no.
         */
        sock = file->private_data;
-       return sock->ops->poll(file, sock, wait);
+
+       if (sk_can_busy_loop(sock->sk)) {
+               /* this socket can poll_ll so tell the system call */
+               busy_flag = POLL_BUSY_LOOP;
+
+               /* once, only if requested by syscall */
+               if (wait && (wait->_key & POLL_BUSY_LOOP))
+                       sk_busy_loop(sock->sk, 1);
+       }
+
+       return busy_flag | sock->ops->poll(file, sock, wait);
 }
 
 static int sock_mmap(struct file *file, struct vm_area_struct *vma)
@@ -1956,7 +1973,7 @@ struct used_address {
        unsigned int name_len;
 };
 
-static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
+static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
                         struct msghdr *msg_sys, unsigned int flags,
                         struct used_address *used_address)
 {
@@ -2071,26 +2088,30 @@ out:
  *     BSD sendmsg interface
  */
 
-SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
+long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
 {
        int fput_needed, err;
        struct msghdr msg_sys;
        struct socket *sock;
 
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
-
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
 
-       err = __sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
+       err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
 
        fput_light(sock->file, fput_needed);
 out:
        return err;
 }
 
+SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
+{
+       if (flags & MSG_CMSG_COMPAT)
+               return -EINVAL;
+       return __sys_sendmsg(fd, msg, flags);
+}
+
 /*
  *     Linux sendmmsg interface
  */
@@ -2121,15 +2142,16 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
 
        while (datagrams < vlen) {
                if (MSG_CMSG_COMPAT & flags) {
-                       err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
-                                           &msg_sys, flags, &used_address);
+                       err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
+                                            &msg_sys, flags, &used_address);
                        if (err < 0)
                                break;
                        err = __put_user(err, &compat_entry->msg_len);
                        ++compat_entry;
                } else {
-                       err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
-                                           &msg_sys, flags, &used_address);
+                       err = ___sys_sendmsg(sock,
+                                            (struct msghdr __user *)entry,
+                                            &msg_sys, flags, &used_address);
                        if (err < 0)
                                break;
                        err = put_user(err, &entry->msg_len);
@@ -2158,7 +2180,7 @@ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
        return __sys_sendmmsg(fd, mmsg, vlen, flags);
 }
 
-static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
+static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
                         struct msghdr *msg_sys, unsigned int flags, int nosec)
 {
        struct compat_msghdr __user *msg_compat =
@@ -2250,27 +2272,31 @@ out:
  *     BSD recvmsg interface
  */
 
-SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
-               unsigned int, flags)
+long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags)
 {
        int fput_needed, err;
        struct msghdr msg_sys;
        struct socket *sock;
 
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
-
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
 
-       err = __sys_recvmsg(sock, msg, &msg_sys, flags, 0);
+       err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0);
 
        fput_light(sock->file, fput_needed);
 out:
        return err;
 }
 
+SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
+               unsigned int, flags)
+{
+       if (flags & MSG_CMSG_COMPAT)
+               return -EINVAL;
+       return __sys_recvmsg(fd, msg, flags);
+}
+
 /*
  *     Linux recvmmsg interface
  */
@@ -2308,17 +2334,18 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
                 * No need to ask LSM for more than the first datagram.
                 */
                if (MSG_CMSG_COMPAT & flags) {
-                       err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
-                                           &msg_sys, flags & ~MSG_WAITFORONE,
-                                           datagrams);
+                       err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
+                                            &msg_sys, flags & ~MSG_WAITFORONE,
+                                            datagrams);
                        if (err < 0)
                                break;
                        err = __put_user(err, &compat_entry->msg_len);
                        ++compat_entry;
                } else {
-                       err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
-                                           &msg_sys, flags & ~MSG_WAITFORONE,
-                                           datagrams);
+                       err = ___sys_recvmsg(sock,
+                                            (struct msghdr __user *)entry,
+                                            &msg_sys, flags & ~MSG_WAITFORONE,
+                                            datagrams);
                        if (err < 0)
                                break;
                        err = put_user(err, &entry->msg_len);
@@ -2505,31 +2532,15 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
                                   (int __user *)a[4]);
                break;
        case SYS_SENDMSG:
-               if (a[2] & MSG_CMSG_COMPAT) {
-                       err = -EINVAL;
-                       break;
-               }
                err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
                break;
        case SYS_SENDMMSG:
-               if (a[3] & MSG_CMSG_COMPAT) {
-                       err = -EINVAL;
-                       break;
-               }
                err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
                break;
        case SYS_RECVMSG:
-               if (a[2] & MSG_CMSG_COMPAT) {
-                       err = -EINVAL;
-                       break;
-               }
                err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
                break;
        case SYS_RECVMMSG:
-               if (a[3] & MSG_CMSG_COMPAT) {
-                       err = -EINVAL;
-                       break;
-               }
                err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
                                   (struct timespec __user *)a[4]);
                break;
@@ -2641,7 +2652,9 @@ static int __init sock_init(void)
         */
 
 #ifdef CONFIG_NETFILTER
-       netfilter_init();
+       err = netfilter_init();
+       if (err)
+               goto out;
 #endif
 
 #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING