Merge branch 'bugfixes' into linux-next
[firefly-linux-kernel-4.4.55.git] / net / sunrpc / clnt.c
index d7a369e61085119f2897aea276ab28fc8dc12fb5..d259fa9669270506c32b941542baccec55b3d061 100644 (file)
@@ -304,10 +304,8 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
        err = rpciod_up();
        if (err)
                goto out_no_rpciod;
-       err = -EINVAL;
-       if (!xprt)
-               goto out_no_xprt;
 
+       err = -EINVAL;
        if (args->version >= program->nrvers)
                goto out_err;
        version = program->version[args->version];
@@ -382,10 +380,9 @@ out_no_principal:
 out_no_stats:
        kfree(clnt);
 out_err:
-       xprt_put(xprt);
-out_no_xprt:
        rpciod_down();
 out_no_rpciod:
+       xprt_put(xprt);
        return ERR_PTR(err);
 }
 
@@ -414,6 +411,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
        };
        char servername[48];
 
+       if (args->flags & RPC_CLNT_CREATE_INFINITE_SLOTS)
+               xprtargs.flags |= XPRT_CREATE_INFINITE_SLOTS;
        /*
         * If the caller chooses not to specify a hostname, whip
         * up a string representation of the passed-in address.
@@ -512,7 +511,7 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
        new = rpc_new_client(args, xprt);
        if (IS_ERR(new)) {
                err = PTR_ERR(new);
-               goto out_put;
+               goto out_err;
        }
 
        atomic_inc(&clnt->cl_count);
@@ -525,8 +524,6 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
        new->cl_chatty = clnt->cl_chatty;
        return new;
 
-out_put:
-       xprt_put(xprt);
 out_err:
        dprintk("RPC:       %s: returned error %d\n", __func__, err);
        return ERR_PTR(err);
@@ -1196,6 +1193,21 @@ size_t rpc_max_payload(struct rpc_clnt *clnt)
 }
 EXPORT_SYMBOL_GPL(rpc_max_payload);
 
+/**
+ * rpc_get_timeout - Get timeout for transport in units of HZ
+ * @clnt: RPC client to query
+ */
+unsigned long rpc_get_timeout(struct rpc_clnt *clnt)
+{
+       unsigned long ret;
+
+       rcu_read_lock();
+       ret = rcu_dereference(clnt->cl_xprt)->timeout->to_initval;
+       rcu_read_unlock();
+       return ret;
+}
+EXPORT_SYMBOL_GPL(rpc_get_timeout);
+
 /**
  * rpc_force_rebind - force transport to check that remote port is unchanged
  * @clnt: client to rebind
@@ -1291,6 +1303,8 @@ call_reserve(struct rpc_task *task)
        xprt_reserve(task);
 }
 
+static void call_retry_reserve(struct rpc_task *task);
+
 /*
  * 1b. Grok the result of xprt_reserve()
  */
@@ -1332,7 +1346,7 @@ call_reserveresult(struct rpc_task *task)
        case -ENOMEM:
                rpc_delay(task, HZ >> 2);
        case -EAGAIN:   /* woken up; retry */
-               task->tk_action = call_reserve;
+               task->tk_action = call_retry_reserve;
                return;
        case -EIO:      /* probably a shutdown */
                break;
@@ -1344,6 +1358,19 @@ call_reserveresult(struct rpc_task *task)
        rpc_exit(task, status);
 }
 
+/*
+ * 1c. Retry reserving an RPC call slot
+ */
+static void
+call_retry_reserve(struct rpc_task *task)
+{
+       dprint_status(task);
+
+       task->tk_status  = 0;
+       task->tk_action  = call_reserveresult;
+       xprt_retry_reserve(task);
+}
+
 /*
  * 2.  Bind and/or refresh the credentials
  */
@@ -1629,22 +1656,26 @@ call_connect_status(struct rpc_task *task)
 
        dprint_status(task);
 
-       task->tk_status = 0;
-       if (status >= 0 || status == -EAGAIN) {
-               clnt->cl_stats->netreconn++;
-               task->tk_action = call_transmit;
-               return;
-       }
-
        trace_rpc_connect_status(task, status);
        switch (status) {
                /* if soft mounted, test if we've timed out */
        case -ETIMEDOUT:
                task->tk_action = call_timeout;
-               break;
-       default:
-               rpc_exit(task, -EIO);
+               return;
+       case -ECONNREFUSED:
+       case -ECONNRESET:
+       case -ENETUNREACH:
+               if (RPC_IS_SOFTCONN(task))
+                       break;
+               /* retry with existing socket, after a delay */
+       case 0:
+       case -EAGAIN:
+               task->tk_status = 0;
+               clnt->cl_stats->netreconn++;
+               task->tk_action = call_transmit;
+               return;
        }
+       rpc_exit(task, status);
 }
 
 /*