aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorOleg Drokin <green@linuxhacker.ru>2016-06-14 23:28:05 -0400
committerJ. Bruce Fields <bfields@redhat.com>2016-06-15 22:03:41 -0400
commit5cc1fb2a093e254b656c64ff24b0b76bed1d34d9 (patch)
treef37829299f97a6ab668ec0ec77bf00af101ae5be /fs
parentfeb9dad5209280085d5b0c094fa67e7a8d75c81a (diff)
nfsd: Extend the mutex holding region around in nfsd4_process_open2()
To avoid racing entry into nfs4_get_vfs_file(). Make init_open_stateid() return with locked stateid to be unlocked by the caller. Signed-off-by: Oleg Drokin <green@linuxhacker.ru> Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4state.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index c927d36d8ac6..94854a06c9ad 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3487,6 +3487,10 @@ init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
3487 struct nfs4_openowner *oo = open->op_openowner; 3487 struct nfs4_openowner *oo = open->op_openowner;
3488 struct nfs4_ol_stateid *retstp = NULL; 3488 struct nfs4_ol_stateid *retstp = NULL;
3489 3489
3490 /* We are moving these outside of the spinlocks to avoid the warnings */
3491 mutex_init(&stp->st_mutex);
3492 mutex_lock(&stp->st_mutex);
3493
3490 spin_lock(&oo->oo_owner.so_client->cl_lock); 3494 spin_lock(&oo->oo_owner.so_client->cl_lock);
3491 spin_lock(&fp->fi_lock); 3495 spin_lock(&fp->fi_lock);
3492 3496
@@ -3502,13 +3506,17 @@ init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
3502 stp->st_access_bmap = 0; 3506 stp->st_access_bmap = 0;
3503 stp->st_deny_bmap = 0; 3507 stp->st_deny_bmap = 0;
3504 stp->st_openstp = NULL; 3508 stp->st_openstp = NULL;
3505 mutex_init(&stp->st_mutex);
3506 list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 3509 list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
3507 list_add(&stp->st_perfile, &fp->fi_stateids); 3510 list_add(&stp->st_perfile, &fp->fi_stateids);
3508 3511
3509out_unlock: 3512out_unlock:
3510 spin_unlock(&fp->fi_lock); 3513 spin_unlock(&fp->fi_lock);
3511 spin_unlock(&oo->oo_owner.so_client->cl_lock); 3514 spin_unlock(&oo->oo_owner.so_client->cl_lock);
3515 if (retstp) {
3516 mutex_lock(&retstp->st_mutex);
3517 /* Not that we need to, just for neatness */
3518 mutex_unlock(&stp->st_mutex);
3519 }
3512 return retstp; 3520 return retstp;
3513} 3521}
3514 3522
@@ -4344,11 +4352,14 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
4344 } else { 4352 } else {
4345 stp = open->op_stp; 4353 stp = open->op_stp;
4346 open->op_stp = NULL; 4354 open->op_stp = NULL;
4355 /*
4356 * init_open_stateid() either returns a locked stateid
4357 * it found, or initializes and locks the new one we passed in
4358 */
4347 swapstp = init_open_stateid(stp, fp, open); 4359 swapstp = init_open_stateid(stp, fp, open);
4348 if (swapstp) { 4360 if (swapstp) {
4349 nfs4_put_stid(&stp->st_stid); 4361 nfs4_put_stid(&stp->st_stid);
4350 stp = swapstp; 4362 stp = swapstp;
4351 mutex_lock(&stp->st_mutex);
4352 status = nfs4_upgrade_open(rqstp, fp, current_fh, 4363 status = nfs4_upgrade_open(rqstp, fp, current_fh,
4353 stp, open); 4364 stp, open);
4354 if (status) { 4365 if (status) {
@@ -4357,7 +4368,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
4357 } 4368 }
4358 goto upgrade_out; 4369 goto upgrade_out;
4359 } 4370 }
4360 mutex_lock(&stp->st_mutex);
4361 status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); 4371 status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
4362 if (status) { 4372 if (status) {
4363 mutex_unlock(&stp->st_mutex); 4373 mutex_unlock(&stp->st_mutex);