net/mlx4_en: Fix mixed PFC and Global pause user control requests
[pandora-kernel.git] / net / socket.c
index 116cf9d..f948397 100644 (file)
@@ -1898,7 +1898,7 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
 
 static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
                          struct msghdr *msg_sys, unsigned flags,
-                         struct used_address *used_address)
+                         struct used_address *used_address, int *residue)
 {
        struct compat_msghdr __user *msg_compat =
            (struct compat_msghdr __user *)msg;
@@ -1911,14 +1911,12 @@ static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
        int err, ctl_len, iov_size, total_len;
 
        err = -EFAULT;
-       if (MSG_CMSG_COMPAT & flags) {
-               if (get_compat_msghdr(msg_sys, msg_compat))
-                       return -EFAULT;
-       } else {
+       if (MSG_CMSG_COMPAT & flags)
+               err = get_compat_msghdr(msg_sys, msg_compat);
+       else
                err = copy_msghdr_from_user(msg_sys, msg);
-               if (err)
-                       return err;
-       }
+       if (err)
+               return err;
 
        /* do not move before msg_sys is valid */
        err = -EMSGSIZE;
@@ -2006,6 +2004,8 @@ static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
                        memcpy(&used_address->name, msg_sys->msg_name,
                               used_address->name_len);
        }
+       if (residue && err >= 0)
+               *residue = total_len - err;
 
 out_freectl:
        if (ctl_buf != ctl)
@@ -2031,7 +2031,7 @@ long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
        if (!sock)
                goto out;
 
-       err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
+       err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL, NULL);
 
        fput_light(sock->file, fput_needed);
 out:
@@ -2058,6 +2058,7 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
        struct compat_mmsghdr __user *compat_entry;
        struct msghdr msg_sys;
        struct used_address used_address;
+       int residue;
 
        if (vlen > UIO_MAXIOV)
                vlen = UIO_MAXIOV;
@@ -2076,7 +2077,8 @@ 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);
+                                            &msg_sys, flags, &used_address,
+                                            &residue);
                        if (err < 0)
                                break;
                        err = __put_user(err, &compat_entry->msg_len);
@@ -2084,7 +2086,8 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
                } else {
                        err = ___sys_sendmsg(sock,
                                             (struct msghdr __user *)entry,
-                                            &msg_sys, flags, &used_address);
+                                            &msg_sys, flags, &used_address,
+                                            &residue);
                        if (err < 0)
                                break;
                        err = put_user(err, &entry->msg_len);
@@ -2094,6 +2097,8 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
                if (err)
                        break;
                ++datagrams;
+               if (residue)
+                       break;
        }
 
        fput_light(sock->file, fput_needed);
@@ -2130,14 +2135,12 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
        struct sockaddr __user *uaddr;
        int __user *uaddr_len;
 
-       if (MSG_CMSG_COMPAT & flags) {
-               if (get_compat_msghdr(msg_sys, msg_compat))
-                       return -EFAULT;
-       } else {
+       if (MSG_CMSG_COMPAT & flags)
+               err = get_compat_msghdr(msg_sys, msg_compat);
+       else
                err = copy_msghdr_from_user(msg_sys, msg);
-               if (err)
-                       return err;
-       }
+       if (err)
+               return err;
 
        err = -EMSGSIZE;
        if (msg_sys->msg_iovlen > UIO_MAXIOV)
@@ -2266,8 +2269,10 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
                return err;
 
        err = sock_error(sock->sk);
-       if (err)
+       if (err) {
+               datagrams = err;
                goto out_put;
+       }
 
        entry = mmsg;
        compat_entry = (struct compat_mmsghdr __user *)mmsg;
@@ -2321,31 +2326,31 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
                        break;
        }
 
-out_put:
-       fput_light(sock->file, fput_needed);
-
        if (err == 0)
-               return datagrams;
+               goto out_put;
+
+       if (datagrams == 0) {
+               datagrams = err;
+               goto out_put;
+       }
 
-       if (datagrams != 0) {
+       /*
+        * We may return less entries than requested (vlen) if the
+        * sock is non block and there aren't enough datagrams...
+        */
+       if (err != -EAGAIN) {
                /*
-                * We may return less entries than requested (vlen) if the
-                * sock is non block and there aren't enough datagrams...
+                * ... or  if recvmsg returns an error after we
+                * received some datagrams, where we record the
+                * error to return on the next call or if the
+                * app asks about it using getsockopt(SO_ERROR).
                 */
-               if (err != -EAGAIN) {
-                       /*
-                        * ... or  if recvmsg returns an error after we
-                        * received some datagrams, where we record the
-                        * error to return on the next call or if the
-                        * app asks about it using getsockopt(SO_ERROR).
-                        */
-                       sock->sk->sk_err = -err;
-               }
-
-               return datagrams;
+               sock->sk->sk_err = -err;
        }
+out_put:
+       fput_light(sock->file, fput_needed);
 
-       return err;
+       return datagrams;
 }
 
 SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,