diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 193 |
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 | ||
197 | struct nfs4_opendata { | 197 | struct 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 | ||
208 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | 211 | static 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 | ||
256 | static void nfs4_opendata_free(struct nfs4_opendata *p) | 260 | static 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 | ||
312 | static 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); | ||
326 | put_inode: | ||
327 | iput(inode); | ||
328 | out: | ||
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 | ||
476 | static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, struct nfs_openargs *o_arg, struct nfs_openres *o_res) | 500 | static 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! */ | 519 | static 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 | |||
543 | static 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); | ||
561 | out_free: | ||
562 | nfs4_opendata_free(data); | ||
563 | } | ||
564 | |||
565 | static 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 | */ | ||
574 | static 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); |
525 | out: | 613 | return 0; |
526 | return status; | ||
527 | } | 614 | } |
528 | 615 | ||
529 | static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags) | 616 | static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags) |
@@ -562,14 +649,15 @@ out: | |||
562 | static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 649 | static 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 | } |
685 | out_close_state: | ||
686 | nfs4_close_state(newstate, openflags); | ||
609 | out_nodeleg: | 687 | out_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 | ||
624 | static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 702 | static 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 | */ |
661 | static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res) | 739 | static 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; |
715 | out_err: | 792 | out_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 | */ |
747 | static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) | 824 | static 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: | |||
791 | out_err: | 863 | out_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, |