lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:	Fri, 15 Aug 2014 21:23:27 +0200
From:	"Michael Kerrisk (man-pages)" <mtk.manpages@...il.com>
To:	Arnaldo Carvalho de Melo <acme@...stprotocols.net>,
	David Miller <davem@...emloft.net>
CC:	mtk.manpages@...il.com, caitlin.bestler@...il.com,
	chris.friesen@...driver.com, David.Laight@...LAB.COM,
	eliedebrauwer@...il.com, nhorman@...driver.com, neleai@...nam.cz,
	paul@...l-moore.com, remi@...lab.net, steve@...gwyn.com,
	netdev@...r.kernel.org
Subject: Re: [PATCH net.git] net: Fix recvmmsg timeout handling

Ping, Arnaldo!

On 07/30/2014 11:47 AM, Michael Kerrisk (man-pages) wrote:
> Hello Arnaldo,
> 
> On 07/22/2014 09:48 PM, Arnaldo Carvalho de Melo wrote:
>> Em Mon, Jul 21, 2014 at 08:45:38PM -0700, David Miller escreveu:
>>> From: Arnaldo Carvalho de Melo <acme@...nel.org>
>>> Date: Mon, 21 Jul 2014 16:21:31 -0300
>>>
>>>> 	Trying to get this merged, finally. I has whas has been
>>>> discussed so far and agreed wrt the timeout handling.
>>>
>>> This gets lots of rejects against the current 'net' tree.
>>>
>>> Please respin and integrate Remi's Acked-by, thanks.
>>
>> Here it is, I think we should wait a bit till Michael (and whoever else
>> is up to test this today) can test it, Michael?
>>
>> It was done on top of:
>>
>>   git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
>>
>> from early today.
> 
> Okay, this applied cleanly against a recent pull of the 'net' tree.
> 
> However, the failure case that I pointed out (for the second time already)
> in http://thread.gmane.org/gmane.linux.kernel/1711197/focus=6435
> is *still* failing. (Are you actually testing this case for your patches?
> It appears not.) However, this time the failure mode is slightly
> different:
> 
>     Suppose the following scenario:
> 
>     1. We do a recvmmsg() with 10 second timeout, asking for 5 
>        messages.
>     2. 3 messages arrive
>     3. 6 seconds after the call, a signal handler interrupts
>        the call.
>     4. recvmmsg() returns success, telling us it got 3 messages.
> 
>     So far, so good. But
> 
>     5. We make a further recvmmsg() call.
>     6. That call returns immediately, with the (unknown error) 
>        value 512 in errno. (In the previous patch version, we
>       (wrongly) got EINTR at this point.)
> 
> I also see now a second failure mode in this patch set (I'm not
> sure if it was present in your earlier patch sets). If the
> timespec structure pointed to by 'timeout' contains {0, 0} then
> the call blocks indefinitely, whereas it should return 
> immediately (with, I think, an EAGAIN error) if there are no
> messages.
> 
> My test program (a modified version of the test program I 
> posted earlier) is below. I've also added a test program that
> sends datagrams. To save some time, on the next iteration
> of your patch, could you please note which of the above
> failure modes you have tested for. Also, I think it would
> be good to include a detailed description of the expected
> semantics of the 'timeout' argument as part of the
> commit message. Then we all understand what the intended
> semantics are, and what needs to be tested. Something like 
> this (may need fixing, if you think it is different):
> 
> [[
> The 'timeout' argument implements three cases:
> 
> 1) 'timeout' is NULL: the call blocks until 'vlen' datagrams
>    are received.
> 2) 'timeout' points to {0, 0}: the call (immediately) returns up to 
>    'vlen' datagrams if they are available. If no datagrams are 
>    available, the call returns immediately, with the error EAGAIN.
> 3) 'timeout'points to a structure in which at least one of the
>    fields is nonzero. The call blocks until either:
>   
>       a) the specified timeout expires
>       b) 'vlen' messages are received
> 
>   In case (a), if one or more messages has been received,
>   the call returns the number of messages received; otherwise,
>   if no messages were received, the call fails with the error
>   EAGAIN.
> 
> If, while blocking, the call is interrupted by a signal handler,
> then:
> 
> * if 1 or more datagrams have been received, then those datagrams
>   are returned (and interruption by a signal handler is not
>   (directly) reported by this or any subsequent call to recvmmsg()).
> * if no datagrams have so far been received, then the call fails
>   with the error EINTR.
> ]]
> 
> (In the cases where I mention EAGAIN above, the call could instead
> return 0, but EAGAIN seems more consistent with other APIs.)
> 
> Of course, if we'd had such a spec to begin with, then probably
> the problems with the 'timeout' argument would have been detected
> much sooner. (But, recvmmsg() is hardly the first, nor the last,
> of many, many  examples of Linux API problems that occurred because 
> of that omission.)
> 
> Thanks,
> 
> Michael
> 
> 
> /* t_recvmmsg.c 
> 
>    (C) 2014, Michael Kerrisk, Licensed under the GNU General Public License,
>    version 2 or later.
> */
> #define _GNU_SOURCE
> #include <sys/time.h>
> #include <signal.h>
> #include <sys/socket.h>
> #include <netdb.h>
> #include <sys/types.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> #include <string.h>
> #include <errno.h>
> 
> #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
>                         } while (0)
> 
> static int              /* Public interfaces: inetBind() and inetListen() */
> createBoundSocket(const char *service, int type, socklen_t *addrlen)
> {
>     struct addrinfo hints;
>     struct addrinfo *result, *rp;
>     int sfd, s;
> 
>     memset(&hints, 0, sizeof(struct addrinfo));
>     hints.ai_canonname = NULL;
>     hints.ai_addr = NULL;
>     hints.ai_next = NULL;
>     hints.ai_socktype = type;
>     hints.ai_family = AF_UNSPEC;        /* Allows IPv4 or IPv6 */
>     hints.ai_flags = AI_PASSIVE;        /* Use wildcard IP address */
> 
>     s = getaddrinfo(NULL, service, &hints, &result);
>     if (s != 0)
>         return -1;
> 
>     /* Walk through returned list until we find an address structure
>        that can be used to successfully create and bind a socket */
> 
>     for (rp = result; rp != NULL; rp = rp->ai_next) {
>         sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
>         if (sfd == -1)
>             continue;                   /* On error, try next address */
> 
>         if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
>             break;                      /* Success */
> 
>         /* bind() failed: close this socket and try next address */
> 
>         close(sfd);
>     }
> 
>     if (rp != NULL && addrlen != NULL)
>         *addrlen = rp->ai_addrlen;      /* Return address structure size */
> 
>     freeaddrinfo(result);
> 
>     return (rp == NULL) ? -1 : sfd;
> }
> 
> static void
> handler()
> {
>     /* Just interrupt a syscall */
> }
> 
> int
> main(int argc, char *argv[])
> {
>     int sfd, vlen, j, s;
>     struct mmsghdr *msgvecp;
>     struct timespec ts, ts_saved;
>     struct timespec *tsp;
>     struct sigaction sa;
> 
>     if (argc < 4) {
>         fprintf(stderr, "Usage: %s port tmo-secs buf-len...\n", argv[0]);
>         exit(EXIT_FAILURE);
>     }
> 
>     sfd = createBoundSocket(argv[1], SOCK_DGRAM, NULL);
>     if (sfd == -1) {
>         fprintf(stderr, "Could not create server socket (%s)",
>                 strerror(errno));
>         exit(EXIT_FAILURE);
>     }
> 
>     /* Handle a signal, so we can test behaviour when recvmmsg()
>        is interrupted by a signal */
> 
>     sa.sa_handler = handler;
>     sa.sa_flags = 0;
>     sigemptyset(&sa.sa_mask);
>     if (sigaction (SIGQUIT, &sa, NULL) == -1)
>         errExit("sigaction");
> 
>     /* argv[2] specifies recvmmsg() timeout in seconds, or is '-', meaning
>        using NULL argument to get infinite timeout */
> 
>     if (argv[2][0] == '-') {
>         tsp = NULL;
> 
>     } else {
>         ts.tv_sec = atoi(argv[2]);
>         ts.tv_nsec = 0;
>         ts_saved = ts;
>         tsp = &ts;
>     }
> 
>     /* Remaining command-line arguments specify the size of recvmmsg()
>        buffers */
> 
>     /* The second argument to recvmmsg() is a pointer to an array of
>        mmsghdr structures. Each element of that array has a field,
>        'struct msghdr msg_hdr', that is used to store information from a
>        single received datagram. Among the fields in the msghdr structure
>        is a 'struct iovec *msg_iov'--that is, a pointer to a scatter/gather
>        I/O vector. To keep things simple for this example, our scatter/gather
>        vectors always consists of a single element.
>     */
> 
>     /* Allocate the mmssghdr vector, whose size corresponds to the
>        number of remaining command-line arguments */
> 
>     vlen = argc - 3;
> 
>     msgvecp = calloc(vlen, sizeof(struct mmsghdr));
>     if (msgvecp == NULL)
>         errExit("calloc");
> 
>     for (j = 0; j < vlen; j++) {
>         msgvecp[j].msg_hdr.msg_name = NULL;
>         msgvecp[j].msg_hdr.msg_namelen = 0;
>         msgvecp[j].msg_hdr.msg_control = NULL;
>         msgvecp[j].msg_hdr.msg_controllen = 0;
> 
>         /* Allocate an iovec for this mmsghdr element. The vector
>            contains just a single item. */
> 
>         msgvecp[j].msg_hdr.msg_iovlen = 1;
> 
>         msgvecp[j].msg_hdr.msg_iov = malloc(sizeof(struct iovec));
>         if (msgvecp[j].msg_hdr.msg_iov == NULL)
>             errExit("malloc");
> 
>         /* The single iovec element contains a pointer to a buffer
>            that is sized according to the number given in the
>            corresponding command-line argument */
> 
>         s = atoi(argv[j + 3]);
>         msgvecp[j].msg_hdr.msg_iov[0].iov_len = s;
>         msgvecp[j].msg_hdr.msg_iov[0].iov_base = malloc(s);
>     }
> 
>     if (tsp != NULL)
>         printf("Timespec before call = %ld.%09ld\n",
>                 (long) tsp->tv_sec, (long) tsp->tv_nsec);
> 
>     /* Now we're ready to make the recvmmsg() call */
> 
>     s = recvmmsg(sfd, msgvecp, vlen, 0, tsp);
>     if (s == -1) {
>         if (errno == EINTR)
>             printf("EINTR! (interrupted system call)\n");
>         else
>             errExit("recvmmsg");
>     }
> 
>     printf("recvmmsg() returned %d\n", s);
> 
>     if (tsp != NULL)
>         printf("Timespec after call = %ld.%09ld\n",
>                 (long) tsp->tv_sec, (long) tsp->tv_nsec);
> 
>     /* Display datagrams retrieved by recvmmsg() */
> 
>     for (j = 0; j < s; j++) {
>         printf("%d: %u - %.*s\n", j,
>                 msgvecp[j].msg_len, msgvecp[j].msg_len,
>                 (char *) msgvecp[j].msg_hdr.msg_iov[0].iov_base);
>     }
> 
> #ifdef SECOND_CALL
>     ts = ts_saved;
>     printf("About to make second recvmmsg() call\n");
>     if (tsp != NULL)
>         printf("Timespec before call = %ld.%09ld\n",
>                 (long) tsp->tv_sec, (long) tsp->tv_nsec);
> 
>     s = recvmmsg(sfd, msgvecp, vlen, 0, tsp);
>     if (s == -1) {
>         if (errno == EINTR)
>             printf("Second recvmmsg(): EINTR! (interrupted system call)\n");
>         else
>             errExit("recvmmsg");
>     }
>     printf("Second recvmmsg(): returned %d\n", s);
> #endif
> 
>     exit(EXIT_SUCCESS);
> }
> 
> 
> And this test program can be used to send datagrams:
> 
> /* id_sendto.c
> 
>    (C) 2014, Michael Kerrisk, Licensed under the GNU General Public License,
>    version 2 or later.
> */
> 
> #include <sys/socket.h>
> #include <netinet/in.h>
> #include <arpa/inet.h>
> #include <netdb.h>
> #include <sys/types.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> #include <string.h>
> #include <errno.h>
> 
> /* Create socket and connect it to the address specified by
>   'host' + 'service'/'type'. Return socket descriptor on success,
>   or -1 on error */
> 
> static int
> inetConnect(const char *host, const char *service, int type)
> {
>     struct addrinfo hints;
>     struct addrinfo *result, *rp;
>     int sfd, s;
> 
>     memset(&hints, 0, sizeof(struct addrinfo));
>     hints.ai_canonname = NULL;
>     hints.ai_addr = NULL;
>     hints.ai_next = NULL;
>     hints.ai_family = AF_UNSPEC;        /* Allows IPv4 or IPv6 */
>     hints.ai_socktype = type;
> 
>     s = getaddrinfo(host, service, &hints, &result);
>     if (s != 0) {
>         errno = ENOSYS;
>         return -1;
>     }
> 
>     /* Walk through returned list until we find an address structure
>        that can be used to successfully connect a socket */
> 
>     for (rp = result; rp != NULL; rp = rp->ai_next) {
>         sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
>         if (sfd == -1)
>             continue;                   /* On error, try next address */
> 
>         if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
>             break;                      /* Success */
> 
>         /* Connect failed: close this socket and try next address */
> 
>         close(sfd);
>     }
> 
>     freeaddrinfo(result);
> 
>     return (rp == NULL) ? -1 : sfd;
> }
> 
> int
> main(int argc, char *argv[])
> {
>     int sfd, j;
> 
>     if (argc < 3 || strcmp(argv[1], "--help") == 0) {
>         fprintf(stderr, "Usage: %s host port msg...\n", argv[0]);
>         exit(EXIT_FAILURE);
>     }
> 
>     sfd = inetConnect(argv[1], argv[2], SOCK_DGRAM);
> 
>     for (j = 3; j < argc; j++) {
>         if (send(sfd, argv[j], strlen(argv[j]), 0)
>                         != strlen(argv[j]))
>             perror("sendto");
>     }
> 
>     exit(EXIT_SUCCESS);
> }
> 
> 
>> - Arnaldo
>>
>> commit 93d40dc3a3266d6d4ed905b9333b6809b5fe24fc
>> Author: Arnaldo Carvalho de Melo <acme@...hat.com>
>> Date:   Fri Jul 18 15:23:44 2014 -0300
>>
>>     net: Fix recvmmsg timeout handling
>>     
>>     As reported by Elie de Brauwer the timeout handling in the recvmmsg
>>     syscall had issues that boil down to it not properly passing the
>>     remaining time to each underlying recvmsg() call.
>>     
>>     Fix it by adding a timeout pointer to the recvmsg implementations, so
>>     that it can use that using a variation of sock_rcvtimeo, that overrides
>>     the value in SO_RCVTIMEO with the timeout passed, and returns the
>>     remaining time in that pointer, this way each underlying recvmsg call
>>     receives the remaining time.
>>     
>>     It ends up in most cases being just a forward of this pointer from
>>     recvmmsg to skb_recv_datagram().
>>     
>>     Reported-by: Elie De Brauwer <eliedebrauwer@...il.com>
>>     Acked-by: Rémi Denis-Courmont <remi@...lab.net>
>>     Cc: Caitlin Bestler <caitlin.bestler@...il.com>
>>     Cc: Chris Friesen <chris.friesen@...driver.com>
>>     Cc: David Laight <David.Laight@...LAB.COM>
>>     Cc: Elie De Brauwer <eliedebrauwer@...il.com>
>>     Cc: Michael Kerrisk <mtk.manpages@...il.com>
>>     Cc: Neil Horman <nhorman@...driver.com>
>>     Cc: Ondřej Bílka <neleai@...nam.cz>
>>     Cc: Paul Moore <paul@...l-moore.com>
>>     Cc: Rémi Denis-Courmont <remi@...lab.net>
>>     Cc: Steven Whitehouse <steve@...gwyn.com>
>>     Link: http://lkml.kernel.org/n/tip-5tupdoo5hdfci7diirv0ugli@git.kernel.org
>>     Signed-off-by: Arnaldo Carvalho de Melo <acme@...hat.com>
>>
>> diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
>> index 850246206b12..e5d36f815083 100644
>> --- a/crypto/algif_hash.c
>> +++ b/crypto/algif_hash.c
>> @@ -151,7 +151,7 @@ unlock:
>>  }
>>  
>>  static int hash_recvmsg(struct kiocb *unused, struct socket *sock,
>> -			struct msghdr *msg, size_t len, int flags)
>> +			struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct alg_sock *ask = alg_sk(sk);
>> diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
>> index a19c027b29bd..4bde01591174 100644
>> --- a/crypto/algif_skcipher.c
>> +++ b/crypto/algif_skcipher.c
>> @@ -419,7 +419,7 @@ unlock:
>>  }
>>  
>>  static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock,
>> -			    struct msghdr *msg, size_t ignored, int flags)
>> +			    struct msghdr *msg, size_t ignored, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct alg_sock *ask = alg_sk(sk);
>> diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
>> index 1be82284cf9d..254515f71793 100644
>> --- a/drivers/isdn/mISDN/socket.c
>> +++ b/drivers/isdn/mISDN/socket.c
>> @@ -113,7 +113,7 @@ mISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
>>  
>>  static int
>>  mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -		   struct msghdr *msg, size_t len, int flags)
>> +		   struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	struct sk_buff		*skb;
>>  	struct sock		*sk = sock->sk;
>> @@ -130,7 +130,7 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	if (sk->sk_state == MISDN_CLOSED)
>>  		return 0;
>>  
>> -	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
>> +	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err, timeop);
>>  	if (!skb)
>>  		return err;
>>  
>> diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
>> index 3381c4f91a8c..13d12ef322f2 100644
>> --- a/drivers/net/macvtap.c
>> +++ b/drivers/net/macvtap.c
>> @@ -1111,7 +1111,7 @@ static int macvtap_sendmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  static int macvtap_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  			   struct msghdr *m, size_t total_len,
>> -			   int flags)
>> +			   int flags, long *timeop)
>>  {
>>  	struct macvtap_queue *q = container_of(sock, struct macvtap_queue, sock);
>>  	int ret;
>> diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
>> index 6c9c16d76935..dc82dee82548 100644
>> --- a/drivers/net/ppp/pppoe.c
>> +++ b/drivers/net/ppp/pppoe.c
>> @@ -963,7 +963,7 @@ static const struct ppp_channel_ops pppoe_chan_ops = {
>>  };
>>  
>>  static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -		  struct msghdr *m, size_t total_len, int flags)
>> +		  struct msghdr *m, size_t total_len, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct sk_buff *skb;
>> @@ -975,7 +975,7 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	}
>>  
>>  	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
>> -				flags & MSG_DONTWAIT, &error);
>> +				flags & MSG_DONTWAIT, &error, timeop);
>>  	if (error < 0)
>>  		goto end;
>>  
>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
>> index 98bad1fb1bfb..f21df9360492 100644
>> --- a/drivers/net/tun.c
>> +++ b/drivers/net/tun.c
>> @@ -1343,7 +1343,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
>>  
>>  	/* Read frames from queue */
>>  	skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0,
>> -				  &peeked, &off, &err);
>> +				  &peeked, &off, &err, NULL);
>>  	if (skb) {
>>  		ret = tun_put_user(tun, tfile, skb, iv, len);
>>  		kfree_skb(skb);
>> @@ -1452,7 +1452,7 @@ static int tun_sendmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  		       struct msghdr *m, size_t total_len,
>> -		       int flags)
>> +		       int flags, long *timeop)
>>  {
>>  	struct tun_file *tfile = container_of(sock, struct tun_file, socket);
>>  	struct tun_struct *tun = __tun_get(tfile);
>> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
>> index 8dae2f724a35..6cd829e78ab6 100644
>> --- a/drivers/vhost/net.c
>> +++ b/drivers/vhost/net.c
>> @@ -602,7 +602,7 @@ static void handle_rx(struct vhost_net *net)
>>  		if (unlikely(headcount > UIO_MAXIOV)) {
>>  			msg.msg_iovlen = 1;
>>  			err = sock->ops->recvmsg(NULL, sock, &msg,
>> -						 1, MSG_DONTWAIT | MSG_TRUNC);
>> +						 1, MSG_DONTWAIT | MSG_TRUNC, NULL);
>>  			pr_debug("Discarded rx packet: len %zd\n", sock_len);
>>  			continue;
>>  		}
>> @@ -628,7 +628,7 @@ static void handle_rx(struct vhost_net *net)
>>  			copy_iovec_hdr(vq->iov, nvq->hdr, sock_hlen, in);
>>  		msg.msg_iovlen = in;
>>  		err = sock->ops->recvmsg(NULL, sock, &msg,
>> -					 sock_len, MSG_DONTWAIT | MSG_TRUNC);
>> +					 sock_len, MSG_DONTWAIT | MSG_TRUNC, NULL);
>>  		/* Userspace might have consumed the packet meanwhile:
>>  		 * it's not supposed to do this usually, but might be hard
>>  		 * to prevent. Discard data we got (if any) and keep going. */
>> diff --git a/include/linux/net.h b/include/linux/net.h
>> index 17d83393afcc..fcbbda434ff4 100644
>> --- a/include/linux/net.h
>> +++ b/include/linux/net.h
>> @@ -171,10 +171,13 @@ struct proto_ops {
>>  	 * returning uninitialized memory to user space.  The recvfrom
>>  	 * handlers can assume that msg.msg_name is either NULL or has
>>  	 * a minimum size of sizeof(struct sockaddr_storage).
>> +	 * timeop contains a per call timeout (as opposed as per socket,
>> +	 * used by recvmmsg, set it to NULL to disable it. It should return
>> +	 * the remaining time, if not NULL.
>>  	 */
>>  	int		(*recvmsg)   (struct kiocb *iocb, struct socket *sock,
>>  				      struct msghdr *m, size_t total_len,
>> -				      int flags);
>> +				      int flags, long *timeop);
>>  	int		(*mmap)	     (struct file *file, struct socket *sock,
>>  				      struct vm_area_struct * vma);
>>  	ssize_t		(*sendpage)  (struct socket *sock, struct page *page,
>> @@ -215,7 +218,7 @@ int sock_create_lite(int family, int type, int proto, struct socket **res);
>>  void sock_release(struct socket *sock);
>>  int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len);
>>  int sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
>> -		 int flags);
>> +		 int flags, long *timeop);
>>  struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname);
>>  struct socket *sockfd_lookup(int fd, int *err);
>>  struct socket *sock_from_file(struct file *file, int *err);
>> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
>> index ec89301ada41..37585fd26bd6 100644
>> --- a/include/linux/skbuff.h
>> +++ b/include/linux/skbuff.h
>> @@ -2513,9 +2513,9 @@ static inline void skb_frag_add_head(struct sk_buff *skb, struct sk_buff *frag)
>>  	for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next)
>>  
>>  struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
>> -				    int *peeked, int *off, int *err);
>> +				    int *peeked, int *off, int *err, long *timeop);
>>  struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
>> -				  int *err);
>> +				  int *err, long *timeop);
>>  unsigned int datagram_poll(struct file *file, struct socket *sock,
>>  			   struct poll_table_struct *wait);
>>  int skb_copy_datagram_iovec(const struct sk_buff *from, int offset,
>> diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h
>> index 428277869400..6c007bd57f39 100644
>> --- a/include/net/af_vsock.h
>> +++ b/include/net/af_vsock.h
>> @@ -101,7 +101,7 @@ struct vsock_transport {
>>  	/* DGRAM. */
>>  	int (*dgram_bind)(struct vsock_sock *, struct sockaddr_vm *);
>>  	int (*dgram_dequeue)(struct kiocb *kiocb, struct vsock_sock *vsk,
>> -			     struct msghdr *msg, size_t len, int flags);
>> +			     struct msghdr *msg, size_t len, int flags, long *timeop);
>>  	int (*dgram_enqueue)(struct vsock_sock *, struct sockaddr_vm *,
>>  			     struct iovec *, size_t len);
>>  	bool (*dgram_allow)(u32 cid, u32 port);
>> diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
>> index 904777c1cd24..ee75e6875aab 100644
>> --- a/include/net/bluetooth/bluetooth.h
>> +++ b/include/net/bluetooth/bluetooth.h
>> @@ -246,9 +246,9 @@ void bt_sock_unregister(int proto);
>>  void bt_sock_link(struct bt_sock_list *l, struct sock *s);
>>  void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
>>  int  bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -				struct msghdr *msg, size_t len, int flags);
>> +				struct msghdr *msg, size_t len, int flags, long *timeop);
>>  int  bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			struct msghdr *msg, size_t len, int flags);
>> +			struct msghdr *msg, size_t len, int flags, long *timeop);
>>  uint bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait);
>>  int  bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
>>  int  bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
>> diff --git a/include/net/inet_common.h b/include/net/inet_common.h
>> index fe7994c48b75..f80071949b98 100644
>> --- a/include/net/inet_common.h
>> +++ b/include/net/inet_common.h
>> @@ -26,7 +26,7 @@ int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
>>  ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
>>  		      size_t size, int flags);
>>  int inet_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
>> -		 size_t size, int flags);
>> +		 size_t size, int flags, long *timeop);
>>  int inet_shutdown(struct socket *sock, int how);
>>  int inet_listen(struct socket *sock, int backlog);
>>  void inet_sock_destruct(struct sock *sk);
>> diff --git a/include/net/ping.h b/include/net/ping.h
>> index 026479b61a2d..c259ba72c811 100644
>> --- a/include/net/ping.h
>> +++ b/include/net/ping.h
>> @@ -76,7 +76,7 @@ int  ping_getfrag(void *from, char *to, int offset, int fraglen, int odd,
>>  		  struct sk_buff *);
>>  
>>  int  ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>> -		  size_t len, int noblock, int flags, int *addr_len);
>> +		  size_t len, int noblock, int flags, int *addr_len, long *timeop);
>>  int  ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
>>  			 void *user_icmph, size_t icmph_len);
>>  int  ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>> diff --git a/include/net/sock.h b/include/net/sock.h
>> index 156350745700..d2aad2123f53 100644
>> --- a/include/net/sock.h
>> +++ b/include/net/sock.h
>> @@ -961,7 +961,7 @@ struct proto {
>>  	int			(*recvmsg)(struct kiocb *iocb, struct sock *sk,
>>  					   struct msghdr *msg,
>>  					   size_t len, int noblock, int flags,
>> -					   int *addr_len);
>> +					   int *addr_len, long *timeop);
>>  	int			(*sendpage)(struct sock *sk, struct page *page,
>>  					int offset, size_t size, int flags);
>>  	int			(*bind)(struct sock *sk,
>> @@ -1593,7 +1593,7 @@ int sock_no_getsockopt(struct socket *, int , int, char __user *, int __user *);
>>  int sock_no_setsockopt(struct socket *, int, int, char __user *, unsigned int);
>>  int sock_no_sendmsg(struct kiocb *, struct socket *, struct msghdr *, size_t);
>>  int sock_no_recvmsg(struct kiocb *, struct socket *, struct msghdr *, size_t,
>> -		    int);
>> +		    int, long *);
>>  int sock_no_mmap(struct file *file, struct socket *sock,
>>  		 struct vm_area_struct *vma);
>>  ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset,
>> @@ -1606,7 +1606,7 @@ ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset,
>>  int sock_common_getsockopt(struct socket *sock, int level, int optname,
>>  				  char __user *optval, int __user *optlen);
>>  int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			       struct msghdr *msg, size_t size, int flags);
>> +			       struct msghdr *msg, size_t size, int flags, long *timeop);
>>  int sock_common_setsockopt(struct socket *sock, int level, int optname,
>>  				  char __user *optval, unsigned int optlen);
>>  int compat_sock_common_getsockopt(struct socket *sock, int level,
>> @@ -2104,6 +2104,11 @@ static inline long sock_rcvtimeo(const struct sock *sk, bool noblock)
>>  	return noblock ? 0 : sk->sk_rcvtimeo;
>>  }
>>  
>> +static inline long sock_rcvtimeop(const struct sock *sk, long *timeop, bool noblock)
>> +{
>> +	return noblock ? 0 : (timeop ? *timeop : sk->sk_rcvtimeo);
>> +}
>> +
>>  static inline long sock_sndtimeo(const struct sock *sk, bool noblock)
>>  {
>>  	return noblock ? 0 : sk->sk_sndtimeo;
>> diff --git a/include/net/tcp.h b/include/net/tcp.h
>> index 7286db80e8b8..ca560b38a4a1 100644
>> --- a/include/net/tcp.h
>> +++ b/include/net/tcp.h
>> @@ -437,7 +437,7 @@ int compat_tcp_setsockopt(struct sock *sk, int level, int optname,
>>  void tcp_set_keepalive(struct sock *sk, int val);
>>  void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req);
>>  int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>> -		size_t len, int nonblock, int flags, int *addr_len);
>> +		size_t len, int nonblock, int flags, int *addr_len, long *timeop);
>>  void tcp_parse_options(const struct sk_buff *skb,
>>  		       struct tcp_options_received *opt_rx,
>>  		       int estab, struct tcp_fastopen_cookie *foc);
>> diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
>> index bfcf6be1d665..3160f6af88b2 100644
>> --- a/net/appletalk/ddp.c
>> +++ b/net/appletalk/ddp.c
>> @@ -1729,7 +1729,7 @@ out:
>>  }
>>  
>>  static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
>> -			 size_t size, int flags)
>> +			 size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct ddpehdr *ddp;
>> @@ -1739,7 +1739,7 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
>>  	struct sk_buff *skb;
>>  
>>  	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
>> -						flags & MSG_DONTWAIT, &err);
>> +						flags & MSG_DONTWAIT, &err, timeop);
>>  	lock_sock(sk);
>>  
>>  	if (!skb)
>> diff --git a/net/atm/common.c b/net/atm/common.c
>> index 7b491006eaf4..8def66eaed87 100644
>> --- a/net/atm/common.c
>> +++ b/net/atm/common.c
>> @@ -524,7 +524,7 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
>>  }
>>  
>>  int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
>> -		size_t size, int flags)
>> +		size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct atm_vcc *vcc;
>> @@ -544,7 +544,7 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
>>  	    !test_bit(ATM_VF_READY, &vcc->flags))
>>  		return 0;
>>  
>> -	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &error);
>> +	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &error, timeop);
>>  	if (!skb)
>>  		return error;
>>  
>> diff --git a/net/atm/common.h b/net/atm/common.h
>> index cc3c2dae4d79..b370ffd78a39 100644
>> --- a/net/atm/common.h
>> +++ b/net/atm/common.h
>> @@ -14,7 +14,7 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family);
>>  int vcc_release(struct socket *sock);
>>  int vcc_connect(struct socket *sock, int itf, short vpi, int vci);
>>  int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
>> -		size_t size, int flags);
>> +		size_t size, int flags, long *timeop);
>>  int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
>>  		size_t total_len);
>>  unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait);
>> diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
>> index c35c3f48fc0f..ee0411920216 100644
>> --- a/net/ax25/af_ax25.c
>> +++ b/net/ax25/af_ax25.c
>> @@ -1600,7 +1600,7 @@ out:
>>  }
>>  
>>  static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -	struct msghdr *msg, size_t size, int flags)
>> +	struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct sk_buff *skb;
>> @@ -1619,7 +1619,7 @@ static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  	/* Now we can treat all alike */
>>  	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
>> -				flags & MSG_DONTWAIT, &err);
>> +				flags & MSG_DONTWAIT, &err, timeop);
>>  	if (skb == NULL)
>>  		goto out;
>>  
>> diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
>> index 2021c481cdb6..4896bd954293 100644
>> --- a/net/bluetooth/af_bluetooth.c
>> +++ b/net/bluetooth/af_bluetooth.c
>> @@ -209,7 +209,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
>>  EXPORT_SYMBOL(bt_accept_dequeue);
>>  
>>  int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -				struct msghdr *msg, size_t len, int flags)
>> +				struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	int noblock = flags & MSG_DONTWAIT;
>>  	struct sock *sk = sock->sk;
>> @@ -222,7 +222,7 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	if (flags & (MSG_OOB))
>>  		return -EOPNOTSUPP;
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb) {
>>  		if (sk->sk_shutdown & RCV_SHUTDOWN)
>>  			return 0;
>> @@ -282,7 +282,7 @@ static long bt_sock_data_wait(struct sock *sk, long timeo)
>>  }
>>  
>>  int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			       struct msghdr *msg, size_t size, int flags)
>> +			       struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	int err = 0;
>> @@ -297,7 +297,7 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	lock_sock(sk);
>>  
>>  	target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
>> -	timeo  = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
>> +	timeo  = sock_rcvtimeop(sk, timeop, flags & MSG_DONTWAIT);
>>  
>>  	do {
>>  		struct sk_buff *skb;
>> @@ -381,6 +381,8 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	} while (size);
>>  
>>  out:
>> +	if (timeop)
>> +		*timeop = timeo;
>>  	release_sock(sk);
>>  	return copied ? : err;
>>  }
>> diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
>> index 80d25c150a65..71934e068bbf 100644
>> --- a/net/bluetooth/hci_sock.c
>> +++ b/net/bluetooth/hci_sock.c
>> @@ -829,7 +829,7 @@ static void hci_sock_cmsg(struct sock *sk, struct msghdr *msg,
>>  }
>>  
>>  static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			    struct msghdr *msg, size_t len, int flags)
>> +			    struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	int noblock = flags & MSG_DONTWAIT;
>>  	struct sock *sk = sock->sk;
>> @@ -844,7 +844,7 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	if (sk->sk_state == BT_CLOSED)
>>  		return 0;
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb)
>>  		return err;
>>  
>> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
>> index e1378693cc90..b4a91945bc0a 100644
>> --- a/net/bluetooth/l2cap_sock.c
>> +++ b/net/bluetooth/l2cap_sock.c
>> @@ -971,7 +971,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
>>  }
>>  
>>  static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			      struct msghdr *msg, size_t len, int flags)
>> +			      struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct l2cap_pinfo *pi = l2cap_pi(sk);
>> @@ -998,9 +998,9 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	release_sock(sk);
>>  
>>  	if (sock->type == SOCK_STREAM)
>> -		err = bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
>> +		err = bt_sock_stream_recvmsg(iocb, sock, msg, len, flags, timeop);
>>  	else
>> -		err = bt_sock_recvmsg(iocb, sock, msg, len, flags);
>> +		err = bt_sock_recvmsg(iocb, sock, msg, len, flags, timeop);
>>  
>>  	if (pi->chan->mode != L2CAP_MODE_ERTM)
>>  		return err;
>> diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
>> index c603a5eb4720..a3cbf8c4daf5 100644
>> --- a/net/bluetooth/rfcomm/sock.c
>> +++ b/net/bluetooth/rfcomm/sock.c
>> @@ -617,7 +617,7 @@ done:
>>  }
>>  
>>  static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			       struct msghdr *msg, size_t size, int flags)
>> +			       struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
>> @@ -628,7 +628,7 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  		return 0;
>>  	}
>>  
>> -	len = bt_sock_stream_recvmsg(iocb, sock, msg, size, flags);
>> +	len = bt_sock_stream_recvmsg(iocb, sock, msg, size, flags, timeop);
>>  
>>  	lock_sock(sk);
>>  	if (!(flags & MSG_PEEK) && len > 0)
>> diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
>> index c06dbd3938e8..bfaa16bdc366 100644
>> --- a/net/bluetooth/sco.c
>> +++ b/net/bluetooth/sco.c
>> @@ -700,7 +700,7 @@ static void sco_conn_defer_accept(struct hci_conn *conn, u16 setting)
>>  }
>>  
>>  static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			    struct msghdr *msg, size_t len, int flags)
>> +			    struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct sco_pinfo *pi = sco_pi(sk);
>> @@ -718,7 +718,7 @@ static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  	release_sock(sk);
>>  
>> -	return bt_sock_recvmsg(iocb, sock, msg, len, flags);
>> +	return bt_sock_recvmsg(iocb, sock, msg, len, flags, timeop);
>>  }
>>  
>>  static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
>> diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
>> index e8437094d15f..069eb2ffde29 100644
>> --- a/net/caif/caif_socket.c
>> +++ b/net/caif/caif_socket.c
>> @@ -272,7 +272,7 @@ static void caif_check_flow_release(struct sock *sk)
>>   * changed locking, address handling and added MSG_TRUNC.
>>   */
>>  static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			       struct msghdr *m, size_t len, int flags)
>> +			       struct msghdr *m, size_t len, int flags, long *timeop)
>>  
>>  {
>>  	struct sock *sk = sock->sk;
>> @@ -284,7 +284,7 @@ static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	if (m->msg_flags&MSG_OOB)
>>  		goto read_error;
>>  
>> -	skb = skb_recv_datagram(sk, flags, 0 , &ret);
>> +	skb = skb_recv_datagram(sk, flags, 0 , &ret, timeop);
>>  	if (!skb)
>>  		goto read_error;
>>  	copylen = skb->len;
>> @@ -345,7 +345,7 @@ static long caif_stream_data_wait(struct sock *sk, long timeo)
>>   */
>>  static int caif_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  			       struct msghdr *msg, size_t size,
>> -			       int flags)
>> +			       int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	int copied = 0;
>> @@ -367,7 +367,7 @@ static int caif_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  	caif_read_lock(sk);
>>  	target = sock_rcvlowat(sk, flags&MSG_WAITALL, size);
>> -	timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT);
>> +	timeo = sock_rcvtimeop(sk, timeop, flags&MSG_DONTWAIT);
>>  
>>  	do {
>>  		int chunk;
>> @@ -450,6 +450,8 @@ unlock:
>>  	caif_read_unlock(sk);
>>  
>>  out:
>> +	if (timeop)
>> +		*timeop = timeo;
>>  	return copied ? : err;
>>  }
>>  
>> diff --git a/net/can/bcm.c b/net/can/bcm.c
>> index dcb75c0e66c1..dc12c80ec5cd 100644
>> --- a/net/can/bcm.c
>> +++ b/net/can/bcm.c
>> @@ -1541,7 +1541,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
>>  }
>>  
>>  static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -		       struct msghdr *msg, size_t size, int flags)
>> +		       struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct sk_buff *skb;
>> @@ -1551,7 +1551,7 @@ static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  	noblock =  flags & MSG_DONTWAIT;
>>  	flags   &= ~MSG_DONTWAIT;
>> -	skb = skb_recv_datagram(sk, flags, noblock, &error);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &error, timeop);
>>  	if (!skb)
>>  		return error;
>>  
>> diff --git a/net/can/raw.c b/net/can/raw.c
>> index 081e81fd017f..0a4aa9d98e5e 100644
>> --- a/net/can/raw.c
>> +++ b/net/can/raw.c
>> @@ -731,7 +731,7 @@ send_failed:
>>  }
>>  
>>  static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -		       struct msghdr *msg, size_t size, int flags)
>> +		       struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct sk_buff *skb;
>> @@ -741,7 +741,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	noblock =  flags & MSG_DONTWAIT;
>>  	flags   &= ~MSG_DONTWAIT;
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb)
>>  		return err;
>>  
>> diff --git a/net/core/datagram.c b/net/core/datagram.c
>> index 488dd1a825c0..856e18c586c6 100644
>> --- a/net/core/datagram.c
>> +++ b/net/core/datagram.c
>> @@ -138,6 +138,9 @@ out_noerr:
>>   *	@off: an offset in bytes to peek skb from. Returns an offset
>>   *	      within an skb where data actually starts
>>   *	@err: error code returned
>> + *	@timeop: per call timeout (as opposed as per socket via SO_RCVTIMEO),
>> + *		 will return the remaining time, used in recvmmsg, ignored
>> + *		 if set to NULL.
>>   *
>>   *	Get a datagram skbuff, understands the peeking, nonblocking wakeups
>>   *	and possible races. This replaces identical code in packet, raw and
>> @@ -162,7 +165,7 @@ out_noerr:
>>   *	the standard around please.
>>   */
>>  struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
>> -				    int *peeked, int *off, int *err)
>> +				    int *peeked, int *off, int *err, long *timeop)
>>  {
>>  	struct sk_buff *skb, *last;
>>  	long timeo;
>> @@ -174,7 +177,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
>>  	if (error)
>>  		goto no_packet;
>>  
>> -	timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
>> +	timeo = sock_rcvtimeop(sk, timeop, flags & MSG_DONTWAIT);
>>  
>>  	do {
>>  		/* Again only user level code calls this function, so nothing
>> @@ -205,6 +208,8 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
>>  
>>  			spin_unlock_irqrestore(&queue->lock, cpu_flags);
>>  			*off = _off;
>> +			if (timeop)
>> +				*timeop = timeo;
>>  			return skb;
>>  		}
>>  		spin_unlock_irqrestore(&queue->lock, cpu_flags);
>> @@ -219,22 +224,24 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
>>  			goto no_packet;
>>  
>>  	} while (!wait_for_more_packets(sk, err, &timeo, last));
>> -
>> +out:
>> +	if (timeop)
>> +		*timeop = timeo;
>>  	return NULL;
>>  
>>  no_packet:
>>  	*err = error;
>> -	return NULL;
>> +	goto out;
>>  }
>>  EXPORT_SYMBOL(__skb_recv_datagram);
>>  
>>  struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned int flags,
>> -				  int noblock, int *err)
>> +				  int noblock, int *err, long *timeop)
>>  {
>>  	int peeked, off = 0;
>>  
>>  	return __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
>> -				   &peeked, &off, err);
>> +				   &peeked, &off, err, timeop);
>>  }
>>  EXPORT_SYMBOL(skb_recv_datagram);
>>  
>> diff --git a/net/core/sock.c b/net/core/sock.c
>> index 026e01f70274..b462e38785af 100644
>> --- a/net/core/sock.c
>> +++ b/net/core/sock.c
>> @@ -2191,7 +2191,7 @@ int sock_no_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
>>  EXPORT_SYMBOL(sock_no_sendmsg);
>>  
>>  int sock_no_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
>> -		    size_t len, int flags)
>> +		    size_t len, int flags, long *timeop)
>>  {
>>  	return -EOPNOTSUPP;
>>  }
>> @@ -2577,14 +2577,14 @@ EXPORT_SYMBOL(compat_sock_common_getsockopt);
>>  #endif
>>  
>>  int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			struct msghdr *msg, size_t size, int flags)
>> +			struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	int addr_len = 0;
>>  	int err;
>>  
>>  	err = sk->sk_prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT,
>> -				   flags & ~MSG_DONTWAIT, &addr_len);
>> +				   flags & ~MSG_DONTWAIT, &addr_len, timeop);
>>  	if (err >= 0)
>>  		msg->msg_namelen = addr_len;
>>  	return err;
>> diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
>> index c67816647cce..fbf4cc113ffe 100644
>> --- a/net/dccp/dccp.h
>> +++ b/net/dccp/dccp.h
>> @@ -314,7 +314,7 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>>  		 size_t size);
>>  int dccp_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  		 struct msghdr *msg, size_t len, int nonblock, int flags,
>> -		 int *addr_len);
>> +		 int *addr_len, long *timeop);
>>  void dccp_shutdown(struct sock *sk, int how);
>>  int inet_dccp_listen(struct socket *sock, int backlog);
>>  unsigned int dccp_poll(struct file *file, struct socket *sock,
>> diff --git a/net/dccp/proto.c b/net/dccp/proto.c
>> index de2c1e719305..92ae3d37c7f0 100644
>> --- a/net/dccp/proto.c
>> +++ b/net/dccp/proto.c
>> @@ -808,7 +808,7 @@ out_discard:
>>  EXPORT_SYMBOL_GPL(dccp_sendmsg);
>>  
>>  int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>> -		 size_t len, int nonblock, int flags, int *addr_len)
>> +		 size_t len, int nonblock, int flags, int *addr_len, long *timeop)
>>  {
>>  	const struct dccp_hdr *dh;
>>  	long timeo;
>> @@ -820,7 +820,7 @@ int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>>  		goto out;
>>  	}
>>  
>> -	timeo = sock_rcvtimeo(sk, nonblock);
>> +	timeo = sock_rcvtimeop(sk, timeop, nonblock);
>>  
>>  	do {
>>  		struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
>> @@ -910,6 +910,8 @@ verify_sock_status:
>>  	} while (1);
>>  out:
>>  	release_sock(sk);
>> +	if (timeop)
>> +		*timeop = timeo;
>>  	return len;
>>  }
>>  
>> diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
>> index ae011b46c071..86dfcbe505de 100644
>> --- a/net/decnet/af_decnet.c
>> +++ b/net/decnet/af_decnet.c
>> @@ -1669,7 +1669,7 @@ static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int
>>  
>>  
>>  static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -	struct msghdr *msg, size_t size, int flags)
>> +	struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct dn_scp *scp = DN_SK(sk);
>> @@ -1680,7 +1680,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	struct sk_buff *skb, *n;
>>  	struct dn_skb_cb *cb = NULL;
>>  	unsigned char eor = 0;
>> -	long timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
>> +	long timeo = sock_rcvtimeop(sk, timeop, flags & MSG_DONTWAIT);
>>  
>>  	lock_sock(sk);
>>  
>> @@ -1814,7 +1814,8 @@ out:
>>  	}
>>  
>>  	release_sock(sk);
>> -
>> +	if (timeop)
>> +		*timeop = timeo;
>>  	return rv;
>>  }
>>  
>> diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
>> index 4f0ed8780194..dd7de8959d07 100644
>> --- a/net/ieee802154/dgram.c
>> +++ b/net/ieee802154/dgram.c
>> @@ -305,14 +305,14 @@ out:
>>  
>>  static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  		struct msghdr *msg, size_t len, int noblock, int flags,
>> -		int *addr_len)
>> +		int *addr_len, long *timeop)
>>  {
>>  	size_t copied = 0;
>>  	int err = -EOPNOTSUPP;
>>  	struct sk_buff *skb;
>>  	DECLARE_SOCKADDR(struct sockaddr_ieee802154 *, saddr, msg->msg_name);
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb)
>>  		goto out;
>>  
>> diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c
>> index 74d54fae33d7..0303aa66a9e2 100644
>> --- a/net/ieee802154/raw.c
>> +++ b/net/ieee802154/raw.c
>> @@ -179,13 +179,13 @@ out:
>>  }
>>  
>>  static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>> -		       size_t len, int noblock, int flags, int *addr_len)
>> +		       size_t len, int noblock, int flags, int *addr_len, long *timeop)
>>  {
>>  	size_t copied = 0;
>>  	int err = -EOPNOTSUPP;
>>  	struct sk_buff *skb;
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb)
>>  		goto out;
>>  
>> diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
>> index d156b3c5f363..69356a067dbf 100644
>> --- a/net/ipv4/af_inet.c
>> +++ b/net/ipv4/af_inet.c
>> @@ -757,7 +757,7 @@ ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
>>  EXPORT_SYMBOL(inet_sendpage);
>>  
>>  int inet_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
>> -		 size_t size, int flags)
>> +		 size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	int addr_len = 0;
>> @@ -766,7 +766,7 @@ int inet_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
>>  	sock_rps_record_flow(sk);
>>  
>>  	err = sk->sk_prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT,
>> -				   flags & ~MSG_DONTWAIT, &addr_len);
>> +				   flags & ~MSG_DONTWAIT, &addr_len, timeop);
>>  	if (err >= 0)
>>  		msg->msg_namelen = addr_len;
>>  	return err;
>> diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
>> index 044a0ddf6a79..791be60b38f1 100644
>> --- a/net/ipv4/ping.c
>> +++ b/net/ipv4/ping.c
>> @@ -840,7 +840,7 @@ do_confirm:
>>  }
>>  
>>  int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>> -		 size_t len, int noblock, int flags, int *addr_len)
>> +		 size_t len, int noblock, int flags, int *addr_len, long *timeop)
>>  {
>>  	struct inet_sock *isk = inet_sk(sk);
>>  	int family = sk->sk_family;
>> @@ -864,7 +864,7 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>>  		}
>>  	}
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb)
>>  		goto out;
>>  
>> diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
>> index 2c65160565e1..bf4fc70229e7 100644
>> --- a/net/ipv4/raw.c
>> +++ b/net/ipv4/raw.c
>> @@ -685,7 +685,7 @@ out:	return ret;
>>   */
>>  
>>  static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>> -		       size_t len, int noblock, int flags, int *addr_len)
>> +		       size_t len, int noblock, int flags, int *addr_len, long *timeop)
>>  {
>>  	struct inet_sock *inet = inet_sk(sk);
>>  	size_t copied = 0;
>> @@ -701,7 +701,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>>  		goto out;
>>  	}
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb)
>>  		goto out;
>>  
>> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
>> index 9d2118e5fbc7..0572060f83aa 100644
>> --- a/net/ipv4/tcp.c
>> +++ b/net/ipv4/tcp.c
>> @@ -1602,7 +1602,7 @@ EXPORT_SYMBOL(tcp_read_sock);
>>   */
>>  
>>  int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>> -		size_t len, int nonblock, int flags, int *addr_len)
>> +		size_t len, int nonblock, int flags, int *addr_len, long *timeop)
>>  {
>>  	struct tcp_sock *tp = tcp_sk(sk);
>>  	int copied = 0;
>> @@ -1627,7 +1627,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>>  	if (sk->sk_state == TCP_LISTEN)
>>  		goto out;
>>  
>> -	timeo = sock_rcvtimeo(sk, nonblock);
>> +	timeo = sock_rcvtimeop(sk, timeop, nonblock);
>>  
>>  	/* Urgent data needs to be handled specially. */
>>  	if (flags & MSG_OOB)
>> @@ -1994,20 +1994,18 @@ skip_copy:
>>  
>>  	/* Clean up data we have read: This will do ACK frames. */
>>  	tcp_cleanup_rbuf(sk, copied);
>> -
>> -	release_sock(sk);
>> -	return copied;
>> -
>>  out:
>>  	release_sock(sk);
>> -	return err;
>> +	if (timeop)
>> +		*timeop = timeo;
>> +	return copied;
>>  
>>  recv_urg:
>> -	err = tcp_recv_urg(sk, msg, len, flags);
>> +	copied = tcp_recv_urg(sk, msg, len, flags);
>>  	goto out;
>>  
>>  recv_sndq:
>> -	err = tcp_peek_sndq(sk, msg, len);
>> +	copied = tcp_peek_sndq(sk, msg, len);
>>  	goto out;
>>  }
>>  EXPORT_SYMBOL(tcp_recvmsg);
>> diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
>> index 7d5a8661df76..0c77df4c3523 100644
>> --- a/net/ipv4/udp.c
>> +++ b/net/ipv4/udp.c
>> @@ -1262,7 +1262,7 @@ EXPORT_SYMBOL(udp_ioctl);
>>   */
>>  
>>  int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>> -		size_t len, int noblock, int flags, int *addr_len)
>> +		size_t len, int noblock, int flags, int *addr_len, long *timeop)
>>  {
>>  	struct inet_sock *inet = inet_sk(sk);
>>  	DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
>> @@ -1278,7 +1278,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>>  
>>  try_again:
>>  	skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
>> -				  &peeked, &off, &err);
>> +				  &peeked, &off, &err, timeop);
>>  	if (!skb)
>>  		goto out;
>>  
>> diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h
>> index f3c27899f62b..a39aa9996b72 100644
>> --- a/net/ipv4/udp_impl.h
>> +++ b/net/ipv4/udp_impl.h
>> @@ -22,7 +22,7 @@ int compat_udp_getsockopt(struct sock *sk, int level, int optname,
>>  			  char __user *optval, int __user *optlen);
>>  #endif
>>  int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>> -		size_t len, int noblock, int flags, int *addr_len);
>> +		size_t len, int noblock, int flags, int *addr_len, long *timeop);
>>  int udp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
>>  		 int flags);
>>  int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
>> diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
>> index b2dc60b0c764..1d267f89eb71 100644
>> --- a/net/ipv6/raw.c
>> +++ b/net/ipv6/raw.c
>> @@ -458,7 +458,7 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
>>  
>>  static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  		  struct msghdr *msg, size_t len,
>> -		  int noblock, int flags, int *addr_len)
>> +		  int noblock, int flags, int *addr_len, long *timeop)
>>  {
>>  	struct ipv6_pinfo *np = inet6_sk(sk);
>>  	DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
>> @@ -475,7 +475,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  	if (np->rxpmtu && np->rxopt.bits.rxpmtu)
>>  		return ipv6_recv_rxpmtu(sk, msg, len, addr_len);
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb)
>>  		goto out;
>>  
>> diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
>> index 7092ff78fd84..6963babf2dff 100644
>> --- a/net/ipv6/udp.c
>> +++ b/net/ipv6/udp.c
>> @@ -380,7 +380,7 @@ EXPORT_SYMBOL_GPL(udp6_lib_lookup);
>>  
>>  int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  		  struct msghdr *msg, size_t len,
>> -		  int noblock, int flags, int *addr_len)
>> +		  int noblock, int flags, int *addr_len, long *timeop)
>>  {
>>  	struct ipv6_pinfo *np = inet6_sk(sk);
>>  	struct inet_sock *inet = inet_sk(sk);
>> @@ -400,7 +400,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  
>>  try_again:
>>  	skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
>> -				  &peeked, &off, &err);
>> +				  &peeked, &off, &err, timeop);
>>  	if (!skb)
>>  		goto out;
>>  
>> diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h
>> index c779c3c90b9d..cd414d719977 100644
>> --- a/net/ipv6/udp_impl.h
>> +++ b/net/ipv6/udp_impl.h
>> @@ -26,7 +26,7 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
>>  int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>>  		  size_t len);
>>  int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>> -		  size_t len, int noblock, int flags, int *addr_len);
>> +		  size_t len, int noblock, int flags, int *addr_len, long *timeop);
>>  int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
>>  void udpv6_destroy_sock(struct sock *sk);
>>  
>> diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
>> index 91729b807c7d..4964c1e0ab03 100644
>> --- a/net/ipx/af_ipx.c
>> +++ b/net/ipx/af_ipx.c
>> @@ -1756,7 +1756,7 @@ out:
>>  
>>  
>>  static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -		struct msghdr *msg, size_t size, int flags)
>> +		struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct ipx_sock *ipxs = ipx_sk(sk);
>> @@ -1791,7 +1791,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  		goto out;
>>  
>>  	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
>> -				flags & MSG_DONTWAIT, &rc);
>> +				flags & MSG_DONTWAIT, &rc, timeop);
>>  	if (!skb) {
>>  		if (rc == -EAGAIN && (sk->sk_shutdown & RCV_SHUTDOWN))
>>  			rc = 0;
>> diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
>> index 54747c25c86c..0991da69f39d 100644
>> --- a/net/irda/af_irda.c
>> +++ b/net/irda/af_irda.c
>> @@ -1373,7 +1373,7 @@ out:
>>   *    after being read, regardless of how much the user actually read
>>   */
>>  static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
>> -			      struct msghdr *msg, size_t size, int flags)
>> +			      struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct irda_sock *self = irda_sk(sk);
>> @@ -1384,7 +1384,7 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
>>  	IRDA_DEBUG(4, "%s()\n", __func__);
>>  
>>  	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
>> -				flags & MSG_DONTWAIT, &err);
>> +				flags & MSG_DONTWAIT, &err, timeop);
>>  	if (!skb)
>>  		return err;
>>  
>> @@ -1422,7 +1422,7 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
>>   * Function irda_recvmsg_stream (iocb, sock, msg, size, flags)
>>   */
>>  static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
>> -			       struct msghdr *msg, size_t size, int flags)
>> +			       struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct irda_sock *self = irda_sk(sk);
>> @@ -1445,7 +1445,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
>>  
>>  	err = 0;
>>  	target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
>> -	timeo = sock_rcvtimeo(sk, noblock);
>> +	timeo = sock_rcvtimeop(sk, timeop, noblock);
>>  
>>  	do {
>>  		int chunk;
>> @@ -1480,8 +1480,10 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
>>  
>>  			finish_wait(sk_sleep(sk), &wait);
>>  
>> -			if (err)
>> -				return err;
>> +			if (err) {
>> +				copied = err;
>> +				break;
>> +			}
>>  			if (sk->sk_shutdown & RCV_SHUTDOWN)
>>  				break;
>>  
>> @@ -1534,6 +1536,8 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
>>  		}
>>  	}
>>  
>> +	if (timeop)
>> +		*timeop = timeo;
>>  	return copied;
>>  }
>>  
>> diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
>> index 7a95fa4a3de1..3aebb4ffae54 100644
>> --- a/net/iucv/af_iucv.c
>> +++ b/net/iucv/af_iucv.c
>> @@ -1321,7 +1321,7 @@ static void iucv_process_message_q(struct sock *sk)
>>  }
>>  
>>  static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			     struct msghdr *msg, size_t len, int flags)
>> +			     struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	int noblock = flags & MSG_DONTWAIT;
>>  	struct sock *sk = sock->sk;
>> @@ -1342,7 +1342,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  	/* receive/dequeue next skb:
>>  	 * the function understands MSG_PEEK and, thus, does not dequeue skb */
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb) {
>>  		if (sk->sk_shutdown & RCV_SHUTDOWN)
>>  			return 0;
>> diff --git a/net/key/af_key.c b/net/key/af_key.c
>> index ba2a2f95911c..27a2119bb905 100644
>> --- a/net/key/af_key.c
>> +++ b/net/key/af_key.c
>> @@ -3635,7 +3635,7 @@ out:
>>  
>>  static int pfkey_recvmsg(struct kiocb *kiocb,
>>  			 struct socket *sock, struct msghdr *msg, size_t len,
>> -			 int flags)
>> +			 int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct pfkey_sock *pfk = pfkey_sk(sk);
>> @@ -3646,7 +3646,7 @@ static int pfkey_recvmsg(struct kiocb *kiocb,
>>  	if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT))
>>  		goto out;
>>  
>> -	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
>> +	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err, timeop);
>>  	if (skb == NULL)
>>  		goto out;
>>  
>> diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
>> index 369a9822488c..4347233855cb 100644
>> --- a/net/l2tp/l2tp_ip.c
>> +++ b/net/l2tp/l2tp_ip.c
>> @@ -507,7 +507,7 @@ no_route:
>>  }
>>  
>>  static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
>> -			   size_t len, int noblock, int flags, int *addr_len)
>> +			   size_t len, int noblock, int flags, int *addr_len, long *timeop)
>>  {
>>  	struct inet_sock *inet = inet_sk(sk);
>>  	size_t copied = 0;
>> @@ -518,7 +518,7 @@ static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
>>  	if (flags & MSG_OOB)
>>  		goto out;
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb)
>>  		goto out;
>>  
>> diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
>> index f3f98a156cee..6c839ba9d299 100644
>> --- a/net/l2tp/l2tp_ip6.c
>> +++ b/net/l2tp/l2tp_ip6.c
>> @@ -645,7 +645,7 @@ do_confirm:
>>  
>>  static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  			    struct msghdr *msg, size_t len, int noblock,
>> -			    int flags, int *addr_len)
>> +			    int flags, int *addr_len, long *timeop)
>>  {
>>  	struct ipv6_pinfo *np = inet6_sk(sk);
>>  	DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name);
>> @@ -662,7 +662,7 @@ static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  	if (flags & MSG_ERRQUEUE)
>>  		return ipv6_recv_error(sk, msg, len, addr_len);
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb)
>>  		goto out;
>>  
>> diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
>> index 13752d96275e..88558464319b 100644
>> --- a/net/l2tp/l2tp_ppp.c
>> +++ b/net/l2tp/l2tp_ppp.c
>> @@ -187,7 +187,7 @@ static int pppol2tp_recv_payload_hook(struct sk_buff *skb)
>>   */
>>  static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  			    struct msghdr *msg, size_t len,
>> -			    int flags)
>> +			    int flags, long *timeop)
>>  {
>>  	int err;
>>  	struct sk_buff *skb;
>> @@ -199,7 +199,7 @@ static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  	err = 0;
>>  	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
>> -				flags & MSG_DONTWAIT, &err);
>> +				flags & MSG_DONTWAIT, &err, timeop);
>>  	if (!skb)
>>  		goto end;
>>  
>> diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
>> index 0080d2b0a8ae..b5edf838f9fa 100644
>> --- a/net/llc/af_llc.c
>> +++ b/net/llc/af_llc.c
>> @@ -705,7 +705,7 @@ out:
>>   *	Returns non-negative upon success, negative otherwise.
>>   */
>>  static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			  struct msghdr *msg, size_t len, int flags)
>> +			  struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	DECLARE_SOCKADDR(struct sockaddr_llc *, uaddr, msg->msg_name);
>>  	const int nonblock = flags & MSG_DONTWAIT;
>> @@ -725,7 +725,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	if (unlikely(sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN))
>>  		goto out;
>>  
>> -	timeo = sock_rcvtimeo(sk, nonblock);
>> +	timeo = sock_rcvtimeop(sk, timeop, nonblock);
>>  
>>  	seq = &llc->copied_seq;
>>  	if (flags & MSG_PEEK) {
>> @@ -851,6 +851,8 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  out:
>>  	release_sock(sk);
>> +	if (timeop)
>> +		*timeop = timeo;
>>  	return copied;
>>  copy_uaddr:
>>  	if (uaddr != NULL && skb != NULL) {
>> diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
>> index e6fac7e3db52..8d661b0b2ca3 100644
>> --- a/net/netlink/af_netlink.c
>> +++ b/net/netlink/af_netlink.c
>> @@ -2404,7 +2404,7 @@ out:
>>  
>>  static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
>>  			   struct msghdr *msg, size_t len,
>> -			   int flags)
>> +			   int flags, long *timeop)
>>  {
>>  	struct sock_iocb *siocb = kiocb_to_siocb(kiocb);
>>  	struct scm_cookie scm;
>> @@ -2420,7 +2420,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
>>  
>>  	copied = 0;
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (skb == NULL)
>>  		goto out;
>>  
>> diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
>> index ede50d197e10..4a9078e2bf7a 100644
>> --- a/net/netrom/af_netrom.c
>> +++ b/net/netrom/af_netrom.c
>> @@ -1134,7 +1134,7 @@ out:
>>  }
>>  
>>  static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -		      struct msghdr *msg, size_t size, int flags)
>> +		      struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	DECLARE_SOCKADDR(struct sockaddr_ax25 *, sax, msg->msg_name);
>> @@ -1154,7 +1154,7 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	}
>>  
>>  	/* Now we can treat all alike */
>> -	if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) {
>> +	if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er, timeop)) == NULL) {
>>  		release_sock(sk);
>>  		return er;
>>  	}
>> diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c
>> index 51f077a92fa9..0b233d1f1a57 100644
>> --- a/net/nfc/llcp_sock.c
>> +++ b/net/nfc/llcp_sock.c
>> @@ -794,7 +794,7 @@ static int llcp_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
>>  }
>>  
>>  static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			     struct msghdr *msg, size_t len, int flags)
>> +			     struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	int noblock = flags & MSG_DONTWAIT;
>>  	struct sock *sk = sock->sk;
>> @@ -817,7 +817,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	if (flags & (MSG_OOB))
>>  		return -EOPNOTSUPP;
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb) {
>>  		pr_err("Recv datagram failed state %d %d %d",
>>  		       sk->sk_state, err, sock_error(sk));
>> diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
>> index 11c3544ea546..ab84d8740fe4 100644
>> --- a/net/nfc/rawsock.c
>> +++ b/net/nfc/rawsock.c
>> @@ -249,7 +249,7 @@ static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock,
>>  }
>>  
>>  static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			   struct msghdr *msg, size_t len, int flags)
>> +			   struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	int noblock = flags & MSG_DONTWAIT;
>>  	struct sock *sk = sock->sk;
>> @@ -259,7 +259,7 @@ static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  	pr_debug("sock=%p sk=%p len=%zu flags=%d\n", sock, sk, len, flags);
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &rc);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &rc, timeop);
>>  	if (!skb)
>>  		return rc;
>>  
>> diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
>> index b85c67ccb797..f56d816340e2 100644
>> --- a/net/packet/af_packet.c
>> +++ b/net/packet/af_packet.c
>> @@ -2852,7 +2852,7 @@ out:
>>   */
>>  
>>  static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			  struct msghdr *msg, size_t len, int flags)
>> +			  struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct sk_buff *skb;
>> @@ -2884,7 +2884,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	 *	but then it will block.
>>  	 */
>>  
>> -	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
>> +	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err, timeop);
>>  
>>  	/*
>>  	 *	An error occurred so return it. Because skb_recv_datagram()
>> diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c
>> index 290352c0e6b4..77eff48eeb83 100644
>> --- a/net/phonet/datagram.c
>> +++ b/net/phonet/datagram.c
>> @@ -127,7 +127,7 @@ static int pn_sendmsg(struct kiocb *iocb, struct sock *sk,
>>  
>>  static int pn_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  			struct msghdr *msg, size_t len, int noblock,
>> -			int flags, int *addr_len)
>> +			int flags, int *addr_len, long *timeop)
>>  {
>>  	struct sk_buff *skb = NULL;
>>  	struct sockaddr_pn sa;
>> @@ -138,7 +138,7 @@ static int pn_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  			MSG_CMSG_COMPAT))
>>  		goto out_nofree;
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &rval);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &rval, timeop);
>>  	if (skb == NULL)
>>  		goto out_nofree;
>>  
>> diff --git a/net/phonet/pep.c b/net/phonet/pep.c
>> index 70a547ea5177..c5832e1958f8 100644
>> --- a/net/phonet/pep.c
>> +++ b/net/phonet/pep.c
>> @@ -783,7 +783,7 @@ static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp)
>>  	u8 pipe_handle, enabled, n_sb;
>>  	u8 aligned = 0;
>>  
>> -	skb = skb_recv_datagram(sk, 0, flags & O_NONBLOCK, errp);
>> +	skb = skb_recv_datagram(sk, 0, flags & O_NONBLOCK, errp, NULL);
>>  	if (!skb)
>>  		return NULL;
>>  
>> @@ -1248,7 +1248,7 @@ struct sk_buff *pep_read(struct sock *sk)
>>  
>>  static int pep_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  			struct msghdr *msg, size_t len, int noblock,
>> -			int flags, int *addr_len)
>> +			int flags, int *addr_len, long *timeop)
>>  {
>>  	struct sk_buff *skb;
>>  	int err;
>> @@ -1277,7 +1277,7 @@ static int pep_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  			return -EINVAL;
>>  	}
>>  
>> -	skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	lock_sock(sk);
>>  	if (skb == NULL) {
>>  		if (err == -ENOTCONN && sk->sk_state == TCP_CLOSE_WAIT)
>> diff --git a/net/rds/rds.h b/net/rds/rds.h
>> index 48f8ffc60f8f..e511e569bbc9 100644
>> --- a/net/rds/rds.h
>> +++ b/net/rds/rds.h
>> @@ -706,7 +706,7 @@ void rds_inc_put(struct rds_incoming *inc);
>>  void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr,
>>  		       struct rds_incoming *inc, gfp_t gfp);
>>  int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
>> -		size_t size, int msg_flags);
>> +		size_t size, int msg_flags, long *timeop);
>>  void rds_clear_recv_queue(struct rds_sock *rs);
>>  int rds_notify_queue_get(struct rds_sock *rs, struct msghdr *msg);
>>  void rds_inc_info_copy(struct rds_incoming *inc,
>> diff --git a/net/rds/recv.c b/net/rds/recv.c
>> index bd82522534fc..6223a4b0fded 100644
>> --- a/net/rds/recv.c
>> +++ b/net/rds/recv.c
>> @@ -396,7 +396,7 @@ static int rds_cmsg_recv(struct rds_incoming *inc, struct msghdr *msg)
>>  }
>>  
>>  int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
>> -		size_t size, int msg_flags)
>> +		size_t size, int msg_flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct rds_sock *rs = rds_sk_to_rs(sk);
>> @@ -406,7 +406,7 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
>>  	struct rds_incoming *inc = NULL;
>>  
>>  	/* udp_recvmsg()->sock_recvtimeo() gets away without locking too.. */
>> -	timeo = sock_rcvtimeo(sk, nonblock);
>> +	timeo = sock_rcvtimeop(sk, timeop, nonblock);
>>  
>>  	rdsdebug("size %zu flags 0x%x timeo %ld\n", size, msg_flags, timeo);
>>  
>> @@ -493,6 +493,8 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
>>  		rds_inc_put(inc);
>>  
>>  out:
>> +	if (timeop)
>> +		*timeop = timeo;
>>  	return ret;
>>  }
>>  
>> diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
>> index 8451c8cdc9de..2cfc75a1cbbb 100644
>> --- a/net/rose/af_rose.c
>> +++ b/net/rose/af_rose.c
>> @@ -1212,7 +1212,7 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  
>>  static int rose_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			struct msghdr *msg, size_t size, int flags)
>> +			struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct rose_sock *rose = rose_sk(sk);
>> @@ -1229,7 +1229,7 @@ static int rose_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  		return -ENOTCONN;
>>  
>>  	/* Now we can treat all alike */
>> -	if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL)
>> +	if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er, timeop)) == NULL)
>>  		return er;
>>  
>>  	qbit = (skb->data[0] & ROSE_Q_BIT) == ROSE_Q_BIT;
>> diff --git a/net/rxrpc/ar-input.c b/net/rxrpc/ar-input.c
>> index 63b21e580de9..2319fae4b1f6 100644
>> --- a/net/rxrpc/ar-input.c
>> +++ b/net/rxrpc/ar-input.c
>> @@ -655,7 +655,7 @@ void rxrpc_data_ready(struct sock *sk)
>>  		return;
>>  	}
>>  
>> -	skb = skb_recv_datagram(sk, 0, 1, &ret);
>> +	skb = skb_recv_datagram(sk, 0, 1, &ret, NULL);
>>  	if (!skb) {
>>  		rxrpc_put_local(local);
>>  		if (ret == -EAGAIN)
>> diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
>> index ba9fd36d3f15..a21e51937e27 100644
>> --- a/net/rxrpc/ar-internal.h
>> +++ b/net/rxrpc/ar-internal.h
>> @@ -573,7 +573,7 @@ extern const struct file_operations rxrpc_connection_seq_fops;
>>   */
>>  void rxrpc_remove_user_ID(struct rxrpc_sock *, struct rxrpc_call *);
>>  int rxrpc_recvmsg(struct kiocb *, struct socket *, struct msghdr *, size_t,
>> -		  int);
>> +		  int, long *);
>>  
>>  /*
>>   * ar-security.c
>> diff --git a/net/rxrpc/ar-recvmsg.c b/net/rxrpc/ar-recvmsg.c
>> index e9aaa65c0778..e9082ed598cd 100644
>> --- a/net/rxrpc/ar-recvmsg.c
>> +++ b/net/rxrpc/ar-recvmsg.c
>> @@ -44,7 +44,7 @@ void rxrpc_remove_user_ID(struct rxrpc_sock *rx, struct rxrpc_call *call)
>>   *   simultaneously
>>   */
>>  int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -		  struct msghdr *msg, size_t len, int flags)
>> +		  struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	struct rxrpc_skb_priv *sp;
>>  	struct rxrpc_call *call = NULL, *continue_call = NULL;
>> @@ -63,7 +63,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  	ullen = msg->msg_flags & MSG_CMSG_COMPAT ? 4 : sizeof(unsigned long);
>>  
>> -	timeo = sock_rcvtimeo(&rx->sk, flags & MSG_DONTWAIT);
>> +	timeo = sock_rcvtimeop(&rx->sk, timeop, flags & MSG_DONTWAIT);
>>  	msg->msg_flags |= MSG_MORE;
>>  
>>  	lock_sock(&rx->sk);
>> @@ -78,7 +78,8 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  				release_sock(&rx->sk);
>>  				if (continue_call)
>>  					rxrpc_put_call(continue_call);
>> -				return -ENODATA;
>> +				copied = -ENODATA;
>> +				goto out_copied;
>>  			}
>>  		}
>>  
>> @@ -135,7 +136,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  				release_sock(&rx->sk);
>>  				rxrpc_put_call(continue_call);
>>  				_leave(" = %d [noncont]", copied);
>> -				return copied;
>> +				goto out_copied;
>>  			}
>>  		}
>>  
>> @@ -252,6 +253,9 @@ out:
>>  	if (continue_call)
>>  		rxrpc_put_call(continue_call);
>>  	_leave(" = %d [data]", copied);
>> +out_copied:
>> +	if (timeop)
>> +		*timeop = timeo;
>>  	return copied;
>>  
>>  	/* handle non-DATA messages such as aborts, incoming connections and
>> @@ -328,7 +332,8 @@ terminal_message:
>>  	if (continue_call)
>>  		rxrpc_put_call(continue_call);
>>  	_leave(" = %d", ret);
>> -	return ret;
>> +	copied = ret;
>> +	goto out_copied;
>>  
>>  copy_error:
>>  	_debug("copy error");
>> @@ -337,7 +342,8 @@ copy_error:
>>  	if (continue_call)
>>  		rxrpc_put_call(continue_call);
>>  	_leave(" = %d", ret);
>> -	return ret;
>> +	copied = ret;
>> +	goto out_copied;
>>  
>>  wait_interrupted:
>>  	ret = sock_intr_errno(timeo);
>> @@ -348,8 +354,7 @@ wait_error:
>>  	if (copied)
>>  		copied = ret;
>>  	_leave(" = %d [waitfail %d]", copied, ret);
>> -	return copied;
>> -
>> +	goto out_copied;
>>  }
>>  
>>  /**
>> diff --git a/net/sctp/socket.c b/net/sctp/socket.c
>> index 429899689408..d05161a168bc 100644
>> --- a/net/sctp/socket.c
>> +++ b/net/sctp/socket.c
>> @@ -2042,11 +2042,11 @@ static int sctp_skb_pull(struct sk_buff *skb, int len)
>>   *  flags   - flags sent or received with the user message, see Section
>>   *            5 for complete description of the flags.
>>   */
>> -static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
>> +static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *, long *);
>>  
>>  static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  			struct msghdr *msg, size_t len, int noblock,
>> -			int flags, int *addr_len)
>> +			int flags, int *addr_len, long *timeop)
>>  {
>>  	struct sctp_ulpevent *event = NULL;
>>  	struct sctp_sock *sp = sctp_sk(sk);
>> @@ -2066,7 +2066,7 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
>>  		goto out;
>>  	}
>>  
>> -	skb = sctp_skb_recv_datagram(sk, flags, noblock, &err);
>> +	skb = sctp_skb_recv_datagram(sk, flags, noblock, &err, timeop);
>>  	if (!skb)
>>  		goto out;
>>  
>> @@ -6519,13 +6519,13 @@ out:
>>   * with a few changes to make lksctp work.
>>   */
>>  static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
>> -					      int noblock, int *err)
>> +					      int noblock, int *err, long *timeop)
>>  {
>>  	int error;
>>  	struct sk_buff *skb;
>>  	long timeo;
>>  
>> -	timeo = sock_rcvtimeo(sk, noblock);
>> +	timeo = sock_rcvtimeop(sk, timeop, noblock);
>>  
>>  	pr_debug("%s: timeo:%ld, max:%ld\n", __func__, timeo,
>>  		 MAX_SCHEDULE_TIMEOUT);
>> @@ -6549,7 +6549,7 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
>>  		}
>>  
>>  		if (skb)
>> -			return skb;
>> +			break;
>>  
>>  		/* Caller is allowed not to check sk->sk_err before calling. */
>>  		error = sock_error(sk);
>> @@ -6569,11 +6569,15 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
>>  			goto no_packet;
>>  	} while (sctp_wait_for_packet(sk, err, &timeo) == 0);
>>  
>> -	return NULL;
>> +out:
>> +	if (timeop)
>> +		*timeop = timeo;
>> +
>> +	return skb;
>>  
>>  no_packet:
>>  	*err = error;
>> -	return NULL;
>> +	goto out;
>>  }
>>  
>>  /* If sndbuf has changed, wake up per association sndbuf waiters.  */
>> diff --git a/net/socket.c b/net/socket.c
>> index abf56b2a14f9..310a50971769 100644
>> --- a/net/socket.c
>> +++ b/net/socket.c
>> @@ -772,7 +772,7 @@ void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
>>  EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops);
>>  
>>  static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
>> -				       struct msghdr *msg, size_t size, int flags)
>> +				       struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	struct sock_iocb *si = kiocb_to_siocb(iocb);
>>  
>> @@ -782,19 +782,19 @@ static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
>>  	si->size = size;
>>  	si->flags = flags;
>>  
>> -	return sock->ops->recvmsg(iocb, sock, msg, size, flags);
>> +	return sock->ops->recvmsg(iocb, sock, msg, size, flags, timeop);
>>  }
>>  
>>  static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -				 struct msghdr *msg, size_t size, int flags)
>> +				 struct msghdr *msg, size_t size, int flags, long *timeop)
>>  {
>>  	int err = security_socket_recvmsg(sock, msg, size, flags);
>>  
>> -	return err ?: __sock_recvmsg_nosec(iocb, sock, msg, size, flags);
>> +	return err ?: __sock_recvmsg_nosec(iocb, sock, msg, size, flags, timeop);
>>  }
>>  
>>  int sock_recvmsg(struct socket *sock, struct msghdr *msg,
>> -		 size_t size, int flags)
>> +		 size_t size, int flags, long *timeop)
>>  {
>>  	struct kiocb iocb;
>>  	struct sock_iocb siocb;
>> @@ -802,7 +802,7 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg,
>>  
>>  	init_sync_kiocb(&iocb, NULL);
>>  	iocb.private = &siocb;
>> -	ret = __sock_recvmsg(&iocb, sock, msg, size, flags);
>> +	ret = __sock_recvmsg(&iocb, sock, msg, size, flags, timeop);
>>  	if (-EIOCBQUEUED == ret)
>>  		ret = wait_on_sync_kiocb(&iocb);
>>  	return ret;
>> @@ -810,7 +810,7 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg,
>>  EXPORT_SYMBOL(sock_recvmsg);
>>  
>>  static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg,
>> -			      size_t size, int flags)
>> +			      size_t size, int flags, long *timeop)
>>  {
>>  	struct kiocb iocb;
>>  	struct sock_iocb siocb;
>> @@ -818,7 +818,7 @@ static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg,
>>  
>>  	init_sync_kiocb(&iocb, NULL);
>>  	iocb.private = &siocb;
>> -	ret = __sock_recvmsg_nosec(&iocb, sock, msg, size, flags);
>> +	ret = __sock_recvmsg_nosec(&iocb, sock, msg, size, flags, timeop);
>>  	if (-EIOCBQUEUED == ret)
>>  		ret = wait_on_sync_kiocb(&iocb);
>>  	return ret;
>> @@ -851,7 +851,7 @@ int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
>>  	 * iovec are identical, yielding the same in-core layout and alignment
>>  	 */
>>  	msg->msg_iov = (struct iovec *)vec, msg->msg_iovlen = num;
>> -	result = sock_recvmsg(sock, msg, size, flags);
>> +	result = sock_recvmsg(sock, msg, size, flags, NULL);
>>  	set_fs(oldfs);
>>  	return result;
>>  }
>> @@ -914,7 +914,7 @@ static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb,
>>  	msg->msg_iovlen = nr_segs;
>>  	msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
>>  
>> -	return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags);
>> +	return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags, NULL);
>>  }
>>  
>>  static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
>> @@ -1862,7 +1862,7 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
>>  	msg.msg_namelen = 0;
>>  	if (sock->file->f_flags & O_NONBLOCK)
>>  		flags |= MSG_DONTWAIT;
>> -	err = sock_recvmsg(sock, &msg, size, flags);
>> +	err = sock_recvmsg(sock, &msg, size, flags, NULL);
>>  
>>  	if (err >= 0 && addr != NULL) {
>>  		err2 = move_addr_to_user(&address,
>> @@ -2207,7 +2207,7 @@ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
>>  }
>>  
>>  static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
>> -			 struct msghdr *msg_sys, unsigned int flags, int nosec)
>> +			 struct msghdr *msg_sys, unsigned int flags, int nosec, long *timeop)
>>  {
>>  	struct compat_msghdr __user *msg_compat =
>>  	    (struct compat_msghdr __user *)msg;
>> @@ -2265,7 +2265,7 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
>>  	if (sock->file->f_flags & O_NONBLOCK)
>>  		flags |= MSG_DONTWAIT;
>>  	err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys,
>> -							  total_len, flags);
>> +							  total_len, flags, timeop);
>>  	if (err < 0)
>>  		goto out_freeiov;
>>  	len = err;
>> @@ -2312,7 +2312,7 @@ long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags)
>>  	if (!sock)
>>  		goto out;
>>  
>> -	err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0);
>> +	err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0, NULL);
>>  
>>  	fput_light(sock->file, fput_needed);
>>  out:
>> @@ -2327,6 +2327,30 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
>>  	return __sys_recvmsg(fd, msg, flags);
>>  }
>>  
>> +static int sock_set_timeout_ts(long *timeo_p, struct timespec *ts)
>> +{
>> +	if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
>> +		return -EDOM;
>> +
>> +	if (ts->tv_sec < 0) {
>> +		static int warned __read_mostly;
>> +
>> +		*timeo_p = 0;
>> +		if (warned < 10 && net_ratelimit()) {
>> +			warned++;
>> +			pr_info("%s: `%s' (pid %d) tries to set negative timeout\n",
>> +				__func__, current->comm, task_pid_nr(current));
>> +		}
>> +		return 0;
>> +	}
>> +	*timeo_p = MAX_SCHEDULE_TIMEOUT;
>> +	if (ts->tv_sec == 0 && ts->tv_nsec == 0)
>> +		return 0;
>> +	if (ts->tv_sec < (MAX_SCHEDULE_TIMEOUT / HZ - 1))
>> +		*timeo_p = ts->tv_sec * HZ + (ts->tv_nsec + (NSEC_PER_SEC / HZ - 1)) / (NSEC_PER_SEC / HZ);
>> +	return 0;
>> +}
>> +
>>  /*
>>   *     Linux recvmmsg interface
>>   */
>> @@ -2339,12 +2363,14 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
>>  	struct mmsghdr __user *entry;
>>  	struct compat_mmsghdr __user *compat_entry;
>>  	struct msghdr msg_sys;
>> -	struct timespec end_time;
>> +	long timeout_hz, *timeop = NULL;
>>  
>> -	if (timeout &&
>> -	    poll_select_set_timeout(&end_time, timeout->tv_sec,
>> -				    timeout->tv_nsec))
>> -		return -EINVAL;
>> +	if (timeout) {
>> +		err = sock_set_timeout_ts(&timeout_hz, timeout);
>> +		if (err)
>> +			return err;
>> +		timeop = &timeout_hz;
>> +	}
>>  
>>  	datagrams = 0;
>>  
>> @@ -2366,7 +2392,7 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
>>  		if (MSG_CMSG_COMPAT & flags) {
>>  			err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
>>  					     &msg_sys, flags & ~MSG_WAITFORONE,
>> -					     datagrams);
>> +					     datagrams, timeop);
>>  			if (err < 0)
>>  				break;
>>  			err = __put_user(err, &compat_entry->msg_len);
>> @@ -2375,7 +2401,7 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
>>  			err = ___sys_recvmsg(sock,
>>  					     (struct msghdr __user *)entry,
>>  					     &msg_sys, flags & ~MSG_WAITFORONE,
>> -					     datagrams);
>> +					     datagrams, timeop);
>>  			if (err < 0)
>>  				break;
>>  			err = put_user(err, &entry->msg_len);
>> @@ -2390,17 +2416,11 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
>>  		if (flags & MSG_WAITFORONE)
>>  			flags |= MSG_DONTWAIT;
>>  
>> -		if (timeout) {
>> -			ktime_get_ts(timeout);
>> -			*timeout = timespec_sub(end_time, *timeout);
>> -			if (timeout->tv_sec < 0) {
>> -				timeout->tv_sec = timeout->tv_nsec = 0;
>> -				break;
>> -			}
>> -
>> +		if (timeout && timeout_hz == 0) {
>>  			/* Timeout, return less than vlen datagrams */
>> -			if (timeout->tv_nsec == 0 && timeout->tv_sec == 0)
>> -				break;
>> +			timeout->tv_sec = timeout->tv_nsec = 0;
>> +			timeop = NULL;
>> +			break;
>>  		}
>>  
>>  		/* Out of band data, return right away */
>> @@ -2411,6 +2431,11 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
>>  out_put:
>>  	fput_light(sock->file, fput_needed);
>>  
>> +	if (timeop) {
>> +		timeout->tv_sec	 = timeout_hz / HZ;
>> +		timeout->tv_nsec = (timeout_hz % HZ) * (NSEC_PER_SEC / HZ);
>> +	}
>> +
>>  	if (err == 0)
>>  		return datagrams;
>>  
>> diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
>> index b507cd327d9b..92417723f9dc 100644
>> --- a/net/sunrpc/svcsock.c
>> +++ b/net/sunrpc/svcsock.c
>> @@ -551,7 +551,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
>>  	err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
>>  			     0, 0, MSG_PEEK | MSG_DONTWAIT);
>>  	if (err >= 0)
>> -		skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err);
>> +		skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err, NULL);
>>  
>>  	if (skb == NULL) {
>>  		if (err != -EAGAIN) {
>> diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
>> index be8bbd5d65ec..1afb8ece3eb6 100644
>> --- a/net/sunrpc/xprtsock.c
>> +++ b/net/sunrpc/xprtsock.c
>> @@ -965,7 +965,7 @@ static void xs_local_data_ready(struct sock *sk)
>>  	if (xprt == NULL)
>>  		goto out;
>>  
>> -	skb = skb_recv_datagram(sk, 0, 1, &err);
>> +	skb = skb_recv_datagram(sk, 0, 1, &err, NULL);
>>  	if (skb == NULL)
>>  		goto out;
>>  
>> @@ -1027,7 +1027,7 @@ static void xs_udp_data_ready(struct sock *sk)
>>  	if (!(xprt = xprt_from_sock(sk)))
>>  		goto out;
>>  
>> -	if ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL)
>> +	if ((skb = skb_recv_datagram(sk, 0, 1, &err, NULL)) == NULL)
>>  		goto out;
>>  
>>  	repsize = skb->len - sizeof(struct udphdr);
>> diff --git a/net/tipc/socket.c b/net/tipc/socket.c
>> index ef0475568f9e..70699525a102 100644
>> --- a/net/tipc/socket.c
>> +++ b/net/tipc/socket.c
>> @@ -1031,7 +1031,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
>>   * Returns size of returned message data, errno otherwise
>>   */
>>  static int tipc_recvmsg(struct kiocb *iocb, struct socket *sock,
>> -			struct msghdr *m, size_t buf_len, int flags)
>> +			struct msghdr *m, size_t buf_len, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct tipc_sock *tsk = tipc_sk(sk);
>> @@ -1054,7 +1054,7 @@ static int tipc_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  		goto exit;
>>  	}
>>  
>> -	timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
>> +	timeo = sock_rcvtimeop(sk, timeop, flags & MSG_DONTWAIT);
>>  restart:
>>  
>>  	/* Look for a message in receive queue; wait if necessary */
>> @@ -1109,6 +1109,8 @@ restart:
>>  		advance_rx_queue(sk);
>>  	}
>>  exit:
>> +	if (timeop)
>> +		*timeop = timeo;
>>  	release_sock(sk);
>>  	return res;
>>  }
>> @@ -1126,7 +1128,7 @@ exit:
>>   * Returns size of returned message data, errno otherwise
>>   */
>>  static int tipc_recv_stream(struct kiocb *iocb, struct socket *sock,
>> -			    struct msghdr *m, size_t buf_len, int flags)
>> +			    struct msghdr *m, size_t buf_len, int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct tipc_sock *tsk = tipc_sk(sk);
>> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
>> index e96884380732..dcca71ed08c6 100644
>> --- a/net/unix/af_unix.c
>> +++ b/net/unix/af_unix.c
>> @@ -519,17 +519,17 @@ static int unix_shutdown(struct socket *, int);
>>  static int unix_stream_sendmsg(struct kiocb *, struct socket *,
>>  			       struct msghdr *, size_t);
>>  static int unix_stream_recvmsg(struct kiocb *, struct socket *,
>> -			       struct msghdr *, size_t, int);
>> +			       struct msghdr *, size_t, int, long *);
>>  static int unix_dgram_sendmsg(struct kiocb *, struct socket *,
>>  			      struct msghdr *, size_t);
>>  static int unix_dgram_recvmsg(struct kiocb *, struct socket *,
>> -			      struct msghdr *, size_t, int);
>> +			      struct msghdr *, size_t, int, long *);
>>  static int unix_dgram_connect(struct socket *, struct sockaddr *,
>>  			      int, int);
>>  static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *,
>>  				  struct msghdr *, size_t);
>>  static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *,
>> -				  struct msghdr *, size_t, int);
>> +				  struct msghdr *, size_t, int, long *);
>>  
>>  static int unix_set_peek_off(struct sock *sk, int val)
>>  {
>> @@ -1283,7 +1283,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
>>  	 * so that no locks are necessary.
>>  	 */
>>  
>> -	skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err);
>> +	skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err, NULL);
>>  	if (!skb) {
>>  		/* This means receive shutdown. */
>>  		if (err == 0)
>> @@ -1755,14 +1755,14 @@ static int unix_seqpacket_sendmsg(struct kiocb *kiocb, struct socket *sock,
>>  
>>  static int unix_seqpacket_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  			      struct msghdr *msg, size_t size,
>> -			      int flags)
>> +			      int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  
>>  	if (sk->sk_state != TCP_ESTABLISHED)
>>  		return -ENOTCONN;
>>  
>> -	return unix_dgram_recvmsg(iocb, sock, msg, size, flags);
>> +	return unix_dgram_recvmsg(iocb, sock, msg, size, flags, timeop);
>>  }
>>  
>>  static void unix_copy_addr(struct msghdr *msg, struct sock *sk)
>> @@ -1777,7 +1777,7 @@ static void unix_copy_addr(struct msghdr *msg, struct sock *sk)
>>  
>>  static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  			      struct msghdr *msg, size_t size,
>> -			      int flags)
>> +			      int flags, long *timeop)
>>  {
>>  	struct sock_iocb *siocb = kiocb_to_siocb(iocb);
>>  	struct scm_cookie tmp_scm;
>> @@ -1803,7 +1803,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  
>>  	skip = sk_peek_offset(sk, flags);
>>  
>> -	skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err);
>> +	skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err, timeop);
>>  	if (!skb) {
>>  		unix_state_lock(sk);
>>  		/* Signal EOF on disconnected non-blocking SEQPACKET socket. */
>> @@ -1914,7 +1914,7 @@ static unsigned int unix_skb_len(const struct sk_buff *skb)
>>  
>>  static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  			       struct msghdr *msg, size_t size,
>> -			       int flags)
>> +			       int flags, long *timeop)
>>  {
>>  	struct sock_iocb *siocb = kiocb_to_siocb(iocb);
>>  	struct scm_cookie tmp_scm;
>> @@ -1926,7 +1926,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  	int check_creds = 0;
>>  	int target;
>>  	int err = 0;
>> -	long timeo;
>> +	long timeo = sock_rcvtimeop(sk, timeop, noblock);
>>  	int skip;
>>  
>>  	err = -EINVAL;
>> @@ -1938,7 +1938,6 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  		goto out;
>>  
>>  	target = sock_rcvlowat(sk, flags&MSG_WAITALL, size);
>> -	timeo = sock_rcvtimeo(sk, noblock);
>>  
>>  	/* Lock the socket to prevent queue disordering
>>  	 * while sleeps in memcpy_tomsg
>> @@ -2071,6 +2070,8 @@ again:
>>  	mutex_unlock(&u->readlock);
>>  	scm_recv(sock, msg, siocb->scm, flags);
>>  out:
>> +	if (timeop)
>> +		*timeop = timeo;
>>  	return copied ? : err;
>>  }
>>  
>> diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
>> index 85d232bed87d..10568565f57d 100644
>> --- a/net/vmw_vsock/af_vsock.c
>> +++ b/net/vmw_vsock/af_vsock.c
>> @@ -1063,10 +1063,10 @@ out:
>>  }
>>  
>>  static int vsock_dgram_recvmsg(struct kiocb *kiocb, struct socket *sock,
>> -			       struct msghdr *msg, size_t len, int flags)
>> +			       struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	return transport->dgram_dequeue(kiocb, vsock_sk(sock->sk), msg, len,
>> -					flags);
>> +					flags, timeop);
>>  }
>>  
>>  static const struct proto_ops vsock_dgram_ops = {
>> @@ -1646,7 +1646,7 @@ out:
>>  static int
>>  vsock_stream_recvmsg(struct kiocb *kiocb,
>>  		     struct socket *sock,
>> -		     struct msghdr *msg, size_t len, int flags)
>> +		     struct msghdr *msg, size_t len, int flags, long *timeop)
>>  {
>>  	struct sock *sk;
>>  	struct vsock_sock *vsk;
>> @@ -1661,6 +1661,7 @@ vsock_stream_recvmsg(struct kiocb *kiocb,
>>  	sk = sock->sk;
>>  	vsk = vsock_sk(sk);
>>  	err = 0;
>> +	timeout = sock_rcvtimeop(sk, timeop, flags & MSG_DONTWAIT);
>>  
>>  	lock_sock(sk);
>>  
>> @@ -1711,7 +1712,6 @@ vsock_stream_recvmsg(struct kiocb *kiocb,
>>  		err = -ENOMEM;
>>  		goto out;
>>  	}
>> -	timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
>>  	copied = 0;
>>  
>>  	err = transport->notify_recv_init(vsk, target, &recv_data);
>> @@ -1821,6 +1821,8 @@ vsock_stream_recvmsg(struct kiocb *kiocb,
>>  out_wait:
>>  	finish_wait(sk_sleep(sk), &wait);
>>  out:
>> +	if (timeop)
>> +		*timeop = timeout;
>>  	release_sock(sk);
>>  	return err;
>>  }
>> diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
>> index 9bb63ffec4f2..9c9e43c17b34 100644
>> --- a/net/vmw_vsock/vmci_transport.c
>> +++ b/net/vmw_vsock/vmci_transport.c
>> @@ -1733,7 +1733,7 @@ static int vmci_transport_dgram_enqueue(
>>  static int vmci_transport_dgram_dequeue(struct kiocb *kiocb,
>>  					struct vsock_sock *vsk,
>>  					struct msghdr *msg, size_t len,
>> -					int flags)
>> +					int flags, long *timeop)
>>  {
>>  	int err;
>>  	int noblock;
>> @@ -1748,7 +1748,7 @@ static int vmci_transport_dgram_dequeue(struct kiocb *kiocb,
>>  
>>  	/* Retrieve the head sk_buff from the socket's receive queue. */
>>  	err = 0;
>> -	skb = skb_recv_datagram(&vsk->sk, flags, noblock, &err);
>> +	skb = skb_recv_datagram(&vsk->sk, flags, noblock, &err, timeop);
>>  	if (err)
>>  		return err;
>>  
>> diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
>> index 5ad4418ef093..da22c042469a 100644
>> --- a/net/x25/af_x25.c
>> +++ b/net/x25/af_x25.c
>> @@ -1254,7 +1254,7 @@ out_kfree_skb:
>>  
>>  static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  		       struct msghdr *msg, size_t size,
>> -		       int flags)
>> +		       int flags, long *timeop)
>>  {
>>  	struct sock *sk = sock->sk;
>>  	struct x25_sock *x25 = x25_sk(sk);
>> @@ -1306,7 +1306,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
>>  		/* Now we can treat all alike */
>>  		release_sock(sk);
>>  		skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
>> -					flags & MSG_DONTWAIT, &rc);
>> +					flags & MSG_DONTWAIT, &rc, timeop);
>>  		lock_sock(sk);
>>  		if (!skb)
>>  			goto out;
>>
> 
> 


-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