aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2014-07-10 14:07:26 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-07-10 15:05:26 -0400
commitde18643dce70e0d7c3dbccb5d2c8f17f04bc24a6 (patch)
treeb569dea6b6922cf46cb2d124ca620a9c1e048206
parent1d31a2531ae91f8a89c0fffa883ef922c0dbb74d (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.c134
-rw-r--r--fs/nfsd/state.h26
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
271static 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
279static struct file *
280find_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
292static struct file *
293find_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
304static 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
316static struct file *
317find_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
328static struct file *
329find_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
271static int num_delegations; 344static int num_delegations;
272unsigned long max_delegations; 345unsigned 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
319static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag) 392static 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
327static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 401static 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,
3206static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 3292static __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;
3310out_free: 3406out_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;
3936out: 4035out:
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 }
4655out: 4754out:
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 4919fput:
4920 fput(filp);
4819out: 4921out:
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
4827out_nfserr: 4929out_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? */
403static 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
410static 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
417static 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. */
428struct nfs4_ol_stateid { 402struct nfs4_ol_stateid {
429 struct nfs4_stid st_stid; /* must be first field */ 403 struct nfs4_stid st_stid; /* must be first field */