NFSv4: Make open_confirm() asynchronous too
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 3 Jan 2006 08:55:12 +0000 (09:55 +0100)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 6 Jan 2006 19:58:42 +0000 (14:58 -0500)
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c
include/linux/nfs_xdr.h

index aed8701c1a3641d95a7b0ae7bdfe30c34688ae41..8154f257946957243001f8f5470656297736f27b 100644 (file)
@@ -57,7 +57,8 @@
 #define NFS4_POLL_RETRY_MIN    (1*HZ)
 #define NFS4_POLL_RETRY_MAX    (15*HZ)
 
-static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid);
+struct nfs4_opendata;
+static int _nfs4_proc_open_confirm(struct nfs4_opendata *data);
 static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
 static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *);
 static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
@@ -198,6 +199,8 @@ struct nfs4_opendata {
        atomic_t count;
        struct nfs_openargs o_arg;
        struct nfs_openres o_res;
+       struct nfs_open_confirmargs c_arg;
+       struct nfs_open_confirmres c_res;
        struct nfs_fattr f_attr;
        struct nfs_fattr dir_attr;
        struct dentry *dentry;
@@ -249,6 +252,9 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
                p->o_arg.u.attrs = &p->attrs;
                memcpy(&p->attrs, attrs, sizeof(p->attrs));
        }
+       p->c_arg.fh = &p->o_res.fh;
+       p->c_arg.stateid = &p->o_res.stateid;
+       p->c_arg.seqid = p->o_arg.seqid;
        return p;
 err_free:
        kfree(p);
@@ -433,8 +439,7 @@ static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state
        if (status != 0)
                goto out_free;
        if(opendata->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) {
-               status = _nfs4_proc_open_confirm(server->client, NFS_FH(inode),
-                               sp, &opendata->o_res.stateid, opendata->o_arg.seqid);
+               status = _nfs4_proc_open_confirm(opendata);
                if (status != 0)
                        goto out_free;
        }
@@ -472,28 +477,79 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
        return err;
 }
 
-static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid)
+static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata)
 {
-       struct nfs_open_confirmargs arg = {
-               .fh             = fh,
-               .seqid          = seqid,
-               .stateid        = *stateid,
-       };
-       struct nfs_open_confirmres res;
-       struct  rpc_message msg = {
-               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM],
-               .rpc_argp       = &arg,
-               .rpc_resp       = &res,
-               .rpc_cred       = sp->so_cred,
+       struct nfs4_opendata *data = calldata;
+       struct  rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM],
+               .rpc_argp = &data->c_arg,
+               .rpc_resp = &data->c_res,
+               .rpc_cred = data->owner->so_cred,
        };
+       rpc_call_setup(task, &msg, 0);
+}
+
+static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_opendata *data = calldata;
+
+       data->rpc_status = task->tk_status;
+       if (RPC_ASSASSINATED(task))
+               return;
+       if (data->rpc_status == 0)
+               memcpy(data->o_res.stateid.data, data->c_res.stateid.data,
+                               sizeof(data->o_res.stateid.data));
+       nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid);
+       nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status);
+}
+
+static void nfs4_open_confirm_release(void *calldata)
+{
+       struct nfs4_opendata *data = calldata;
+       struct nfs4_state *state = NULL;
+
+       /* If this request hasn't been cancelled, do nothing */
+       if (data->cancelled == 0)
+               goto out_free;
+       /* In case of error, no cleanup! */
+       if (data->rpc_status != 0)
+               goto out_free;
+       nfs_confirm_seqid(&data->owner->so_seqid, 0);
+       state = nfs4_opendata_to_nfs4_state(data);
+       if (state != NULL)
+               nfs4_close_state(state, data->o_arg.open_flags);
+out_free:
+       nfs4_opendata_free(data);
+}
+
+static const struct rpc_call_ops nfs4_open_confirm_ops = {
+       .rpc_call_prepare = nfs4_open_confirm_prepare,
+       .rpc_call_done = nfs4_open_confirm_done,
+       .rpc_release = nfs4_open_confirm_release,
+};
+
+/*
+ * Note: On error, nfs4_proc_open_confirm will free the struct nfs4_opendata
+ */
+static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
+{
+       struct nfs_server *server = NFS_SERVER(data->dir->d_inode);
+       struct rpc_task *task;
        int status;
 
-       status = rpc_call_sync(clnt, &msg, RPC_TASK_NOINTR);
-       /* Confirm the sequence as being established */
-       nfs_confirm_seqid(&sp->so_seqid, status);
-       nfs_increment_open_seqid(status, seqid);
-       if (status >= 0)
-               memcpy(stateid, &res.stateid, sizeof(*stateid));
+       atomic_inc(&data->count);
+       task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data);
+       if (IS_ERR(task)) {
+               nfs4_opendata_free(data);
+               return PTR_ERR(task);
+       }
+       status = nfs4_wait_for_completion_rpc_task(task);
+       if (status != 0) {
+               data->cancelled = 1;
+               smp_wmb();
+       } else
+               status = data->rpc_status;
+       rpc_release_task(task);
        return status;
 }
 
@@ -602,8 +658,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
        } else
                nfs_refresh_inode(dir, o_res->dir_attr);
        if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
-               status = _nfs4_proc_open_confirm(server->client, &o_res->fh,
-                               data->owner, &o_res->stateid, o_arg->seqid);
+               status = _nfs4_proc_open_confirm(data);
                if (status != 0)
                        return status;
        }
index db2bcf722f918b1cb03914e26172215369c33977..2ba9906f2a51f158dd063d0323083ea75ea87bba 100644 (file)
@@ -964,9 +964,9 @@ static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_con
 {
        uint32_t *p;
 
-       RESERVE_SPACE(8+sizeof(arg->stateid.data));
+       RESERVE_SPACE(8+sizeof(arg->stateid->data));
        WRITE32(OP_OPEN_CONFIRM);
-       WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data));
+       WRITEMEM(arg->stateid->data, sizeof(arg->stateid->data));
        WRITE32(arg->seqid->sequence->counter);
 
        return 0;
@@ -1535,9 +1535,6 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct n
        };
        int status;
 
-       status = nfs_wait_on_sequence(args->seqid, req->rq_task);
-       if (status != 0)
-               goto out;
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
        encode_compound_hdr(&xdr, &hdr);
        status = encode_putfh(&xdr, args->fh);
index 40718669b9c896e45939e6490f38d843d67623ea..518cfa5cd024617ee75672b590edfd47a1d49757 100644 (file)
@@ -137,7 +137,7 @@ struct nfs_openres {
  */
 struct nfs_open_confirmargs {
        const struct nfs_fh *   fh;
-       nfs4_stateid            stateid;
+       nfs4_stateid *          stateid;
        struct nfs_seqid *      seqid;
 };