These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / sunrpc / clnt.c
index e6ce151..23608eb 100644 (file)
@@ -891,15 +891,8 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
                        task->tk_flags |= RPC_TASK_SOFT;
                if (clnt->cl_noretranstimeo)
                        task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT;
-               if (sk_memalloc_socks()) {
-                       struct rpc_xprt *xprt;
-
-                       rcu_read_lock();
-                       xprt = rcu_dereference(clnt->cl_xprt);
-                       if (xprt->swapper)
-                               task->tk_flags |= RPC_TASK_SWAPPER;
-                       rcu_read_unlock();
-               }
+               if (atomic_read(&clnt->cl_swapper))
+                       task->tk_flags |= RPC_TASK_SWAPPER;
                /* Add to the client's list of all tasks */
                spin_lock(&clnt->cl_lock);
                list_add_tail(&task->tk_task, &clnt->cl_tasks);
@@ -1031,15 +1024,14 @@ EXPORT_SYMBOL_GPL(rpc_call_async);
  * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run
  * rpc_execute against it
  * @req: RPC request
- * @tk_ops: RPC call ops
  */
-struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req,
-                               const struct rpc_call_ops *tk_ops)
+struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req)
 {
        struct rpc_task *task;
        struct xdr_buf *xbufp = &req->rq_snd_buf;
        struct rpc_task_setup task_setup_data = {
-               .callback_ops = tk_ops,
+               .callback_ops = &rpc_default_ops,
+               .flags = RPC_TASK_SOFTCONN,
        };
 
        dprintk("RPC: rpc_run_bc_task req= %p\n", req);
@@ -1614,6 +1606,7 @@ call_allocate(struct rpc_task *task)
                                        req->rq_callsize + req->rq_rcvsize);
        if (req->rq_buffer != NULL)
                return;
+       xprt_inject_disconnect(xprt);
 
        dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid);
 
@@ -1909,6 +1902,7 @@ call_transmit_status(struct rpc_task *task)
 
        switch (task->tk_status) {
        case -EAGAIN:
+       case -ENOBUFS:
                break;
        default:
                dprint_status(task);
@@ -1935,7 +1929,6 @@ call_transmit_status(struct rpc_task *task)
        case -ECONNABORTED:
        case -EADDRINUSE:
        case -ENOTCONN:
-       case -ENOBUFS:
        case -EPIPE:
                rpc_task_force_reencode(task);
        }
@@ -1951,33 +1944,36 @@ call_bc_transmit(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
 
-       if (!xprt_prepare_transmit(task)) {
-               /*
-                * Could not reserve the transport. Try again after the
-                * transport is released.
-                */
-               task->tk_status = 0;
-               task->tk_action = call_bc_transmit;
-               return;
-       }
+       if (!xprt_prepare_transmit(task))
+               goto out_retry;
 
-       task->tk_action = rpc_exit_task;
        if (task->tk_status < 0) {
                printk(KERN_NOTICE "RPC: Could not send backchannel reply "
                        "error: %d\n", task->tk_status);
-               return;
+               goto out_done;
        }
+       if (req->rq_connect_cookie != req->rq_xprt->connect_cookie)
+               req->rq_bytes_sent = 0;
 
        xprt_transmit(task);
+
+       if (task->tk_status == -EAGAIN)
+               goto out_nospace;
+
        xprt_end_transmit(task);
        dprint_status(task);
        switch (task->tk_status) {
        case 0:
                /* Success */
-               break;
        case -EHOSTDOWN:
        case -EHOSTUNREACH:
        case -ENETUNREACH:
+       case -ECONNRESET:
+       case -ECONNREFUSED:
+       case -EADDRINUSE:
+       case -ENOTCONN:
+       case -EPIPE:
+               break;
        case -ETIMEDOUT:
                /*
                 * Problem reaching the server.  Disconnect and let the
@@ -2002,6 +1998,13 @@ call_bc_transmit(struct rpc_task *task)
                break;
        }
        rpc_wake_up_queued_task(&req->rq_xprt->pending, task);
+out_done:
+       task->tk_action = rpc_exit_task;
+       return;
+out_nospace:
+       req->rq_connect_cookie = req->rq_xprt->connect_cookie;
+out_retry:
+       task->tk_status = 0;
 }
 #endif /* CONFIG_SUNRPC_BACKCHANNEL */
 
@@ -2054,12 +2057,13 @@ call_status(struct rpc_task *task)
        case -ECONNABORTED:
                rpc_force_rebind(clnt);
        case -EADDRINUSE:
-       case -ENOBUFS:
                rpc_delay(task, 3*HZ);
        case -EPIPE:
        case -ENOTCONN:
                task->tk_action = call_bind;
                break;
+       case -ENOBUFS:
+               rpc_delay(task, HZ>>2);
        case -EAGAIN:
                task->tk_action = call_transmit;
                break;
@@ -2476,3 +2480,59 @@ void rpc_show_tasks(struct net *net)
        spin_unlock(&sn->rpc_client_lock);
 }
 #endif
+
+#if IS_ENABLED(CONFIG_SUNRPC_SWAP)
+int
+rpc_clnt_swap_activate(struct rpc_clnt *clnt)
+{
+       int ret = 0;
+       struct rpc_xprt *xprt;
+
+       if (atomic_inc_return(&clnt->cl_swapper) == 1) {
+retry:
+               rcu_read_lock();
+               xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
+               rcu_read_unlock();
+               if (!xprt) {
+                       /*
+                        * If we didn't get a reference, then we likely are
+                        * racing with a migration event. Wait for a grace
+                        * period and try again.
+                        */
+                       synchronize_rcu();
+                       goto retry;
+               }
+
+               ret = xprt_enable_swap(xprt);
+               xprt_put(xprt);
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(rpc_clnt_swap_activate);
+
+void
+rpc_clnt_swap_deactivate(struct rpc_clnt *clnt)
+{
+       struct rpc_xprt *xprt;
+
+       if (atomic_dec_if_positive(&clnt->cl_swapper) == 0) {
+retry:
+               rcu_read_lock();
+               xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
+               rcu_read_unlock();
+               if (!xprt) {
+                       /*
+                        * If we didn't get a reference, then we likely are
+                        * racing with a migration event. Wait for a grace
+                        * period and try again.
+                        */
+                       synchronize_rcu();
+                       goto retry;
+               }
+
+               xprt_disable_swap(xprt);
+               xprt_put(xprt);
+       }
+}
+EXPORT_SYMBOL_GPL(rpc_clnt_swap_deactivate);
+#endif /* CONFIG_SUNRPC_SWAP */