diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-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; |