diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-07-10 14:07:26 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-07-10 15:05:26 -0400 |
commit | de18643dce70e0d7c3dbccb5d2c8f17f04bc24a6 (patch) | |
tree | b569dea6b6922cf46cb2d124ca620a9c1e048206 | |
parent | 1d31a2531ae91f8a89c0fffa883ef922c0dbb74d (diff) |
nfsd: Add locking to the nfs4_file->fi_fds[] array
Preparation for removal of the client_mutex, which currently protects
this array. While we don't actually need the find_*_file_locked variants
just yet, a later patch will. So go ahead and add them now to reduce
future churn in this code.
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r-- | fs/nfsd/nfs4state.c | 134 | ||||
-rw-r--r-- | fs/nfsd/state.h | 26 |
2 files changed, 118 insertions, 42 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index cfb10d060c83..314dc8061461 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -268,6 +268,79 @@ get_nfs4_file(struct nfs4_file *fi) | |||
268 | atomic_inc(&fi->fi_ref); | 268 | atomic_inc(&fi->fi_ref); |
269 | } | 269 | } |
270 | 270 | ||
271 | static struct file * | ||
272 | __nfs4_get_fd(struct nfs4_file *f, int oflag) | ||
273 | { | ||
274 | if (f->fi_fds[oflag]) | ||
275 | return get_file(f->fi_fds[oflag]); | ||
276 | return NULL; | ||
277 | } | ||
278 | |||
279 | static struct file * | ||
280 | find_writeable_file_locked(struct nfs4_file *f) | ||
281 | { | ||
282 | struct file *ret; | ||
283 | |||
284 | lockdep_assert_held(&f->fi_lock); | ||
285 | |||
286 | ret = __nfs4_get_fd(f, O_WRONLY); | ||
287 | if (!ret) | ||
288 | ret = __nfs4_get_fd(f, O_RDWR); | ||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | static struct file * | ||
293 | find_writeable_file(struct nfs4_file *f) | ||
294 | { | ||
295 | struct file *ret; | ||
296 | |||
297 | spin_lock(&f->fi_lock); | ||
298 | ret = find_writeable_file_locked(f); | ||
299 | spin_unlock(&f->fi_lock); | ||
300 | |||
301 | return ret; | ||
302 | } | ||
303 | |||
304 | static struct file *find_readable_file_locked(struct nfs4_file *f) | ||
305 | { | ||
306 | struct file *ret; | ||
307 | |||
308 | lockdep_assert_held(&f->fi_lock); | ||
309 | |||
310 | ret = __nfs4_get_fd(f, O_RDONLY); | ||
311 | if (!ret) | ||
312 | ret = __nfs4_get_fd(f, O_RDWR); | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | static struct file * | ||
317 | find_readable_file(struct nfs4_file *f) | ||
318 | { | ||
319 | struct file *ret; | ||
320 | |||
321 | spin_lock(&f->fi_lock); | ||
322 | ret = find_readable_file_locked(f); | ||
323 | spin_unlock(&f->fi_lock); | ||
324 | |||
325 | return ret; | ||
326 | } | ||
327 | |||
328 | static struct file * | ||
329 | find_any_file(struct nfs4_file *f) | ||
330 | { | ||
331 | struct file *ret; | ||
332 | |||
333 | spin_lock(&f->fi_lock); | ||
334 | ret = __nfs4_get_fd(f, O_RDWR); | ||
335 | if (!ret) { | ||
336 | ret = __nfs4_get_fd(f, O_WRONLY); | ||
337 | if (!ret) | ||
338 | ret = __nfs4_get_fd(f, O_RDONLY); | ||
339 | } | ||
340 | spin_unlock(&f->fi_lock); | ||
341 | return ret; | ||
342 | } | ||
343 | |||
271 | static int num_delegations; | 344 | static int num_delegations; |
272 | unsigned long max_delegations; | 345 | unsigned long max_delegations; |
273 | 346 | ||
@@ -316,20 +389,31 @@ static void nfs4_file_get_access(struct nfs4_file *fp, int oflag) | |||
316 | __nfs4_file_get_access(fp, oflag); | 389 | __nfs4_file_get_access(fp, oflag); |
317 | } | 390 | } |
318 | 391 | ||
319 | static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag) | 392 | static struct file *nfs4_file_put_fd(struct nfs4_file *fp, int oflag) |
320 | { | 393 | { |
321 | if (fp->fi_fds[oflag]) { | 394 | struct file *filp; |
322 | fput(fp->fi_fds[oflag]); | 395 | |
323 | fp->fi_fds[oflag] = NULL; | 396 | filp = fp->fi_fds[oflag]; |
324 | } | 397 | fp->fi_fds[oflag] = NULL; |
398 | return filp; | ||
325 | } | 399 | } |
326 | 400 | ||
327 | static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) | 401 | static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) |
328 | { | 402 | { |
329 | if (atomic_dec_and_test(&fp->fi_access[oflag])) { | 403 | might_lock(&fp->fi_lock); |
330 | nfs4_file_put_fd(fp, oflag); | 404 | |
405 | if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { | ||
406 | struct file *f1 = NULL; | ||
407 | struct file *f2 = NULL; | ||
408 | |||
409 | f1 = nfs4_file_put_fd(fp, oflag); | ||
331 | if (atomic_read(&fp->fi_access[1 - oflag]) == 0) | 410 | if (atomic_read(&fp->fi_access[1 - oflag]) == 0) |
332 | nfs4_file_put_fd(fp, O_RDWR); | 411 | f2 = nfs4_file_put_fd(fp, O_RDWR); |
412 | spin_unlock(&fp->fi_lock); | ||
413 | if (f1) | ||
414 | fput(f1); | ||
415 | if (f2) | ||
416 | fput(f2); | ||
333 | } | 417 | } |
334 | } | 418 | } |
335 | 419 | ||
@@ -737,8 +821,10 @@ static void __release_lock_stateid(struct nfs4_ol_stateid *stp) | |||
737 | unhash_generic_stateid(stp); | 821 | unhash_generic_stateid(stp); |
738 | unhash_stid(&stp->st_stid); | 822 | unhash_stid(&stp->st_stid); |
739 | file = find_any_file(stp->st_file); | 823 | file = find_any_file(stp->st_file); |
740 | if (file) | 824 | if (file) { |
741 | locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner)); | 825 | locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner)); |
826 | fput(file); | ||
827 | } | ||
742 | close_generic_stateid(stp); | 828 | close_generic_stateid(stp); |
743 | free_generic_stateid(stp); | 829 | free_generic_stateid(stp); |
744 | } | 830 | } |
@@ -3206,17 +3292,27 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, | |||
3206 | static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, | 3292 | static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, |
3207 | struct svc_fh *cur_fh, struct nfsd4_open *open) | 3293 | struct svc_fh *cur_fh, struct nfsd4_open *open) |
3208 | { | 3294 | { |
3295 | struct file *filp = NULL; | ||
3209 | __be32 status; | 3296 | __be32 status; |
3210 | int oflag = nfs4_access_to_omode(open->op_share_access); | 3297 | int oflag = nfs4_access_to_omode(open->op_share_access); |
3211 | int access = nfs4_access_to_access(open->op_share_access); | 3298 | int access = nfs4_access_to_access(open->op_share_access); |
3212 | 3299 | ||
3300 | spin_lock(&fp->fi_lock); | ||
3213 | if (!fp->fi_fds[oflag]) { | 3301 | if (!fp->fi_fds[oflag]) { |
3214 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, | 3302 | spin_unlock(&fp->fi_lock); |
3215 | &fp->fi_fds[oflag]); | 3303 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp); |
3216 | if (status) | 3304 | if (status) |
3217 | goto out; | 3305 | goto out; |
3306 | spin_lock(&fp->fi_lock); | ||
3307 | if (!fp->fi_fds[oflag]) { | ||
3308 | fp->fi_fds[oflag] = filp; | ||
3309 | filp = NULL; | ||
3310 | } | ||
3218 | } | 3311 | } |
3219 | nfs4_file_get_access(fp, oflag); | 3312 | nfs4_file_get_access(fp, oflag); |
3313 | spin_unlock(&fp->fi_lock); | ||
3314 | if (filp) | ||
3315 | fput(filp); | ||
3220 | 3316 | ||
3221 | status = nfsd4_truncate(rqstp, cur_fh, open); | 3317 | status = nfsd4_truncate(rqstp, cur_fh, open); |
3222 | if (status) | 3318 | if (status) |
@@ -3301,13 +3397,15 @@ static int nfs4_setlease(struct nfs4_delegation *dp) | |||
3301 | if (status) | 3397 | if (status) |
3302 | goto out_free; | 3398 | goto out_free; |
3303 | fp->fi_lease = fl; | 3399 | fp->fi_lease = fl; |
3304 | fp->fi_deleg_file = get_file(fl->fl_file); | 3400 | fp->fi_deleg_file = fl->fl_file; |
3305 | atomic_set(&fp->fi_delegees, 1); | 3401 | atomic_set(&fp->fi_delegees, 1); |
3306 | spin_lock(&state_lock); | 3402 | spin_lock(&state_lock); |
3307 | hash_delegation_locked(dp, fp); | 3403 | hash_delegation_locked(dp, fp); |
3308 | spin_unlock(&state_lock); | 3404 | spin_unlock(&state_lock); |
3309 | return 0; | 3405 | return 0; |
3310 | out_free: | 3406 | out_free: |
3407 | if (fl->fl_file) | ||
3408 | fput(fl->fl_file); | ||
3311 | locks_free_lock(fl); | 3409 | locks_free_lock(fl); |
3312 | return status; | 3410 | return status; |
3313 | } | 3411 | } |
@@ -3905,6 +4003,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, | |||
3905 | status = nfserr_serverfault; | 4003 | status = nfserr_serverfault; |
3906 | goto out; | 4004 | goto out; |
3907 | } | 4005 | } |
4006 | get_file(file); | ||
3908 | } | 4007 | } |
3909 | break; | 4008 | break; |
3910 | case NFS4_OPEN_STID: | 4009 | case NFS4_OPEN_STID: |
@@ -3932,7 +4031,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, | |||
3932 | } | 4031 | } |
3933 | status = nfs_ok; | 4032 | status = nfs_ok; |
3934 | if (file) | 4033 | if (file) |
3935 | *filpp = get_file(file); | 4034 | *filpp = file; |
3936 | out: | 4035 | out: |
3937 | nfs4_unlock_state(); | 4036 | nfs4_unlock_state(); |
3938 | return status; | 4037 | return status; |
@@ -4653,6 +4752,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4653 | break; | 4752 | break; |
4654 | } | 4753 | } |
4655 | out: | 4754 | out: |
4755 | if (filp) | ||
4756 | fput(filp); | ||
4656 | if (status && new_state) | 4757 | if (status && new_state) |
4657 | release_lock_stateid(lock_stp); | 4758 | release_lock_stateid(lock_stp); |
4658 | nfsd4_bump_seqid(cstate, status); | 4759 | nfsd4_bump_seqid(cstate, status); |
@@ -4793,7 +4894,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4793 | if (!file_lock) { | 4894 | if (!file_lock) { |
4794 | dprintk("NFSD: %s: unable to allocate lock!\n", __func__); | 4895 | dprintk("NFSD: %s: unable to allocate lock!\n", __func__); |
4795 | status = nfserr_jukebox; | 4896 | status = nfserr_jukebox; |
4796 | goto out; | 4897 | goto fput; |
4797 | } | 4898 | } |
4798 | locks_init_lock(file_lock); | 4899 | locks_init_lock(file_lock); |
4799 | file_lock->fl_type = F_UNLCK; | 4900 | file_lock->fl_type = F_UNLCK; |
@@ -4815,7 +4916,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4815 | } | 4916 | } |
4816 | update_stateid(&stp->st_stid.sc_stateid); | 4917 | update_stateid(&stp->st_stid.sc_stateid); |
4817 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 4918 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
4818 | 4919 | fput: | |
4920 | fput(filp); | ||
4819 | out: | 4921 | out: |
4820 | nfsd4_bump_seqid(cstate, status); | 4922 | nfsd4_bump_seqid(cstate, status); |
4821 | if (!cstate->replay_owner) | 4923 | if (!cstate->replay_owner) |
@@ -4826,7 +4928,7 @@ out: | |||
4826 | 4928 | ||
4827 | out_nfserr: | 4929 | out_nfserr: |
4828 | status = nfserrno(err); | 4930 | status = nfserrno(err); |
4829 | goto out; | 4931 | goto fput; |
4830 | } | 4932 | } |
4831 | 4933 | ||
4832 | /* | 4934 | /* |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 04737b3ed363..9f1159d5de56 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -398,32 +398,6 @@ struct nfs4_file { | |||
398 | bool fi_had_conflict; | 398 | bool fi_had_conflict; |
399 | }; | 399 | }; |
400 | 400 | ||
401 | /* XXX: for first cut may fall back on returning file that doesn't work | ||
402 | * at all? */ | ||
403 | static inline struct file *find_writeable_file(struct nfs4_file *f) | ||
404 | { | ||
405 | if (f->fi_fds[O_WRONLY]) | ||
406 | return f->fi_fds[O_WRONLY]; | ||
407 | return f->fi_fds[O_RDWR]; | ||
408 | } | ||
409 | |||
410 | static inline struct file *find_readable_file(struct nfs4_file *f) | ||
411 | { | ||
412 | if (f->fi_fds[O_RDONLY]) | ||
413 | return f->fi_fds[O_RDONLY]; | ||
414 | return f->fi_fds[O_RDWR]; | ||
415 | } | ||
416 | |||
417 | static inline struct file *find_any_file(struct nfs4_file *f) | ||
418 | { | ||
419 | if (f->fi_fds[O_RDWR]) | ||
420 | return f->fi_fds[O_RDWR]; | ||
421 | else if (f->fi_fds[O_WRONLY]) | ||
422 | return f->fi_fds[O_WRONLY]; | ||
423 | else | ||
424 | return f->fi_fds[O_RDONLY]; | ||
425 | } | ||
426 | |||
427 | /* "ol" stands for "Open or Lock". Better suggestions welcome. */ | 401 | /* "ol" stands for "Open or Lock". Better suggestions welcome. */ |
428 | struct nfs4_ol_stateid { | 402 | struct nfs4_ol_stateid { |
429 | struct nfs4_stid st_stid; /* must be first field */ | 403 | struct nfs4_stid st_stid; /* must be first field */ |