aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSachin Bhamare <sachin.bhamare@primarydata.com>2015-04-27 08:50:14 -0400
committerJ. Bruce Fields <bfields@redhat.com>2015-05-04 12:02:39 -0400
commit8287f009bd95a5e548059dba62a67727bb9549cd (patch)
tree12d451819b0e805fd86172cdb120cb77014c5e75 /fs
parentebe9cb3bb13e7b9b281969cd279ce70834f7500f (diff)
nfsd: fix pNFS return on close semantics
For the sake of forgetful clients, the server should return the layouts to the file system on 'last close' of a file (assuming that there are no delegations outstanding to that particular client) or on delegreturn (assuming that there are no opens on a file from that particular client). In theory the information is all there in current data structures, but it's not efficiently available; nfs4_file->fi_ref includes references on the file across all clients, but we need a per-(client, file) count. Walking through lots of stateid's to calculate this on each close or delegreturn would be painful. This patch introduces infrastructure to maintain per-client opens and delegation counters on a per-file basis. [hch: ported to the mainline pNFS support, merged various fixes from Jeff] Signed-off-by: Sachin Bhamare <sachin.bhamare@primarydata.com> Signed-off-by: Jeff Layton <jlayton@primarydata.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4state.c125
-rw-r--r--fs/nfsd/state.h14
-rw-r--r--fs/nfsd/xdr4.h1
3 files changed, 133 insertions, 7 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index fb8c66725035..66067a291267 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -94,6 +94,7 @@ static struct kmem_cache *lockowner_slab;
94static struct kmem_cache *file_slab; 94static struct kmem_cache *file_slab;
95static struct kmem_cache *stateid_slab; 95static struct kmem_cache *stateid_slab;
96static struct kmem_cache *deleg_slab; 96static struct kmem_cache *deleg_slab;
97static struct kmem_cache *odstate_slab;
97 98
98static void free_session(struct nfsd4_session *); 99static void free_session(struct nfsd4_session *);
99 100
@@ -281,6 +282,7 @@ put_nfs4_file(struct nfs4_file *fi)
281 if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) { 282 if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) {
282 hlist_del_rcu(&fi->fi_hash); 283 hlist_del_rcu(&fi->fi_hash);
283 spin_unlock(&state_lock); 284 spin_unlock(&state_lock);
285 WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate));
284 WARN_ON_ONCE(!list_empty(&fi->fi_delegations)); 286 WARN_ON_ONCE(!list_empty(&fi->fi_delegations));
285 call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu); 287 call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu);
286 } 288 }
@@ -471,6 +473,86 @@ static void nfs4_file_put_access(struct nfs4_file *fp, u32 access)
471 __nfs4_file_put_access(fp, O_RDONLY); 473 __nfs4_file_put_access(fp, O_RDONLY);
472} 474}
473 475
476/*
477 * Allocate a new open/delegation state counter. This is needed for
478 * pNFS for proper return on close semantics.
479 *
480 * Note that we only allocate it for pNFS-enabled exports, otherwise
481 * all pointers to struct nfs4_clnt_odstate are always NULL.
482 */
483static struct nfs4_clnt_odstate *
484alloc_clnt_odstate(struct nfs4_client *clp)
485{
486 struct nfs4_clnt_odstate *co;
487
488 co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL);
489 if (co) {
490 co->co_client = clp;
491 atomic_set(&co->co_odcount, 1);
492 }
493 return co;
494}
495
496static void
497hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co)
498{
499 struct nfs4_file *fp = co->co_file;
500
501 lockdep_assert_held(&fp->fi_lock);
502 list_add(&co->co_perfile, &fp->fi_clnt_odstate);
503}
504
505static inline void
506get_clnt_odstate(struct nfs4_clnt_odstate *co)
507{
508 if (co)
509 atomic_inc(&co->co_odcount);
510}
511
512static void
513put_clnt_odstate(struct nfs4_clnt_odstate *co)
514{
515 struct nfs4_file *fp;
516
517 if (!co)
518 return;
519
520 fp = co->co_file;
521 if (atomic_dec_and_lock(&co->co_odcount, &fp->fi_lock)) {
522 list_del(&co->co_perfile);
523 spin_unlock(&fp->fi_lock);
524
525 nfsd4_return_all_file_layouts(co->co_client, fp);
526 kmem_cache_free(odstate_slab, co);
527 }
528}
529
530static struct nfs4_clnt_odstate *
531find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new)
532{
533 struct nfs4_clnt_odstate *co;
534 struct nfs4_client *cl;
535
536 if (!new)
537 return NULL;
538
539 cl = new->co_client;
540
541 spin_lock(&fp->fi_lock);
542 list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) {
543 if (co->co_client == cl) {
544 get_clnt_odstate(co);
545 goto out;
546 }
547 }
548 co = new;
549 co->co_file = fp;
550 hash_clnt_odstate_locked(new);
551out:
552 spin_unlock(&fp->fi_lock);
553 return co;
554}
555
474struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, 556struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
475 struct kmem_cache *slab) 557 struct kmem_cache *slab)
476{ 558{
@@ -606,7 +688,8 @@ static void block_delegations(struct knfsd_fh *fh)
606} 688}
607 689
608static struct nfs4_delegation * 690static struct nfs4_delegation *
609alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh) 691alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh,
692 struct nfs4_clnt_odstate *odstate)
610{ 693{
611 struct nfs4_delegation *dp; 694 struct nfs4_delegation *dp;
612 long n; 695 long n;
@@ -631,6 +714,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh)
631 INIT_LIST_HEAD(&dp->dl_perfile); 714 INIT_LIST_HEAD(&dp->dl_perfile);
632 INIT_LIST_HEAD(&dp->dl_perclnt); 715 INIT_LIST_HEAD(&dp->dl_perclnt);
633 INIT_LIST_HEAD(&dp->dl_recall_lru); 716 INIT_LIST_HEAD(&dp->dl_recall_lru);
717 dp->dl_clnt_odstate = odstate;
718 get_clnt_odstate(odstate);
634 dp->dl_type = NFS4_OPEN_DELEGATE_READ; 719 dp->dl_type = NFS4_OPEN_DELEGATE_READ;
635 dp->dl_retries = 1; 720 dp->dl_retries = 1;
636 nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, 721 nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client,
@@ -714,6 +799,7 @@ static void destroy_delegation(struct nfs4_delegation *dp)
714 spin_lock(&state_lock); 799 spin_lock(&state_lock);
715 unhash_delegation_locked(dp); 800 unhash_delegation_locked(dp);
716 spin_unlock(&state_lock); 801 spin_unlock(&state_lock);
802 put_clnt_odstate(dp->dl_clnt_odstate);
717 nfs4_put_deleg_lease(dp->dl_stid.sc_file); 803 nfs4_put_deleg_lease(dp->dl_stid.sc_file);
718 nfs4_put_stid(&dp->dl_stid); 804 nfs4_put_stid(&dp->dl_stid);
719} 805}
@@ -724,6 +810,7 @@ static void revoke_delegation(struct nfs4_delegation *dp)
724 810
725 WARN_ON(!list_empty(&dp->dl_recall_lru)); 811 WARN_ON(!list_empty(&dp->dl_recall_lru));
726 812
813 put_clnt_odstate(dp->dl_clnt_odstate);
727 nfs4_put_deleg_lease(dp->dl_stid.sc_file); 814 nfs4_put_deleg_lease(dp->dl_stid.sc_file);
728 815
729 if (clp->cl_minorversion == 0) 816 if (clp->cl_minorversion == 0)
@@ -933,6 +1020,7 @@ static void nfs4_free_ol_stateid(struct nfs4_stid *stid)
933{ 1020{
934 struct nfs4_ol_stateid *stp = openlockstateid(stid); 1021 struct nfs4_ol_stateid *stp = openlockstateid(stid);
935 1022
1023 put_clnt_odstate(stp->st_clnt_odstate);
936 release_all_access(stp); 1024 release_all_access(stp);
937 if (stp->st_stateowner) 1025 if (stp->st_stateowner)
938 nfs4_put_stateowner(stp->st_stateowner); 1026 nfs4_put_stateowner(stp->st_stateowner);
@@ -1634,6 +1722,7 @@ __destroy_client(struct nfs4_client *clp)
1634 while (!list_empty(&reaplist)) { 1722 while (!list_empty(&reaplist)) {
1635 dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 1723 dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
1636 list_del_init(&dp->dl_recall_lru); 1724 list_del_init(&dp->dl_recall_lru);
1725 put_clnt_odstate(dp->dl_clnt_odstate);
1637 nfs4_put_deleg_lease(dp->dl_stid.sc_file); 1726 nfs4_put_deleg_lease(dp->dl_stid.sc_file);
1638 nfs4_put_stid(&dp->dl_stid); 1727 nfs4_put_stid(&dp->dl_stid);
1639 } 1728 }
@@ -3057,6 +3146,7 @@ static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval,
3057 spin_lock_init(&fp->fi_lock); 3146 spin_lock_init(&fp->fi_lock);
3058 INIT_LIST_HEAD(&fp->fi_stateids); 3147 INIT_LIST_HEAD(&fp->fi_stateids);
3059 INIT_LIST_HEAD(&fp->fi_delegations); 3148 INIT_LIST_HEAD(&fp->fi_delegations);
3149 INIT_LIST_HEAD(&fp->fi_clnt_odstate);
3060 fh_copy_shallow(&fp->fi_fhandle, fh); 3150 fh_copy_shallow(&fp->fi_fhandle, fh);
3061 fp->fi_deleg_file = NULL; 3151 fp->fi_deleg_file = NULL;
3062 fp->fi_had_conflict = false; 3152 fp->fi_had_conflict = false;
@@ -3073,6 +3163,7 @@ static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval,
3073void 3163void
3074nfsd4_free_slabs(void) 3164nfsd4_free_slabs(void)
3075{ 3165{
3166 kmem_cache_destroy(odstate_slab);
3076 kmem_cache_destroy(openowner_slab); 3167 kmem_cache_destroy(openowner_slab);
3077 kmem_cache_destroy(lockowner_slab); 3168 kmem_cache_destroy(lockowner_slab);
3078 kmem_cache_destroy(file_slab); 3169 kmem_cache_destroy(file_slab);
@@ -3103,8 +3194,14 @@ nfsd4_init_slabs(void)
3103 sizeof(struct nfs4_delegation), 0, 0, NULL); 3194 sizeof(struct nfs4_delegation), 0, 0, NULL);
3104 if (deleg_slab == NULL) 3195 if (deleg_slab == NULL)
3105 goto out_free_stateid_slab; 3196 goto out_free_stateid_slab;
3197 odstate_slab = kmem_cache_create("nfsd4_odstate",
3198 sizeof(struct nfs4_clnt_odstate), 0, 0, NULL);
3199 if (odstate_slab == NULL)
3200 goto out_free_deleg_slab;
3106 return 0; 3201 return 0;
3107 3202
3203out_free_deleg_slab:
3204 kmem_cache_destroy(deleg_slab);
3108out_free_stateid_slab: 3205out_free_stateid_slab:
3109 kmem_cache_destroy(stateid_slab); 3206 kmem_cache_destroy(stateid_slab);
3110out_free_file_slab: 3207out_free_file_slab:
@@ -3581,6 +3678,14 @@ alloc_stateid:
3581 open->op_stp = nfs4_alloc_open_stateid(clp); 3678 open->op_stp = nfs4_alloc_open_stateid(clp);
3582 if (!open->op_stp) 3679 if (!open->op_stp)
3583 return nfserr_jukebox; 3680 return nfserr_jukebox;
3681
3682 if (nfsd4_has_session(cstate) &&
3683 (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) {
3684 open->op_odstate = alloc_clnt_odstate(clp);
3685 if (!open->op_odstate)
3686 return nfserr_jukebox;
3687 }
3688
3584 return nfs_ok; 3689 return nfs_ok;
3585} 3690}
3586 3691
@@ -3869,7 +3974,7 @@ out_fput:
3869 3974
3870static struct nfs4_delegation * 3975static struct nfs4_delegation *
3871nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, 3976nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
3872 struct nfs4_file *fp) 3977 struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
3873{ 3978{
3874 int status; 3979 int status;
3875 struct nfs4_delegation *dp; 3980 struct nfs4_delegation *dp;
@@ -3877,7 +3982,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
3877 if (fp->fi_had_conflict) 3982 if (fp->fi_had_conflict)
3878 return ERR_PTR(-EAGAIN); 3983 return ERR_PTR(-EAGAIN);
3879 3984
3880 dp = alloc_init_deleg(clp, fh); 3985 dp = alloc_init_deleg(clp, fh, odstate);
3881 if (!dp) 3986 if (!dp)
3882 return ERR_PTR(-ENOMEM); 3987 return ERR_PTR(-ENOMEM);
3883 3988
@@ -3903,6 +4008,7 @@ out_unlock:
3903 spin_unlock(&state_lock); 4008 spin_unlock(&state_lock);
3904out: 4009out:
3905 if (status) { 4010 if (status) {
4011 put_clnt_odstate(dp->dl_clnt_odstate);
3906 nfs4_put_stid(&dp->dl_stid); 4012 nfs4_put_stid(&dp->dl_stid);
3907 return ERR_PTR(status); 4013 return ERR_PTR(status);
3908 } 4014 }
@@ -3980,7 +4086,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
3980 default: 4086 default:
3981 goto out_no_deleg; 4087 goto out_no_deleg;
3982 } 4088 }
3983 dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file); 4089 dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate);
3984 if (IS_ERR(dp)) 4090 if (IS_ERR(dp))
3985 goto out_no_deleg; 4091 goto out_no_deleg;
3986 4092
@@ -4069,6 +4175,11 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
4069 release_open_stateid(stp); 4175 release_open_stateid(stp);
4070 goto out; 4176 goto out;
4071 } 4177 }
4178
4179 stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp,
4180 open->op_odstate);
4181 if (stp->st_clnt_odstate == open->op_odstate)
4182 open->op_odstate = NULL;
4072 } 4183 }
4073 update_stateid(&stp->st_stid.sc_stateid); 4184 update_stateid(&stp->st_stid.sc_stateid);
4074 memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 4185 memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
@@ -4129,6 +4240,8 @@ void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
4129 kmem_cache_free(file_slab, open->op_file); 4240 kmem_cache_free(file_slab, open->op_file);
4130 if (open->op_stp) 4241 if (open->op_stp)
4131 nfs4_put_stid(&open->op_stp->st_stid); 4242 nfs4_put_stid(&open->op_stp->st_stid);
4243 if (open->op_odstate)
4244 kmem_cache_free(odstate_slab, open->op_odstate);
4132} 4245}
4133 4246
4134__be32 4247__be32
@@ -4853,9 +4966,6 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4853 update_stateid(&stp->st_stid.sc_stateid); 4966 update_stateid(&stp->st_stid.sc_stateid);
4854 memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 4967 memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
4855 4968
4856 nfsd4_return_all_file_layouts(stp->st_stateowner->so_client,
4857 stp->st_stid.sc_file);
4858
4859 nfsd4_close_open_stateid(stp); 4969 nfsd4_close_open_stateid(stp);
4860 4970
4861 /* put reference from nfs4_preprocess_seqid_op */ 4971 /* put reference from nfs4_preprocess_seqid_op */
@@ -6489,6 +6599,7 @@ nfs4_state_shutdown_net(struct net *net)
6489 list_for_each_safe(pos, next, &reaplist) { 6599 list_for_each_safe(pos, next, &reaplist) {
6490 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 6600 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
6491 list_del_init(&dp->dl_recall_lru); 6601 list_del_init(&dp->dl_recall_lru);
6602 put_clnt_odstate(dp->dl_clnt_odstate);
6492 nfs4_put_deleg_lease(dp->dl_stid.sc_file); 6603 nfs4_put_deleg_lease(dp->dl_stid.sc_file);
6493 nfs4_put_stid(&dp->dl_stid); 6604 nfs4_put_stid(&dp->dl_stid);
6494 } 6605 }
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 4f3bfeb11766..bde45d90b746 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -126,6 +126,7 @@ struct nfs4_delegation {
126 struct list_head dl_perfile; 126 struct list_head dl_perfile;
127 struct list_head dl_perclnt; 127 struct list_head dl_perclnt;
128 struct list_head dl_recall_lru; /* delegation recalled */ 128 struct list_head dl_recall_lru; /* delegation recalled */
129 struct nfs4_clnt_odstate *dl_clnt_odstate;
129 u32 dl_type; 130 u32 dl_type;
130 time_t dl_time; 131 time_t dl_time;
131/* For recall: */ 132/* For recall: */
@@ -465,6 +466,17 @@ static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so)
465} 466}
466 467
467/* 468/*
469 * Per-client state indicating no. of opens and outstanding delegations
470 * on a file from a particular client.'od' stands for 'open & delegation'
471 */
472struct nfs4_clnt_odstate {
473 struct nfs4_client *co_client;
474 struct nfs4_file *co_file;
475 struct list_head co_perfile;
476 atomic_t co_odcount;
477};
478
479/*
468 * nfs4_file: a file opened by some number of (open) nfs4_stateowners. 480 * nfs4_file: a file opened by some number of (open) nfs4_stateowners.
469 * 481 *
470 * These objects are global. nfsd keeps one instance of a nfs4_file per 482 * These objects are global. nfsd keeps one instance of a nfs4_file per
@@ -485,6 +497,7 @@ struct nfs4_file {
485 struct list_head fi_delegations; 497 struct list_head fi_delegations;
486 struct rcu_head fi_rcu; 498 struct rcu_head fi_rcu;
487 }; 499 };
500 struct list_head fi_clnt_odstate;
488 /* One each for O_RDONLY, O_WRONLY, O_RDWR: */ 501 /* One each for O_RDONLY, O_WRONLY, O_RDWR: */
489 struct file * fi_fds[3]; 502 struct file * fi_fds[3];
490 /* 503 /*
@@ -526,6 +539,7 @@ struct nfs4_ol_stateid {
526 struct list_head st_perstateowner; 539 struct list_head st_perstateowner;
527 struct list_head st_locks; 540 struct list_head st_locks;
528 struct nfs4_stateowner * st_stateowner; 541 struct nfs4_stateowner * st_stateowner;
542 struct nfs4_clnt_odstate * st_clnt_odstate;
529 unsigned char st_access_bmap; 543 unsigned char st_access_bmap;
530 unsigned char st_deny_bmap; 544 unsigned char st_deny_bmap;
531 struct nfs4_ol_stateid * st_openstp; 545 struct nfs4_ol_stateid * st_openstp;
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index f982ae84f0cd..2f8c092be2b3 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -247,6 +247,7 @@ struct nfsd4_open {
247 struct nfs4_openowner *op_openowner; /* used during processing */ 247 struct nfs4_openowner *op_openowner; /* used during processing */
248 struct nfs4_file *op_file; /* used during processing */ 248 struct nfs4_file *op_file; /* used during processing */
249 struct nfs4_ol_stateid *op_stp; /* used during processing */ 249 struct nfs4_ol_stateid *op_stp; /* used during processing */
250 struct nfs4_clnt_odstate *op_odstate; /* used during processing */
250 struct nfs4_acl *op_acl; 251 struct nfs4_acl *op_acl;
251 struct xdr_netobj op_label; 252 struct xdr_netobj op_label;
252}; 253};