]> err.no Git - linux-2.6/blobdiff - net/sunrpc/clnt.c
SUNRPC: rpc_execute should not return task->tk_status;
[linux-2.6] / net / sunrpc / clnt.c
index 702ede309b067260130321a32f8e8c1779b529bf..f025b7e72353f38879a9dadec4e960c377ed9699 100644 (file)
@@ -55,6 +55,7 @@ static void   call_bind(struct rpc_task *task);
 static void    call_bind_status(struct rpc_task *task);
 static void    call_transmit(struct rpc_task *task);
 static void    call_status(struct rpc_task *task);
+static void    call_transmit_status(struct rpc_task *task);
 static void    call_refresh(struct rpc_task *task);
 static void    call_refreshresult(struct rpc_task *task);
 static void    call_timeout(struct rpc_task *task);
@@ -373,10 +374,14 @@ out:
  * Default callback for async RPC calls
  */
 static void
-rpc_default_callback(struct rpc_task *task)
+rpc_default_callback(struct rpc_task *task, void *data)
 {
 }
 
+static const struct rpc_call_ops rpc_default_ops = {
+       .rpc_call_done = rpc_default_callback,
+};
+
 /*
  *     Export the signal mask handling for synchronous code that
  *     sleeps on RPC calls
@@ -431,7 +436,7 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
        BUG_ON(flags & RPC_TASK_ASYNC);
 
        status = -ENOMEM;
-       task = rpc_new_task(clnt, NULL, flags);
+       task = rpc_new_task(clnt, flags, &rpc_default_ops, NULL);
        if (task == NULL)
                goto out;
 
@@ -441,14 +446,15 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
        rpc_call_setup(task, msg, 0);
 
        /* Set up the call info struct and execute the task */
-       if (task->tk_status == 0) {
+       status = task->tk_status;
+       if (status == 0) {
+               atomic_inc(&task->tk_count);
                status = rpc_execute(task);
-       } else {
-               status = task->tk_status;
-               rpc_release_task(task);
+               if (status == 0)
+                       status = task->tk_status;
        }
-
        rpc_restore_sigmask(&oldset);
+       rpc_release_task(task);
 out:
        return status;
 }
@@ -458,7 +464,7 @@ out:
  */
 int
 rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
-              rpc_action callback, void *data)
+              const struct rpc_call_ops *tk_ops, void *data)
 {
        struct rpc_task *task;
        sigset_t        oldset;
@@ -471,12 +477,9 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
        flags |= RPC_TASK_ASYNC;
 
        /* Create/initialize a new RPC task */
-       if (!callback)
-               callback = rpc_default_callback;
        status = -ENOMEM;
-       if (!(task = rpc_new_task(clnt, callback, flags)))
+       if (!(task = rpc_new_task(clnt, flags, tk_ops, data)))
                goto out;
-       task->tk_calldata = data;
 
        /* Mask signals on GSS_AUTH upcalls */
        rpc_task_sigmask(task, &oldset);                
@@ -510,7 +513,7 @@ rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags)
        if (task->tk_status == 0)
                task->tk_action = call_start;
        else
-               task->tk_action = NULL;
+               task->tk_action = rpc_exit_task;
 }
 
 void
@@ -672,6 +675,18 @@ call_allocate(struct rpc_task *task)
        rpc_exit(task, -ERESTARTSYS);
 }
 
+static inline int
+rpc_task_need_encode(struct rpc_task *task)
+{
+       return task->tk_rqstp->rq_snd_buf.len == 0;
+}
+
+static inline void
+rpc_task_force_reencode(struct rpc_task *task)
+{
+       task->tk_rqstp->rq_snd_buf.len = 0;
+}
+
 /*
  * 3.  Encode arguments of an RPC call
  */
@@ -867,23 +882,26 @@ call_transmit(struct rpc_task *task)
        if (task->tk_status != 0)
                return;
        /* Encode here so that rpcsec_gss can use correct sequence number. */
