diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 51 |
1 files changed, 29 insertions, 22 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 1afd7d4420bd..1379d86f7b4f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -275,9 +275,11 @@ opaque_hashval(const void *ptr, int nbytes) | |||
275 | return x; | 275 | return x; |
276 | } | 276 | } |
277 | 277 | ||
278 | static void nfsd4_free_file(struct nfs4_file *f) | 278 | static void nfsd4_free_file_rcu(struct rcu_head *rcu) |
279 | { | 279 | { |
280 | kmem_cache_free(file_slab, f); | 280 | struct nfs4_file *fp = container_of(rcu, struct nfs4_file, fi_rcu); |
281 | |||
282 | kmem_cache_free(file_slab, fp); | ||
281 | } | 283 | } |
282 | 284 | ||
283 | static inline void | 285 | static inline void |
@@ -286,9 +288,10 @@ put_nfs4_file(struct nfs4_file *fi) | |||
286 | might_lock(&state_lock); | 288 | might_lock(&state_lock); |
287 | 289 | ||
288 | if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) { | 290 | if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) { |
289 | hlist_del(&fi->fi_hash); | 291 | hlist_del_rcu(&fi->fi_hash); |
290 | spin_unlock(&state_lock); | 292 | spin_unlock(&state_lock); |
291 | nfsd4_free_file(fi); | 293 | WARN_ON_ONCE(!list_empty(&fi->fi_delegations)); |
294 | call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu); | ||
292 | } | 295 | } |
293 | } | 296 | } |
294 | 297 | ||
@@ -3057,10 +3060,9 @@ static struct nfs4_file *nfsd4_alloc_file(void) | |||
3057 | } | 3060 | } |
3058 | 3061 | ||
3059 | /* OPEN Share state helper functions */ | 3062 | /* OPEN Share state helper functions */ |
3060 | static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh) | 3063 | static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, |
3064 | struct nfs4_file *fp) | ||
3061 | { | 3065 | { |
3062 | unsigned int hashval = file_hashval(fh); | ||
3063 | |||
3064 | lockdep_assert_held(&state_lock); | 3066 | lockdep_assert_held(&state_lock); |
3065 | 3067 | ||
3066 | atomic_set(&fp->fi_ref, 1); | 3068 | atomic_set(&fp->fi_ref, 1); |
@@ -3073,7 +3075,7 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh) | |||
3073 | fp->fi_share_deny = 0; | 3075 | fp->fi_share_deny = 0; |
3074 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); | 3076 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); |
3075 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); | 3077 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); |
3076 | hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]); | 3078 | hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]); |
3077 | } | 3079 | } |
3078 | 3080 | ||
3079 | void | 3081 | void |
@@ -3294,17 +3296,14 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) | |||
3294 | 3296 | ||
3295 | /* search file_hashtbl[] for file */ | 3297 | /* search file_hashtbl[] for file */ |
3296 | static struct nfs4_file * | 3298 | static struct nfs4_file * |
3297 | find_file_locked(struct knfsd_fh *fh) | 3299 | find_file_locked(struct knfsd_fh *fh, unsigned int hashval) |
3298 | { | 3300 | { |
3299 | unsigned int hashval = file_hashval(fh); | ||
3300 | struct nfs4_file *fp; | 3301 | struct nfs4_file *fp; |
3301 | 3302 | ||
3302 | lockdep_assert_held(&state_lock); | 3303 | hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) { |
3303 | |||
3304 | hlist_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { | ||
3305 | if (nfsd_fh_match(&fp->fi_fhandle, fh)) { | 3304 | if (nfsd_fh_match(&fp->fi_fhandle, fh)) { |
3306 | get_nfs4_file(fp); | 3305 | if (atomic_inc_not_zero(&fp->fi_ref)) |
3307 | return fp; | 3306 | return fp; |
3308 | } | 3307 | } |
3309 | } | 3308 | } |
3310 | return NULL; | 3309 | return NULL; |
@@ -3314,10 +3313,11 @@ static struct nfs4_file * | |||
3314 | find_file(struct knfsd_fh *fh) | 3313 | find_file(struct knfsd_fh *fh) |
3315 | { | 3314 | { |
3316 | struct nfs4_file *fp; | 3315 | struct nfs4_file *fp; |
3316 | unsigned int hashval = file_hashval(fh); | ||
3317 | 3317 | ||
3318 | spin_lock(&state_lock); | 3318 | rcu_read_lock(); |
3319 | fp = find_file_locked(fh); | 3319 | fp = find_file_locked(fh, hashval); |
3320 | spin_unlock(&state_lock); | 3320 | rcu_read_unlock(); |
3321 | return fp; | 3321 | return fp; |
3322 | } | 3322 | } |
3323 | 3323 | ||
@@ -3325,11 +3325,18 @@ static struct nfs4_file * | |||
3325 | find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) | 3325 | find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) |
3326 | { | 3326 | { |
3327 | struct nfs4_file *fp; | 3327 | struct nfs4_file *fp; |
3328 | unsigned int hashval = file_hashval(fh); | ||
3329 | |||
3330 | rcu_read_lock(); | ||
3331 | fp = find_file_locked(fh, hashval); | ||
3332 | rcu_read_unlock(); | ||
3333 | if (fp) | ||
3334 | return fp; | ||
3328 | 3335 | ||
3329 | spin_lock(&state_lock); | 3336 | spin_lock(&state_lock); |
3330 | fp = find_file_locked(fh); | 3337 | fp = find_file_locked(fh, hashval); |
3331 | if (fp == NULL) { | 3338 | if (likely(fp == NULL)) { |
3332 | nfsd4_init_file(new, fh); | 3339 | nfsd4_init_file(fh, hashval, new); |
3333 | fp = new; | 3340 | fp = new; |
3334 | } | 3341 | } |
3335 | spin_unlock(&state_lock); | 3342 | spin_unlock(&state_lock); |
@@ -4127,7 +4134,7 @@ void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, | |||
4127 | nfs4_put_stateowner(so); | 4134 | nfs4_put_stateowner(so); |
4128 | } | 4135 | } |
4129 | if (open->op_file) | 4136 | if (open->op_file) |
4130 | nfsd4_free_file(open->op_file); | 4137 | kmem_cache_free(file_slab, open->op_file); |
4131 | if (open->op_stp) | 4138 | if (open->op_stp) |
4132 | nfs4_put_stid(&open->op_stp->st_stid); | 4139 | nfs4_put_stid(&open->op_stp->st_stid); |
4133 | } | 4140 | } |