diff options
author | NeilBrown <neilb@cse.unsw.edu.au> | 2005-06-24 01:03:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-24 03:06:30 -0400 |
commit | 13cd21845d6a9729ca95e36ae6e8c669623fbfd4 (patch) | |
tree | d60064a17994393bfdc412cc1a85ffdf2a5f5914 /fs | |
parent | 8beefa249371f55432394ac96864c83b0b309c28 (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')
-rw-r--r-- | fs/nfsd/nfs4state.c | 100 |
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 */ |
112 | static void release_stateowner(struct nfs4_stateowner *sop); | 112 | static void release_stateowner(struct nfs4_stateowner *sop); |
113 | static void release_stateid(struct nfs4_stateid *stp, int flags); | 113 | static void release_stateid(struct nfs4_stateid *stp, int flags); |
114 | static 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); | |||
121 | spinlock_t recall_lock; | 120 | spinlock_t recall_lock; |
122 | static struct list_head del_recall_lru; | 121 | static struct list_head del_recall_lru; |
123 | 122 | ||
123 | static void | ||
124 | free_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 | |||
132 | static inline void | ||
133 | put_nfs4_file(struct nfs4_file *fi) | ||
134 | { | ||
135 | kref_put(&fi->fi_ref, free_nfs4_file); | ||
136 | } | ||
137 | |||
138 | static inline void | ||
139 | get_nfs4_file(struct nfs4_file *fi) | ||
140 | { | ||
141 | kref_get(&fi->fi_ref); | ||
142 | } | ||
143 | |||
124 | static struct nfs4_delegation * | 144 | static struct nfs4_delegation * |
125 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) | 145 | alloc_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 | ||
967 | static void | 990 | static void |
968 | release_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 | |||
985 | static void | ||
986 | nfsd4_free_slab(kmem_cache_t **slab) | 991 | nfsd4_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 | ||
1173 | static void | ||
1174 | release_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 | |||
1181 | void | 1180 | void |
1182 | move_to_close_lru(struct nfs4_stateowner *sop) | 1181 | move_to_close_lru(struct nfs4_stateowner *sop) |
1183 | { | 1182 | { |
@@ -1192,7 +1191,6 @@ void | |||
1192 | release_state_owner(struct nfs4_stateid *stp, int flag) | 1191 | release_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 | ||
1212 | static int | 1206 | static 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; |
1302 | out: | ||
1303 | put_nfs4_file(fp); | ||
1304 | return ret; | ||
1304 | } | 1305 | } |
1305 | 1306 | ||
1306 | static inline void | 1307 | static 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); |
1831 | out: | 1832 | out: |
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) | |||
2480 | static struct nfs4_delegation * | 2479 | static struct nfs4_delegation * |
2481 | find_delegation_stateid(struct inode *ino, stateid_t *stid) | 2480 | find_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; |