aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@cse.unsw.edu.au>2005-06-24 01:03:10 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-24 03:06:30 -0400
commit13cd21845d6a9729ca95e36ae6e8c669623fbfd4 (patch)
treed60064a17994393bfdc412cc1a85ffdf2a5f5914 /fs/nfsd/nfs4state.c
parent8beefa249371f55432394ac96864c83b0b309c28 (diff)
[PATCH] nfsd4: reference count struct nfs4_file
Add a struct kref to each nfs4_file and take a reference to it from each stateid and delegation that refers to it. The atomicity guarantees are overkill given that all this stuff is done under the single nfsd4 state lock, but a) we'd like finer-grained locking some day, and b) this simplifies the cleanup of the structures a bit, something that has previously been a bit complicated and bug-prone. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r--fs/nfsd/nfs4state.c100
1 files changed, 51 insertions, 49 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a84a80e8c0cf..6ba428afa433 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -111,7 +111,6 @@ opaque_hashval(const void *ptr, int nbytes)
111/* forward declarations */ 111/* forward declarations */
112static void release_stateowner(struct nfs4_stateowner *sop); 112static void release_stateowner(struct nfs4_stateowner *sop);
113static void release_stateid(struct nfs4_stateid *stp, int flags); 113static void release_stateid(struct nfs4_stateid *stp, int flags);
114static void release_file(struct nfs4_file *fp);
115 114
116/* 115/*
117 * Delegation state 116 * Delegation state
@@ -121,6 +120,27 @@ static void release_file(struct nfs4_file *fp);
121spinlock_t recall_lock; 120spinlock_t recall_lock;
122static struct list_head del_recall_lru; 121static struct list_head del_recall_lru;
123 122
123static void
124free_nfs4_file(struct kref *kref)
125{
126 struct nfs4_file *fp = container_of(kref, struct nfs4_file, fi_ref);
127 list_del(&fp->fi_hash);
128 iput(fp->fi_inode);
129 kmem_cache_free(file_slab, fp);
130}
131
132static inline void
133put_nfs4_file(struct nfs4_file *fi)
134{
135 kref_put(&fi->fi_ref, free_nfs4_file);
136}
137
138static inline void
139get_nfs4_file(struct nfs4_file *fi)
140{
141 kref_get(&fi->fi_ref);
142}
143
124static struct nfs4_delegation * 144static struct nfs4_delegation *
125alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) 145alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
126{ 146{
@@ -136,6 +156,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
136 INIT_LIST_HEAD(&dp->dl_del_perclnt); 156 INIT_LIST_HEAD(&dp->dl_del_perclnt);
137 INIT_LIST_HEAD(&dp->dl_recall_lru); 157 INIT_LIST_HEAD(&dp->dl_recall_lru);
138 dp->dl_client = clp; 158 dp->dl_client = clp;
159 get_nfs4_file(fp);
139 dp->dl_file = fp; 160 dp->dl_file = fp;
140 dp->dl_flock = NULL; 161 dp->dl_flock = NULL;
141 get_file(stp->st_vfs_file); 162 get_file(stp->st_vfs_file);
@@ -163,6 +184,7 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
163{ 184{
164 if (atomic_dec_and_test(&dp->dl_count)) { 185 if (atomic_dec_and_test(&dp->dl_count)) {
165 dprintk("NFSD: freeing dp %p\n",dp); 186 dprintk("NFSD: freeing dp %p\n",dp);
187 put_nfs4_file(dp->dl_file);
166 kmem_cache_free(deleg_slab, dp); 188 kmem_cache_free(deleg_slab, dp);
167 } 189 }
168} 190}
@@ -953,6 +975,7 @@ alloc_init_file(struct inode *ino)
953 975
954 fp = kmem_cache_alloc(file_slab, GFP_KERNEL); 976 fp = kmem_cache_alloc(file_slab, GFP_KERNEL);
955 if (fp) { 977 if (fp) {
978 kref_init(&fp->fi_ref);
956 INIT_LIST_HEAD(&fp->fi_hash); 979 INIT_LIST_HEAD(&fp->fi_hash);
957 INIT_LIST_HEAD(&fp->fi_stateids); 980 INIT_LIST_HEAD(&fp->fi_stateids);
958 INIT_LIST_HEAD(&fp->fi_delegations); 981 INIT_LIST_HEAD(&fp->fi_delegations);
@@ -965,24 +988,6 @@ alloc_init_file(struct inode *ino)
965} 988}
966 989
967static void 990static void
968release_all_files(void)
969{
970 int i;
971 struct nfs4_file *fp;
972
973 for (i=0;i<FILE_HASH_SIZE;i++) {
974 while (!list_empty(&file_hashtbl[i])) {
975 fp = list_entry(file_hashtbl[i].next, struct nfs4_file, fi_hash);
976 /* this should never be more than once... */
977 if (!list_empty(&fp->fi_stateids) || !list_empty(&fp->fi_delegations)) {
978 printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp);
979 }
980 release_file(fp);
981 }
982 }
983}
984
985static void
986nfsd4_free_slab(kmem_cache_t **slab) 991nfsd4_free_slab(kmem_cache_t **slab)
987{ 992{
988 int status; 993 int status;
@@ -1141,6 +1146,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
1141 list_add(&stp->st_perfilestate, &sop->so_perfilestate); 1146 list_add(&stp->st_perfilestate, &sop->so_perfilestate);
1142 list_add(&stp->st_perfile, &fp->fi_stateids); 1147 list_add(&stp->st_perfile, &fp->fi_stateids);
1143 stp->st_stateowner = sop; 1148 stp->st_stateowner = sop;
1149 get_nfs4_file(fp);
1144 stp->st_file = fp; 1150 stp->st_file = fp;
1145 stp->st_stateid.si_boot = boot_time; 1151 stp->st_stateid.si_boot = boot_time;
1146 stp->st_stateid.si_stateownerid = sop->so_id; 1152 stp->st_stateid.si_stateownerid = sop->so_id;
@@ -1166,18 +1172,11 @@ release_stateid(struct nfs4_stateid *stp, int flags)
1166 nfsd_close(filp); 1172 nfsd_close(filp);
1167 } else if (flags & LOCK_STATE) 1173 } else if (flags & LOCK_STATE)
1168 locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner); 1174 locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
1175 put_nfs4_file(stp->st_file);
1169 kmem_cache_free(stateid_slab, stp); 1176 kmem_cache_free(stateid_slab, stp);
1170 stp = NULL; 1177 stp = NULL;
1171} 1178}
1172 1179
1173static void
1174release_file(struct nfs4_file *fp)
1175{
1176 list_del(&fp->fi_hash);
1177 iput(fp->fi_inode);
1178 kmem_cache_free(file_slab, fp);
1179}
1180
1181void 1180void
1182move_to_close_lru(struct nfs4_stateowner *sop) 1181move_to_close_lru(struct nfs4_stateowner *sop)
1183{ 1182{
@@ -1192,7 +1191,6 @@ void
1192release_state_owner(struct nfs4_stateid *stp, int flag) 1191release_state_owner(struct nfs4_stateid *stp, int flag)
1193{ 1192{
1194 struct nfs4_stateowner *sop = stp->st_stateowner; 1193 struct nfs4_stateowner *sop = stp->st_stateowner;
1195 struct nfs4_file *fp = stp->st_file;
1196 1194
1197 dprintk("NFSD: release_state_owner\n"); 1195 dprintk("NFSD: release_state_owner\n");
1198 release_stateid(stp, flag); 1196 release_stateid(stp, flag);
@@ -1203,10 +1201,6 @@ release_state_owner(struct nfs4_stateid *stp, int flag)
1203 */ 1201 */
1204 if (sop->so_confirmed && list_empty(&sop->so_perfilestate)) 1202 if (sop->so_confirmed && list_empty(&sop->so_perfilestate))
1205 move_to_close_lru(sop); 1203 move_to_close_lru(sop);
1206 /* unused nfs4_file's are releseed. XXX slab cache? */
1207 if (list_empty(&fp->fi_stateids) && list_empty(&fp->fi_delegations)) {
1208 release_file(fp);
1209 }
1210} 1204}
1211 1205
1212static int 1206static int
@@ -1236,8 +1230,10 @@ find_file(struct inode *ino)
1236 struct nfs4_file *fp; 1230 struct nfs4_file *fp;
1237 1231
1238 list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { 1232 list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
1239 if (fp->fi_inode == ino) 1233 if (fp->fi_inode == ino) {
1234 get_nfs4_file(fp);
1240 return fp; 1235 return fp;
1236 }
1241 } 1237 }
1242 return NULL; 1238 return NULL;
1243} 1239}
@@ -1288,19 +1284,24 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
1288 struct inode *ino = current_fh->fh_dentry->d_inode; 1284 struct inode *ino = current_fh->fh_dentry->d_inode;
1289 struct nfs4_file *fp; 1285 struct nfs4_file *fp;
1290 struct nfs4_stateid *stp; 1286 struct nfs4_stateid *stp;
1287 int ret;
1291 1288
1292 dprintk("NFSD: nfs4_share_conflict\n"); 1289 dprintk("NFSD: nfs4_share_conflict\n");
1293 1290
1294 fp = find_file(ino); 1291 fp = find_file(ino);
1295 if (fp) { 1292 if (!fp)
1293 return nfs_ok;
1294 ret = nfserr_share_denied;
1296 /* Search for conflicting share reservations */ 1295 /* Search for conflicting share reservations */
1297 list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { 1296 list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
1298 if (test_bit(deny_type, &stp->st_deny_bmap) || 1297 if (test_bit(deny_type, &stp->st_deny_bmap) ||
1299 test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap)) 1298 test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
1300 return nfserr_share_denied; 1299 goto out;
1301 }
1302 } 1300 }
1303 return nfs_ok; 1301 ret = nfs_ok;
1302out:
1303 put_nfs4_file(fp);
1304 return ret;
1304} 1305}
1305 1306
1306static inline void 1307static inline void
@@ -1829,10 +1830,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
1829 stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid, 1830 stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid,
1830 stp->st_stateid.si_fileid, stp->st_stateid.si_generation); 1831 stp->st_stateid.si_fileid, stp->st_stateid.si_generation);
1831out: 1832out:
1832 /* take the opportunity to clean up unused state */ 1833 if (fp)
1833 if (fp && list_empty(&fp->fi_stateids) && list_empty(&fp->fi_delegations)) 1834 put_nfs4_file(fp);
1834 release_file(fp);
1835
1836 /* CLAIM_PREVIOUS has different error returns */ 1835 /* CLAIM_PREVIOUS has different error returns */
1837 nfs4_set_claim_prev(open, &status); 1836 nfs4_set_claim_prev(open, &status);
1838 /* 1837 /*
@@ -2480,16 +2479,19 @@ find_stateid(stateid_t *stid, int flags)
2480static struct nfs4_delegation * 2479static struct nfs4_delegation *
2481find_delegation_stateid(struct inode *ino, stateid_t *stid) 2480find_delegation_stateid(struct inode *ino, stateid_t *stid)
2482{ 2481{
2483 struct nfs4_file *fp = NULL; 2482 struct nfs4_file *fp;
2483 struct nfs4_delegation *dl;
2484 2484
2485 dprintk("NFSD:find_delegation_stateid stateid=(%08x/%08x/%08x/%08x)\n", 2485 dprintk("NFSD:find_delegation_stateid stateid=(%08x/%08x/%08x/%08x)\n",
2486 stid->si_boot, stid->si_stateownerid, 2486 stid->si_boot, stid->si_stateownerid,
2487 stid->si_fileid, stid->si_generation); 2487 stid->si_fileid, stid->si_generation);
2488 2488
2489 fp = find_file(ino); 2489 fp = find_file(ino);
2490 if (fp) 2490 if (!fp)
2491 return find_delegation_file(fp, stid); 2491 return NULL;
2492 return NULL; 2492 dl = find_delegation_file(fp, stid);
2493 put_nfs4_file(fp);
2494 return dl;
2493} 2495}
2494 2496
2495/* 2497/*
@@ -2636,6 +2638,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
2636 list_add(&stp->st_perfile, &fp->fi_stateids); 2638 list_add(&stp->st_perfile, &fp->fi_stateids);
2637 list_add(&stp->st_perfilestate, &sop->so_perfilestate); 2639 list_add(&stp->st_perfilestate, &sop->so_perfilestate);
2638 stp->st_stateowner = sop; 2640 stp->st_stateowner = sop;
2641 get_nfs4_file(fp);
2639 stp->st_file = fp; 2642 stp->st_file = fp;
2640 stp->st_stateid.si_boot = boot_time; 2643 stp->st_stateid.si_boot = boot_time;
2641 stp->st_stateid.si_stateownerid = sop->so_id; 2644 stp->st_stateid.si_stateownerid = sop->so_id;
@@ -3287,7 +3290,6 @@ __nfs4_state_shutdown(void)
3287 unhash_delegation(dp); 3290 unhash_delegation(dp);
3288 } 3291 }
3289 3292
3290 release_all_files();
3291 cancel_delayed_work(&laundromat_work); 3293 cancel_delayed_work(&laundromat_work);
3292 flush_scheduled_work(); 3294 flush_scheduled_work();
3293 nfs4_init = 0; 3295 nfs4_init = 0;