nfsd4: make recall callback an asynchronous rpc
[safe/jmp/linux-2.6] / fs / nfsd / nfs4callback.c
index 2509305..f4fab69 100644 (file)
@@ -224,7 +224,7 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp)
        WRITE32(OP_CB_RECALL);
        WRITE32(dp->dl_stateid.si_generation);
        WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t));
-       WRITE32(dp->dl_trunc);
+       WRITE32(0); /* truncate optimization not implemented */
        WRITE32(len);
        WRITEMEM(&dp->dl_fh.fh_base, len);
        return 0;
@@ -494,6 +494,49 @@ nfsd4_probe_callback(struct nfs4_client *clp)
        do_probe_callback(clp);
 }
 
+static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_delegation *dp = calldata;
+       struct nfs4_client *clp = dp->dl_client;
+
+       switch (task->tk_status) {
+       case -EIO:
+               /* Network partition? */
+               atomic_set(&clp->cl_cb_conn.cb_set, 0);
+               warn_no_callback_path(clp, task->tk_status);
+       case -EBADHANDLE:
+       case -NFS4ERR_BAD_STATEID:
+               /* Race: client probably got cb_recall
+                * before open reply granting delegation */
+               break;
+       default:
+               /* success, or error we can't handle */
+               return;
+       }
+       if (dp->dl_retries--) {
+               rpc_delay(task, 2*HZ);
+               task->tk_status = 0;
+               rpc_restart_call(task);
+       } else {
+               atomic_set(&clp->cl_cb_conn.cb_set, 0);
+               warn_no_callback_path(clp, task->tk_status);
+       }
+}
+
+static void nfsd4_cb_recall_release(void *calldata)
+{
+       struct nfs4_delegation *dp = calldata;
+       struct nfs4_client *clp = dp->dl_client;
+
+       nfs4_put_delegation(dp);
+       put_nfs4_client(clp);
+}
+
+static const struct rpc_call_ops nfsd4_cb_recall_ops = {
+       .rpc_call_done = nfsd4_cb_recall_done,
+       .rpc_release = nfsd4_cb_recall_release,
+};
+
 /*
  * called with dp->dl_count inc'ed.
  */
@@ -507,34 +550,13 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
                .rpc_argp = dp,
                .rpc_cred = clp->cl_cb_conn.cb_cred
        };
-       int retries = 1;
-       int status = 0;
-
-       dp->dl_trunc = 0; /* XXX need to implement truncate optimization */
-
-       status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
-       while (retries--) {
-               switch (status) {
-                       case -EIO:
-                               /* Network partition? */
-                               atomic_set(&clp->cl_cb_conn.cb_set, 0);
-                       case -EBADHANDLE:
-                       case -NFS4ERR_BAD_STATEID:
-                               /* Race: client probably got cb_recall
-                                * before open reply granting delegation */
-                               break;
-                       default:
-                               goto out_put_cred;
-               }
-               ssleep(2);
-               status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
+       int status;
+
+       dp->dl_retries = 1;
+       status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT,
+                               &nfsd4_cb_recall_ops, dp);
+       if (status) {
+               put_nfs4_client(clp);
+               nfs4_put_delegation(dp);
        }
-out_put_cred:
-       /*
-        * Success or failure, now we're either waiting for lease expiration
-        * or deleg_return.
-        */
-       put_nfs4_client(clp);
-       nfs4_put_delegation(dp);
-       return;
 }