diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-01-03 03:55:12 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-01-06 14:58:42 -0500 |
commit | cdd4e68b5f0ed12c64b3e2be83655d2a47588a74 (patch) | |
tree | c31565c36e0550655207d2edcabaa6ea1f3217f7 /fs/nfs/nfs4proc.c | |
parent | 24ac23ab88df5b21b5b2df8cde748bf99b289099 (diff) |
NFSv4: Make open_confirm() asynchronous too
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 101 |
1 files changed, 78 insertions, 23 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index aed8701c1a36..8154f2579469 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -57,7 +57,8 @@ | |||
57 | #define NFS4_POLL_RETRY_MIN (1*HZ) | 57 | #define NFS4_POLL_RETRY_MIN (1*HZ) |
58 | #define NFS4_POLL_RETRY_MAX (15*HZ) | 58 | #define NFS4_POLL_RETRY_MAX (15*HZ) |
59 | 59 | ||
60 | 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); | 60 | struct nfs4_opendata; |
61 | static int _nfs4_proc_open_confirm(struct nfs4_opendata *data); | ||
61 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 62 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
62 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); | 63 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); |
63 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); | 64 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); |
@@ -198,6 +199,8 @@ struct nfs4_opendata { | |||
198 | atomic_t count; | 199 | atomic_t count; |
199 | struct nfs_openargs o_arg; | 200 | struct nfs_openargs o_arg; |
200 | struct nfs_openres o_res; | 201 | struct nfs_openres o_res; |
202 | struct nfs_open_confirmargs c_arg; | ||
203 | struct nfs_open_confirmres c_res; | ||
201 | struct nfs_fattr f_attr; | 204 | struct nfs_fattr f_attr; |
202 | struct nfs_fattr dir_attr; | 205 | struct nfs_fattr dir_attr; |
203 | struct dentry *dentry; | 206 | struct dentry *dentry; |
@@ -249,6 +252,9 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
249 | p->o_arg.u.attrs = &p->attrs; | 252 | p->o_arg.u.attrs = &p->attrs; |
250 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | 253 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); |
251 | } | 254 | } |
255 | p->c_arg.fh = &p->o_res.fh; | ||
256 | p->c_arg.stateid = &p->o_res.stateid; | ||
257 | p->c_arg.seqid = p->o_arg.seqid; | ||
252 | return p; | 258 | return p; |
253 | err_free: | 259 | err_free: |
254 | kfree(p); | 260 | kfree(p); |
@@ -433,8 +439,7 @@ static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state | |||
433 | if (status != 0) | 439 | if (status != 0) |
434 | goto out_free; | 440 | goto out_free; |
435 | if(opendata->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) { | 441 | if(opendata->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) { |
436 | status = _nfs4_proc_open_confirm(server->client, NFS_FH(inode), | 442 | status = _nfs4_proc_open_confirm(opendata); |
437 | sp, &opendata->o_res.stateid, opendata->o_arg.seqid); | ||
438 | if (status != 0) | 443 | if (status != 0) |
439 | goto out_free; | 444 | goto out_free; |
440 | } | 445 | } |
@@ -472,28 +477,79 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | |||
472 | return err; | 477 | return err; |
473 | } | 478 | } |
474 | 479 | ||
475 | 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) | 480 | static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata) |
476 | { | 481 | { |
477 | struct nfs_open_confirmargs arg = { | 482 | struct nfs4_opendata *data = calldata; |
478 | .fh = fh, | 483 | struct rpc_message msg = { |
479 | .seqid = seqid, | 484 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], |
480 | .stateid = *stateid, | 485 | .rpc_argp = &data->c_arg, |
481 | }; | 486 | .rpc_resp = &data->c_res, |
482 | struct nfs_open_confirmres res; | 487 | .rpc_cred = data->owner->so_cred, |
483 | struct rpc_message msg = { | ||
484 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], | ||
485 | .rpc_argp = &arg, | ||
486 | .rpc_resp = &res, | ||
487 | .rpc_cred = sp->so_cred, | ||
488 | }; | 488 | }; |
489 | rpc_call_setup(task, &msg, 0); | ||
490 | } | ||
491 | |||
492 | static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | ||
493 | { | ||
494 | struct nfs4_opendata *data = calldata; | ||
495 | |||
496 | data->rpc_status = task->tk_status; | ||
497 | if (RPC_ASSASSINATED(task)) | ||
498 | return; | ||
499 | if (data->rpc_status == 0) | ||
500 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, | ||
501 | sizeof(data->o_res.stateid.data)); | ||
502 | nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); | ||
503 | nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status); | ||
504 | } | ||
505 | |||
506 | static void nfs4_open_confirm_release(void *calldata) | ||
507 | { | ||
508 | struct nfs4_opendata *data = calldata; | ||
509 | struct nfs4_state *state = NULL; | ||
510 | |||
511 | /* If this request hasn't been cancelled, do nothing */ | ||
512 | if (data->cancelled == 0) | ||
513 | goto out_free; | ||
514 | /* In case of error, no cleanup! */ | ||
515 | if (data->rpc_status != 0) | ||
516 | goto out_free; | ||
517 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | ||
518 | state = nfs4_opendata_to_nfs4_state(data); | ||
519 | if (state != NULL) | ||
520 | nfs4_close_state(state, data->o_arg.open_flags); | ||
521 | out_free: | ||
522 | nfs4_opendata_free(data); | ||
523 | } | ||
524 | |||
525 | static const struct rpc_call_ops nfs4_open_confirm_ops = { | ||
526 | .rpc_call_prepare = nfs4_open_confirm_prepare, | ||
527 | .rpc_call_done = nfs4_open_confirm_done, | ||
528 | .rpc_release = nfs4_open_confirm_release, | ||
529 | }; | ||
530 | |||
531 | /* | ||
532 | * Note: On error, nfs4_proc_open_confirm will free the struct nfs4_opendata | ||
533 | */ | ||
534 | static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | ||
535 | { | ||
536 | struct nfs_server *server = NFS_SERVER(data->dir->d_inode); | ||
537 | struct rpc_task *task; | ||
489 | int status; | 538 | int status; |
490 | 539 | ||
491 | status = rpc_call_sync(clnt, &msg, RPC_TASK_NOINTR); | 540 | atomic_inc(&data->count); |
492 | /* Confirm the sequence as being established */ | 541 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); |
493 | nfs_confirm_seqid(&sp->so_seqid, status); | 542 | if (IS_ERR(task)) { |
494 | nfs_increment_open_seqid(status, seqid); | 543 | nfs4_opendata_free(data); |
495 | if (status >= 0) | 544 | return PTR_ERR(task); |
496 | memcpy(stateid, &res.stateid, sizeof(*stateid)); | 545 | } |
546 | status = nfs4_wait_for_completion_rpc_task(task); | ||
547 | if (status != 0) { | ||
548 | data->cancelled = 1; | ||
549 | smp_wmb(); | ||
550 | } else | ||
551 | status = data->rpc_status; | ||
552 | rpc_release_task(task); | ||
497 | return status; | 553 | return status; |
498 | } | 554 | } |
499 | 555 | ||
@@ -602,8 +658,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
602 | } else | 658 | } else |
603 | nfs_refresh_inode(dir, o_res->dir_attr); | 659 | nfs_refresh_inode(dir, o_res->dir_attr); |
604 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | 660 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { |
605 | status = _nfs4_proc_open_confirm(server->client, &o_res->fh, | 661 | status = _nfs4_proc_open_confirm(data); |
606 | data->owner, &o_res->stateid, o_arg->seqid); | ||
607 | if (status != 0) | 662 | if (status != 0) |
608 | return status; | 663 | return status; |
609 | } | 664 | } |