-       if (task->tk_rqstp->rq_bytes_sent == 0) {
+       if (rpc_task_need_encode(task)) {
+               task->tk_rqstp->rq_bytes_sent = 0;
                call_encode(task);
                /* Did the encode result in an error condition? */
                if (task->tk_status != 0)
                        goto out_nosend;
        }
+       task->tk_action = call_transmit_status;
        xprt_transmit(task);
        if (task->tk_status < 0)
                return;
        if (!task->tk_msg.rpc_proc->p_decode) {
-               task->tk_action = NULL;
+               task->tk_action = rpc_exit_task;
                rpc_wake_up_task(task);
        }
        return;
 out_nosend:
        /* release socket write lock before attempting to handle error */
        xprt_abort_transmit(task);
+       rpc_task_force_reencode(task);
 }
 
 /*
@@ -915,7 +933,6 @@ call_status(struct rpc_task *task)
                break;
        case -ECONNREFUSED:
        case -ENOTCONN:
-               req->rq_bytes_sent = 0;
                if (clnt->cl_autobind)
                        clnt->cl_port = 0;
                task->tk_action = call_bind;
@@ -937,7 +954,18 @@ call_status(struct rpc_task *task)
 }
 
 /*
- * 6a. Handle RPC timeout
+ * 6a. Handle transmission errors.
+ */
+static void
+call_transmit_status(struct rpc_task *task)
+{
+       if (task->tk_status != -EAGAIN)
+               rpc_task_force_reencode(task);
+       call_status(task);
+}
+
+/*
+ * 6b. Handle RPC timeout
  *     We do not release the request slot, so we keep using the
  *     same XID for all retransmits.
  */
@@ -1013,13 +1041,14 @@ call_decode(struct rpc_task *task)
                                sizeof(req->rq_rcv_buf)) != 0);
 
        /* Verify the RPC header */
-       if (!(p = call_verify(task))) {
-               if (task->tk_action == NULL)
-                       return;
-               goto out_retry;
+       p = call_verify(task);
+       if (IS_ERR(p)) {
+               if (p == ERR_PTR(-EAGAIN))
+                       goto out_retry;
+               return;
        }
 
-       task->tk_action = NULL;
+       task->tk_action = rpc_exit_task;
 
        if (decode)
                task->tk_status = rpcauth_unwrap_resp(task, decode, req, p,
@@ -1112,7 +1141,7 @@ call_verify(struct rpc_task *task)
 
        if ((n = ntohl(*p++)) != RPC_REPLY) {
                printk(KERN_WARNING "call_verify: not an RPC reply: %x\n", n);
-               goto out_retry;
+               goto out_garbage;
        }
        if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
                if (--len < 0)
@@ -1142,7 +1171,7 @@ call_verify(struct rpc_task *task)
                                                        task->tk_pid);
                        rpcauth_invalcred(task);
                        task->tk_action = call_refresh;
-                       return NULL;
+                       goto out_retry;
                case RPC_AUTH_BADCRED:
                case RPC_AUTH_BADVERF:
                        /* possibly garbled cred/verf? */
@@ -1152,7 +1181,7 @@ call_verify(struct rpc_task *task)
                        dprintk("RPC: %4d call_verify: retry garbled creds\n",
                                                        task->tk_pid);
                        task->tk_action = call_bind;
-                       return NULL;
+                       goto out_retry;
                case RPC_AUTH_TOOWEAK:
                        printk(KERN_NOTICE "call_verify: server requires stronger "
                               "authentication.\n");
@@ -1167,7 +1196,7 @@ call_verify(struct rpc_task *task)
        }
        if (!(p = rpcauth_checkverf(task, p))) {
                printk(KERN_WARNING "call_verify: auth check failed\n");
-               goto out_retry;         /* bad verifier, retry */
+               goto out_garbage;               /* bad verifier, retry */
        }
        len = p - (u32 *)iov->iov_base - 1;
        if (len < 0)
@@ -1204,23 +1233,24 @@ call_verify(struct rpc_task *task)
                /* Also retry */
        }
 
-out_retry:
+out_garbage:
        task->tk_client->cl_stats->rpcgarbage++;
        if (task->tk_garb_retry) {
                task->tk_garb_retry--;
                dprintk("RPC %s: retrying %4d\n", __FUNCTION__, task->tk_pid);
                task->tk_action = call_bind;
-               return NULL;
+out_retry:
+               return ERR_PTR(-EAGAIN);
        }
        printk(KERN_WARNING "RPC %s: retry failed, exit EIO\n", __FUNCTION__);
 out_eio:
        error = -EIO;
 out_err:
        rpc_exit(task, error);
-       return NULL;
+       return ERR_PTR(error);
 out_overflow:
        printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__);
-       goto out_retry;
+       goto out_garbage;
 }
 
 static int rpcproc_encode_null(void *rqstp, u32 *data, void *obj)