aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c193
1 files changed, 130 insertions, 63 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 4a5cc8402110..aed8701c1a36 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -195,6 +195,7 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf
195} 195}
196 196
197struct nfs4_opendata { 197struct nfs4_opendata {
198 atomic_t count;
198 struct nfs_openargs o_arg; 199 struct nfs_openargs o_arg;
199 struct nfs_openres o_res; 200 struct nfs_openres o_res;
200 struct nfs_fattr f_attr; 201 struct nfs_fattr f_attr;
@@ -203,6 +204,8 @@ struct nfs4_opendata {
203 struct dentry *dir; 204 struct dentry *dir;
204 struct nfs4_state_owner *owner; 205 struct nfs4_state_owner *owner;
205 struct iattr attrs; 206 struct iattr attrs;
207 int rpc_status;
208 int cancelled;
206}; 209};
207 210
208static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, 211static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
@@ -220,6 +223,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
220 p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); 223 p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
221 if (p->o_arg.seqid == NULL) 224 if (p->o_arg.seqid == NULL)
222 goto err_free; 225 goto err_free;
226 atomic_set(&p->count, 1);
223 p->dentry = dget(dentry); 227 p->dentry = dget(dentry);
224 p->dir = parent; 228 p->dir = parent;
225 p->owner = sp; 229 p->owner = sp;
@@ -255,7 +259,7 @@ err:
255 259
256static void nfs4_opendata_free(struct nfs4_opendata *p) 260static void nfs4_opendata_free(struct nfs4_opendata *p)
257{ 261{
258 if (p != NULL) { 262 if (p != NULL && atomic_dec_and_test(&p->count)) {
259 nfs_free_seqid(p->o_arg.seqid); 263 nfs_free_seqid(p->o_arg.seqid);
260 nfs4_put_state_owner(p->owner); 264 nfs4_put_state_owner(p->owner);
261 dput(p->dir); 265 dput(p->dir);
@@ -305,6 +309,26 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid,
305 spin_unlock(&state->owner->so_lock); 309 spin_unlock(&state->owner->so_lock);
306} 310}
307 311
312static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
313{
314 struct inode *inode;
315 struct nfs4_state *state = NULL;
316
317 if (!(data->f_attr.valid & NFS_ATTR_FATTR))
318 goto out;
319 inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr);
320 if (inode == NULL)
321 goto out;
322 state = nfs4_get_open_state(inode, data->owner);
323 if (state == NULL)
324 goto put_inode;
325 update_open_stateid(state, &data->o_res.stateid, data->o_arg.open_flags);
326put_inode:
327 iput(inode);
328out:
329 return state;
330}
331
308/* 332/*
309 * OPEN_RECLAIM: 333 * OPEN_RECLAIM:
310 * reclaim state on the server after a reboot. 334 * reclaim state on the server after a reboot.
@@ -473,41 +497,105 @@ static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *f
473 return status; 497 return status;
474} 498}
475 499
476static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, struct nfs_openargs *o_arg, struct nfs_openres *o_res) 500static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
477{ 501{
478 struct nfs_server *server = NFS_SERVER(dir); 502 struct nfs4_opendata *data = calldata;
503 struct nfs4_state_owner *sp = data->owner;
479 struct rpc_message msg = { 504 struct rpc_message msg = {
480 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], 505 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN],
481 .rpc_argp = o_arg, 506 .rpc_argp = &data->o_arg,
482 .rpc_resp = o_res, 507 .rpc_resp = &data->o_res,
483 .rpc_cred = sp->so_cred, 508 .rpc_cred = sp->so_cred,
484 }; 509 };
485 int status; 510
511 if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0)
512 return;
513 /* Update sequence id. */
514 data->o_arg.id = sp->so_id;
515 data->o_arg.clientid = sp->so_client->cl_clientid;
516 rpc_call_setup(task, &msg, 0);
517}
486 518
487 /* Update sequence id. The caller must serialize! */ 519static void nfs4_open_done(struct rpc_task *task, void *calldata)
488 o_arg->id = sp->so_id; 520{
489 o_arg->clientid = sp->so_client->cl_clientid; 521 struct nfs4_opendata *data = calldata;
490 522
491 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); 523 data->rpc_status = task->tk_status;
492 if (status == 0) { 524 if (RPC_ASSASSINATED(task))
493 /* OPEN on anything except a regular file is disallowed in NFSv4 */ 525 return;
494 switch (o_res->f_attr->mode & S_IFMT) { 526 if (task->tk_status == 0) {
527 switch (data->o_res.f_attr->mode & S_IFMT) {
495 case S_IFREG: 528 case S_IFREG:
496 break; 529 break;
497 case S_IFLNK: 530 case S_IFLNK:
498 status = -ELOOP; 531 data->rpc_status = -ELOOP;
499 break; 532 break;
500 case S_IFDIR: 533 case S_IFDIR:
501 status = -EISDIR; 534 data->rpc_status = -EISDIR;
502 break; 535 break;
503 default: 536 default:
504 status = -ENOTDIR; 537 data->rpc_status = -ENOTDIR;
505 } 538 }
506 } 539 }
540 nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid);
541}
542
543static void nfs4_open_release(void *calldata)
544{
545 struct nfs4_opendata *data = calldata;
546 struct nfs4_state *state = NULL;
547
548 /* If this request hasn't been cancelled, do nothing */
549 if (data->cancelled == 0)
550 goto out_free;
551 /* In case of error, no cleanup! */
552 if (data->rpc_status != 0)
553 goto out_free;
554 /* In case we need an open_confirm, no cleanup! */
555 if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)
556 goto out_free;
557 nfs_confirm_seqid(&data->owner->so_seqid, 0);
558 state = nfs4_opendata_to_nfs4_state(data);
559 if (state != NULL)
560 nfs4_close_state(state, data->o_arg.open_flags);
561out_free:
562 nfs4_opendata_free(data);
563}
564
565static const struct rpc_call_ops nfs4_open_ops = {
566 .rpc_call_prepare = nfs4_open_prepare,
567 .rpc_call_done = nfs4_open_done,
568 .rpc_release = nfs4_open_release,
569};
507 570
508 nfs_increment_open_seqid(status, o_arg->seqid); 571/*
572 * Note: On error, nfs4_proc_open will free the struct nfs4_opendata
573 */
574static int _nfs4_proc_open(struct nfs4_opendata *data)
575{
576 struct inode *dir = data->dir->d_inode;
577 struct nfs_server *server = NFS_SERVER(dir);
578 struct nfs_openargs *o_arg = &data->o_arg;
579 struct nfs_openres *o_res = &data->o_res;
580 struct rpc_task *task;
581 int status;
582
583 atomic_inc(&data->count);
584 task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data);
585 if (IS_ERR(task)) {
586 nfs4_opendata_free(data);
587 return PTR_ERR(task);
588 }
589 status = nfs4_wait_for_completion_rpc_task(task);
590 if (status != 0) {
591 data->cancelled = 1;
592 smp_wmb();
593 } else
594 status = data->rpc_status;
595 rpc_release_task(task);
509 if (status != 0) 596 if (status != 0)
510 goto out; 597 return status;
598
511 if (o_arg->open_flags & O_CREAT) { 599 if (o_arg->open_flags & O_CREAT) {
512 update_changeattr(dir, &o_res->cinfo); 600 update_changeattr(dir, &o_res->cinfo);
513 nfs_post_op_update_inode(dir, o_res->dir_attr); 601 nfs_post_op_update_inode(dir, o_res->dir_attr);
@@ -515,15 +603,14 @@ static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, stru
515 nfs_refresh_inode(dir, o_res->dir_attr); 603 nfs_refresh_inode(dir, o_res->dir_attr);
516 if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { 604 if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
517 status = _nfs4_proc_open_confirm(server->client, &o_res->fh, 605 status = _nfs4_proc_open_confirm(server->client, &o_res->fh,
518 sp, &o_res->stateid, o_arg->seqid); 606 data->owner, &o_res->stateid, o_arg->seqid);
519 if (status != 0) 607 if (status != 0)
520 goto out; 608 return status;
521 } 609 }
522 nfs_confirm_seqid(&sp->so_seqid, 0); 610 nfs_confirm_seqid(&data->owner->so_seqid, 0);
523 if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) 611 if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
524 status = server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); 612 return server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr);
525out: 613 return 0;
526 return status;
527} 614}
528 615
529static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags) 616static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags)
@@ -562,14 +649,15 @@ out:
562static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) 649static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
563{ 650{
564 struct dentry *parent = dget_parent(dentry); 651 struct dentry *parent = dget_parent(dentry);
565 struct inode *dir = parent->d_inode;
566 struct inode *inode = state->inode; 652 struct inode *inode = state->inode;
567 struct nfs_delegation *delegation = NFS_I(inode)->delegation; 653 struct nfs_delegation *delegation = NFS_I(inode)->delegation;
568 struct nfs4_opendata *opendata; 654 struct nfs4_opendata *opendata;
655 struct nfs4_state *newstate;
656 int openflags = state->state & (FMODE_READ|FMODE_WRITE);
569 int status = 0; 657 int status = 0;
570 658
571 if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { 659 if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) {
572 status = _nfs4_do_access(inode, sp->so_cred, state->state); 660 status = _nfs4_do_access(inode, sp->so_cred, openflags);
573 if (status < 0) 661 if (status < 0)
574 goto out; 662 goto out;
575 memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid)); 663 memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid));
@@ -577,27 +665,15 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
577 goto out; 665 goto out;
578 } 666 }
579 status = -ENOMEM; 667 status = -ENOMEM;
580 opendata = nfs4_opendata_alloc(dentry, sp, state->state, NULL); 668 opendata = nfs4_opendata_alloc(dentry, sp, openflags, NULL);
581 if (opendata == NULL) 669 if (opendata == NULL)
582 goto out; 670 goto out;
583 status = _nfs4_proc_open(dir, sp, &opendata->o_arg, &opendata->o_res); 671 status = _nfs4_proc_open(opendata);
584 if (status != 0) 672 if (status != 0)
585 goto out_nodeleg; 673 goto out_nodeleg;
586 /* Check if files differ */ 674 newstate = nfs4_opendata_to_nfs4_state(opendata);
587 if ((opendata->f_attr.mode & S_IFMT) != (inode->i_mode & S_IFMT)) 675 if (newstate != state)
588 goto out_stale; 676 goto out_stale;
589 /* Has the file handle changed? */
590 if (nfs_compare_fh(&opendata->o_res.fh, NFS_FH(inode)) != 0) {
591 /* Verify if the change attributes are the same */
592 if (opendata->f_attr.change_attr != NFS_I(inode)->change_attr)
593 goto out_stale;
594 if (nfs_size_to_loff_t(opendata->f_attr.size) != inode->i_size)
595 goto out_stale;
596 /* Lets just pretend that this is the same file */
597 nfs_copy_fh(NFS_FH(inode), &opendata->o_res.fh);
598 NFS_I(inode)->fileid = opendata->f_attr.fileid;
599 }
600 memcpy(&state->stateid, &opendata->o_res.stateid, sizeof(state->stateid));
601 if (opendata->o_res.delegation_type != 0) { 677 if (opendata->o_res.delegation_type != 0) {
602 if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) 678 if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM))
603 nfs_inode_set_delegation(inode, sp->so_cred, 679 nfs_inode_set_delegation(inode, sp->so_cred,
@@ -606,6 +682,8 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
606 nfs_inode_reclaim_delegation(inode, sp->so_cred, 682 nfs_inode_reclaim_delegation(inode, sp->so_cred,
607 &opendata->o_res); 683 &opendata->o_res);
608 } 684 }
685out_close_state:
686 nfs4_close_state(newstate, openflags);
609out_nodeleg: 687out_nodeleg:
610 nfs4_opendata_free(opendata); 688 nfs4_opendata_free(opendata);
611 clear_bit(NFS_DELEGATED_STATE, &state->flags); 689 clear_bit(NFS_DELEGATED_STATE, &state->flags);
@@ -618,7 +696,7 @@ out_stale:
618 nfs4_drop_state_owner(sp); 696 nfs4_drop_state_owner(sp);
619 d_drop(dentry); 697 d_drop(dentry);
620 /* Should we be trying to close that stateid? */ 698 /* Should we be trying to close that stateid? */
621 goto out_nodeleg; 699 goto out_close_state;
622} 700}
623 701
624static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) 702static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
@@ -656,7 +734,7 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
656} 734}
657 735
658/* 736/*
659 * Returns an nfs4_state + an extra reference to the inode 737 * Returns a referenced nfs4_state if there is an open delegation on the file
660 */ 738 */
661static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res) 739static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res)
662{ 740{
@@ -709,7 +787,6 @@ out_ok:
709 nfs4_put_state_owner(sp); 787 nfs4_put_state_owner(sp);
710 up_read(&nfsi->rwsem); 788 up_read(&nfsi->rwsem);
711 up_read(&clp->cl_sem); 789 up_read(&clp->cl_sem);
712 igrab(inode);
713 *res = state; 790 *res = state;
714 return 0; 791 return 0;
715out_err: 792out_err:
@@ -742,7 +819,7 @@ static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, st
742} 819}
743 820
744/* 821/*
745 * Returns an nfs4_state + an referenced inode 822 * Returns a referenced nfs4_state
746 */ 823 */
747static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) 824static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
748{ 825{
@@ -750,7 +827,6 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
750 struct nfs4_state *state = NULL; 827 struct nfs4_state *state = NULL;
751 struct nfs_server *server = NFS_SERVER(dir); 828 struct nfs_server *server = NFS_SERVER(dir);
752 struct nfs4_client *clp = server->nfs4_state; 829 struct nfs4_client *clp = server->nfs4_state;
753 struct inode *inode = NULL;
754 struct nfs4_opendata *opendata; 830 struct nfs4_opendata *opendata;
755 int status; 831 int status;
756 832
@@ -765,20 +841,16 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
765 if (opendata == NULL) 841 if (opendata == NULL)
766 goto err_put_state_owner; 842 goto err_put_state_owner;
767 843
768 status = _nfs4_proc_open(dir, sp, &opendata->o_arg, &opendata->o_res); 844 status = _nfs4_proc_open(opendata);
769 if (status != 0) 845 if (status != 0)
770 goto err_opendata_free; 846 goto err_opendata_free;
771 847
772 status = -ENOMEM; 848 status = -ENOMEM;
773 inode = nfs_fhget(dir->i_sb, &opendata->o_res.fh, &opendata->f_attr); 849 state = nfs4_opendata_to_nfs4_state(opendata);
774 if (!inode) 850 if (state == NULL)
775 goto err_opendata_free;
776 state = nfs4_get_open_state(inode, sp);
777 if (!state)
778 goto err_opendata_free; 851 goto err_opendata_free;
779 update_open_stateid(state, &opendata->o_res.stateid, flags);
780 if (opendata->o_res.delegation_type != 0) 852 if (opendata->o_res.delegation_type != 0)
781 nfs_inode_set_delegation(inode, cred, &opendata->o_res); 853 nfs_inode_set_delegation(state->inode, cred, &opendata->o_res);
782 nfs4_opendata_free(opendata); 854 nfs4_opendata_free(opendata);
783 nfs4_put_state_owner(sp); 855 nfs4_put_state_owner(sp);
784 up_read(&clp->cl_sem); 856 up_read(&clp->cl_sem);
@@ -791,8 +863,6 @@ err_put_state_owner:
791out_err: 863out_err:
792 /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */ 864 /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */
793 up_read(&clp->cl_sem); 865 up_read(&clp->cl_sem);
794 if (inode != NULL)
795 iput(inode);
796 *res = NULL; 866 *res = NULL;
797 return status; 867 return status;
798} 868}
@@ -1066,7 +1136,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
1066 d_add(dentry, NULL); 1136 d_add(dentry, NULL);
1067 return (struct dentry *)state; 1137 return (struct dentry *)state;
1068 } 1138 }
1069 res = d_add_unique(dentry, state->inode); 1139 res = d_add_unique(dentry, igrab(state->inode));
1070 if (res != NULL) 1140 if (res != NULL)
1071 dentry = res; 1141 dentry = res;
1072 nfs4_intent_set_file(nd, dentry, state); 1142 nfs4_intent_set_file(nd, dentry, state);
@@ -1078,7 +1148,6 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
1078{ 1148{
1079 struct rpc_cred *cred; 1149 struct rpc_cred *cred;
1080 struct nfs4_state *state; 1150 struct nfs4_state *state;
1081 struct inode *inode;
1082 1151
1083 cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); 1152 cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
1084 if (IS_ERR(cred)) 1153 if (IS_ERR(cred))
@@ -1102,9 +1171,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
1102 } 1171 }
1103 goto out_drop; 1172 goto out_drop;
1104 } 1173 }
1105 inode = state->inode; 1174 if (state->inode == dentry->d_inode) {
1106 iput(inode);
1107 if (inode == dentry->d_inode) {
1108 nfs4_intent_set_file(nd, dentry, state); 1175 nfs4_intent_set_file(nd, dentry, state);
1109 return 1; 1176 return 1;
1110 } 1177 }
@@ -1633,7 +1700,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
1633 status = PTR_ERR(state); 1700 status = PTR_ERR(state);
1634 goto out; 1701 goto out;
1635 } 1702 }
1636 d_instantiate(dentry, state->inode); 1703 d_instantiate(dentry, igrab(state->inode));
1637 if (flags & O_EXCL) { 1704 if (flags & O_EXCL) {
1638 struct nfs_fattr fattr; 1705 struct nfs_fattr fattr;
1639 status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, 1706 status = nfs4_do_setattr(NFS_SERVER(dir), &fattr,