]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/sunrpc/xprtsock.c
Merge remote-tracking branch 'remotes/stable/linux-4.4.y' into karo-tx6-mainline
[karo-tx-linux.git] / net / sunrpc / xprtsock.c
index 2ffaf6a794994ae20247fda57a6dd4c4bee64b0d..027c9ef8a263fa63042afd1156dc8b1f59c2bc64 100644 (file)
@@ -398,7 +398,6 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen,
        if (unlikely(!sock))
                return -ENOTSOCK;
 
-       clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags);
        if (base != 0) {
                addr = NULL;
                addrlen = 0;
@@ -442,7 +441,6 @@ static void xs_nospace_callback(struct rpc_task *task)
        struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt);
 
        transport->inet->sk_write_pending--;
-       clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
 }
 
 /**
@@ -467,20 +465,11 @@ static int xs_nospace(struct rpc_task *task)
 
        /* Don't race with disconnect */
        if (xprt_connected(xprt)) {
-               if (test_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags)) {
-                       /*
-                        * Notify TCP that we're limited by the application
-                        * window size
-                        */
-                       set_bit(SOCK_NOSPACE, &transport->sock->flags);
-                       sk->sk_write_pending++;
-                       /* ...and wait for more buffer space */
-                       xprt_wait_for_buffer_space(task, xs_nospace_callback);
-               }
-       } else {
-               clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
+               /* wait for more buffer space */
+               sk->sk_write_pending++;
+               xprt_wait_for_buffer_space(task, xs_nospace_callback);
+       } else
                ret = -ENOTCONN;
-       }
 
        spin_unlock_bh(&xprt->transport_lock);
 
@@ -616,9 +605,6 @@ process_status:
        case -EAGAIN:
                status = xs_nospace(task);
                break;
-       default:
-               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
-                       -status);
        case -ENETUNREACH:
        case -ENOBUFS:
        case -EPIPE:
@@ -626,7 +612,10 @@ process_status:
        case -EPERM:
                /* When the server has died, an ICMP port unreachable message
                 * prompts ECONNREFUSED. */
-               clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
+               break;
+       default:
+               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
+                       -status);
        }
 
        return status;
@@ -706,16 +695,16 @@ static int xs_tcp_send_request(struct rpc_task *task)
        case -EAGAIN:
                status = xs_nospace(task);
                break;
-       default:
-               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
-                       -status);
        case -ECONNRESET:
        case -ECONNREFUSED:
        case -ENOTCONN:
        case -EADDRINUSE:
        case -ENOBUFS:
        case -EPIPE:
-               clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
+               break;
+       default:
+               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
+                       -status);
        }
 
        return status;
@@ -1609,19 +1598,23 @@ static void xs_tcp_state_change(struct sock *sk)
 
 static void xs_write_space(struct sock *sk)
 {
-       struct socket *sock;
+       struct socket_wq *wq;
        struct rpc_xprt *xprt;
 
-       if (unlikely(!(sock = sk->sk_socket)))
+       if (!sk->sk_socket)
                return;
-       clear_bit(SOCK_NOSPACE, &sock->flags);
+       clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
 
        if (unlikely(!(xprt = xprt_from_sock(sk))))
                return;
-       if (test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags) == 0)
-               return;
+       rcu_read_lock();
+       wq = rcu_dereference(sk->sk_wq);
+       if (!wq || test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags) == 0)
+               goto out;
 
        xprt_write_space(xprt);
+out:
+       rcu_read_unlock();
 }
 
 /**