diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-06-16 23:25:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-06-16 23:25:52 -0400 |
commit | 41ef72181a9fde78f13d0966e3019fb37f6058e4 (patch) | |
tree | a2f6d64b8c9ffb4b2e59042891578eef91764113 /fs | |
parent | 9c514bedbe6948f31d29c53aceb9234c1484ae69 (diff) | |
parent | 8c7245abda877d4689b3371db8ae2a4400d7d9ce (diff) |
Merge tag 'nfsd-4.7-1' of git://linux-nfs.org/~bfields/linux
Pull nfsd bugfixes from Bruce Fields:
"Oleg Drokin found and fixed races in the nfsd4 state code that go back
to the big nfs4_lock_state removal around 3.17 (but that were also
probably hard to reproduce before client changes in 3.20 allowed the
client to perform parallel opens).
Also fix a 4.1 backchannel crash due to rpc multipath changes in 4.6.
Trond acked the client-side rpc fixes going through my tree"
* tag 'nfsd-4.7-1' of git://linux-nfs.org/~bfields/linux:
nfsd: Make init_open_stateid() a bit more whole
nfsd: Extend the mutex holding region around in nfsd4_process_open2()
nfsd: Always lock state exclusively.
rpc: share one xps between all backchannels
nfsd4/rpc: move backchannel create logic into rpc code
SUNRPC: fix xprt leak on xps allocation failure
nfsd: Fix NFSD_MDS_PR_KEY on 32-bit by adding ULL postfix
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/blocklayout.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 18 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 67 | ||||
-rw-r--r-- | fs/nfsd/state.h | 2 |
4 files changed, 40 insertions, 49 deletions
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c index e55b5242614d..31f3df193bdb 100644 --- a/fs/nfsd/blocklayout.c +++ b/fs/nfsd/blocklayout.c | |||
@@ -290,7 +290,7 @@ out_free_buf: | |||
290 | return error; | 290 | return error; |
291 | } | 291 | } |
292 | 292 | ||
293 | #define NFSD_MDS_PR_KEY 0x0100000000000000 | 293 | #define NFSD_MDS_PR_KEY 0x0100000000000000ULL |
294 | 294 | ||
295 | /* | 295 | /* |
296 | * We use the client ID as a unique key for the reservations. | 296 | * We use the client ID as a unique key for the reservations. |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 7389cb1d7409..04c68d900324 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -710,22 +710,6 @@ static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc | |||
710 | } | 710 | } |
711 | } | 711 | } |
712 | 712 | ||
713 | static struct rpc_clnt *create_backchannel_client(struct rpc_create_args *args) | ||
714 | { | ||
715 | struct rpc_xprt *xprt; | ||
716 | |||
717 | if (args->protocol != XPRT_TRANSPORT_BC_TCP) | ||
718 | return rpc_create(args); | ||
719 | |||
720 | xprt = args->bc_xprt->xpt_bc_xprt; | ||
721 | if (xprt) { | ||
722 | xprt_get(xprt); | ||
723 | return rpc_create_xprt(args, xprt); | ||
724 | } | ||
725 | |||
726 | return rpc_create(args); | ||
727 | } | ||
728 | |||
729 | static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) | 713 | static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) |
730 | { | 714 | { |
731 | int maxtime = max_cb_time(clp->net); | 715 | int maxtime = max_cb_time(clp->net); |
@@ -768,7 +752,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c | |||
768 | args.authflavor = ses->se_cb_sec.flavor; | 752 | args.authflavor = ses->se_cb_sec.flavor; |
769 | } | 753 | } |
770 | /* Create RPC client */ | 754 | /* Create RPC client */ |
771 | client = create_backchannel_client(&args); | 755 | client = rpc_create(&args); |
772 | if (IS_ERR(client)) { | 756 | if (IS_ERR(client)) { |
773 | dprintk("NFSD: couldn't create callback client: %ld\n", | 757 | dprintk("NFSD: couldn't create callback client: %ld\n", |
774 | PTR_ERR(client)); | 758 | PTR_ERR(client)); |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f5f82e145018..70d0b9b33031 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -3480,12 +3480,17 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, | |||
3480 | } | 3480 | } |
3481 | 3481 | ||
3482 | static struct nfs4_ol_stateid * | 3482 | static struct nfs4_ol_stateid * |
3483 | init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, | 3483 | init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open) |
3484 | struct nfsd4_open *open) | ||
3485 | { | 3484 | { |
3486 | 3485 | ||
3487 | struct nfs4_openowner *oo = open->op_openowner; | 3486 | struct nfs4_openowner *oo = open->op_openowner; |
3488 | struct nfs4_ol_stateid *retstp = NULL; | 3487 | struct nfs4_ol_stateid *retstp = NULL; |
3488 | struct nfs4_ol_stateid *stp; | ||
3489 | |||
3490 | stp = open->op_stp; | ||
3491 | /* We are moving these outside of the spinlocks to avoid the warnings */ | ||
3492 | mutex_init(&stp->st_mutex); | ||
3493 | mutex_lock(&stp->st_mutex); | ||
3489 | 3494 | ||
3490 | spin_lock(&oo->oo_owner.so_client->cl_lock); | 3495 | spin_lock(&oo->oo_owner.so_client->cl_lock); |
3491 | spin_lock(&fp->fi_lock); | 3496 | spin_lock(&fp->fi_lock); |
@@ -3493,6 +3498,8 @@ init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, | |||
3493 | retstp = nfsd4_find_existing_open(fp, open); | 3498 | retstp = nfsd4_find_existing_open(fp, open); |
3494 | if (retstp) | 3499 | if (retstp) |
3495 | goto out_unlock; | 3500 | goto out_unlock; |
3501 | |||
3502 | open->op_stp = NULL; | ||
3496 | atomic_inc(&stp->st_stid.sc_count); | 3503 | atomic_inc(&stp->st_stid.sc_count); |
3497 | stp->st_stid.sc_type = NFS4_OPEN_STID; | 3504 | stp->st_stid.sc_type = NFS4_OPEN_STID; |
3498 | INIT_LIST_HEAD(&stp->st_locks); | 3505 | INIT_LIST_HEAD(&stp->st_locks); |
@@ -3502,14 +3509,19 @@ init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, | |||
3502 | stp->st_access_bmap = 0; | 3509 | stp->st_access_bmap = 0; |
3503 | stp->st_deny_bmap = 0; | 3510 | stp->st_deny_bmap = 0; |
3504 | stp->st_openstp = NULL; | 3511 | stp->st_openstp = NULL; |
3505 | init_rwsem(&stp->st_rwsem); | ||
3506 | list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); | 3512 | list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); |
3507 | list_add(&stp->st_perfile, &fp->fi_stateids); | 3513 | list_add(&stp->st_perfile, &fp->fi_stateids); |
3508 | 3514 | ||
3509 | out_unlock: | 3515 | out_unlock: |
3510 | spin_unlock(&fp->fi_lock); | 3516 | spin_unlock(&fp->fi_lock); |
3511 | spin_unlock(&oo->oo_owner.so_client->cl_lock); | 3517 | spin_unlock(&oo->oo_owner.so_client->cl_lock); |
3512 | return retstp; | 3518 | if (retstp) { |
3519 | mutex_lock(&retstp->st_mutex); | ||
3520 | /* To keep mutex tracking happy */ | ||
3521 | mutex_unlock(&stp->st_mutex); | ||
3522 | stp = retstp; | ||
3523 | } | ||
3524 | return stp; | ||
3513 | } | 3525 | } |
3514 | 3526 | ||
3515 | /* | 3527 | /* |
@@ -4305,7 +4317,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
4305 | struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; | 4317 | struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; |
4306 | struct nfs4_file *fp = NULL; | 4318 | struct nfs4_file *fp = NULL; |
4307 | struct nfs4_ol_stateid *stp = NULL; | 4319 | struct nfs4_ol_stateid *stp = NULL; |
4308 | struct nfs4_ol_stateid *swapstp = NULL; | ||
4309 | struct nfs4_delegation *dp = NULL; | 4320 | struct nfs4_delegation *dp = NULL; |
4310 | __be32 status; | 4321 | __be32 status; |
4311 | 4322 | ||
@@ -4335,32 +4346,28 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
4335 | */ | 4346 | */ |
4336 | if (stp) { | 4347 | if (stp) { |
4337 | /* Stateid was found, this is an OPEN upgrade */ | 4348 | /* Stateid was found, this is an OPEN upgrade */ |
4338 | down_read(&stp->st_rwsem); | 4349 | mutex_lock(&stp->st_mutex); |
4339 | status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); | 4350 | status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); |
4340 | if (status) { | 4351 | if (status) { |
4341 | up_read(&stp->st_rwsem); | 4352 | mutex_unlock(&stp->st_mutex); |
4342 | goto out; | 4353 | goto out; |
4343 | } | 4354 | } |
4344 | } else { | 4355 | } else { |
4345 | stp = open->op_stp; | 4356 | /* stp is returned locked. */ |
4346 | open->op_stp = NULL; | 4357 | stp = init_open_stateid(fp, open); |
4347 | swapstp = init_open_stateid(stp, fp, open); | 4358 | /* See if we lost the race to some other thread */ |
4348 | if (swapstp) { | 4359 | if (stp->st_access_bmap != 0) { |
4349 | nfs4_put_stid(&stp->st_stid); | ||
4350 | stp = swapstp; | ||
4351 | down_read(&stp->st_rwsem); | ||
4352 | status = nfs4_upgrade_open(rqstp, fp, current_fh, | 4360 | status = nfs4_upgrade_open(rqstp, fp, current_fh, |
4353 | stp, open); | 4361 | stp, open); |
4354 | if (status) { | 4362 | if (status) { |
4355 | up_read(&stp->st_rwsem); | 4363 | mutex_unlock(&stp->st_mutex); |
4356 | goto out; | 4364 | goto out; |
4357 | } | 4365 | } |
4358 | goto upgrade_out; | 4366 | goto upgrade_out; |
4359 | } | 4367 | } |
4360 | down_read(&stp->st_rwsem); | ||
4361 | status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); | 4368 | status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); |
4362 | if (status) { | 4369 | if (status) { |
4363 | up_read(&stp->st_rwsem); | 4370 | mutex_unlock(&stp->st_mutex); |
4364 | release_open_stateid(stp); | 4371 | release_open_stateid(stp); |
4365 | goto out; | 4372 | goto out; |
4366 | } | 4373 | } |
@@ -4372,7 +4379,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
4372 | } | 4379 | } |
4373 | upgrade_out: | 4380 | upgrade_out: |
4374 | nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); | 4381 | nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); |
4375 | up_read(&stp->st_rwsem); | 4382 | mutex_unlock(&stp->st_mutex); |
4376 | 4383 | ||
4377 | if (nfsd4_has_session(&resp->cstate)) { | 4384 | if (nfsd4_has_session(&resp->cstate)) { |
4378 | if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { | 4385 | if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { |
@@ -4977,12 +4984,12 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_ | |||
4977 | * revoked delegations are kept only for free_stateid. | 4984 | * revoked delegations are kept only for free_stateid. |
4978 | */ | 4985 | */ |
4979 | return nfserr_bad_stateid; | 4986 | return nfserr_bad_stateid; |
4980 | down_write(&stp->st_rwsem); | 4987 | mutex_lock(&stp->st_mutex); |
4981 | status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); | 4988 | status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); |
4982 | if (status == nfs_ok) | 4989 | if (status == nfs_ok) |
4983 | status = nfs4_check_fh(current_fh, &stp->st_stid); | 4990 | status = nfs4_check_fh(current_fh, &stp->st_stid); |
4984 | if (status != nfs_ok) | 4991 | if (status != nfs_ok) |
4985 | up_write(&stp->st_rwsem); | 4992 | mutex_unlock(&stp->st_mutex); |
4986 | return status; | 4993 | return status; |
4987 | } | 4994 | } |
4988 | 4995 | ||
@@ -5030,7 +5037,7 @@ static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cs | |||
5030 | return status; | 5037 | return status; |
5031 | oo = openowner(stp->st_stateowner); | 5038 | oo = openowner(stp->st_stateowner); |
5032 | if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { | 5039 | if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { |
5033 | up_write(&stp->st_rwsem); | 5040 | mutex_unlock(&stp->st_mutex); |
5034 | nfs4_put_stid(&stp->st_stid); | 5041 | nfs4_put_stid(&stp->st_stid); |
5035 | return nfserr_bad_stateid; | 5042 | return nfserr_bad_stateid; |
5036 | } | 5043 | } |
@@ -5062,12 +5069,12 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5062 | oo = openowner(stp->st_stateowner); | 5069 | oo = openowner(stp->st_stateowner); |
5063 | status = nfserr_bad_stateid; | 5070 | status = nfserr_bad_stateid; |
5064 | if (oo->oo_flags & NFS4_OO_CONFIRMED) { | 5071 | if (oo->oo_flags & NFS4_OO_CONFIRMED) { |
5065 | up_write(&stp->st_rwsem); | 5072 | mutex_unlock(&stp->st_mutex); |
5066 | goto put_stateid; | 5073 | goto put_stateid; |
5067 | } | 5074 | } |
5068 | oo->oo_flags |= NFS4_OO_CONFIRMED; | 5075 | oo->oo_flags |= NFS4_OO_CONFIRMED; |
5069 | nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); | 5076 | nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); |
5070 | up_write(&stp->st_rwsem); | 5077 | mutex_unlock(&stp->st_mutex); |
5071 | dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", | 5078 | dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", |
5072 | __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); | 5079 | __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); |
5073 | 5080 | ||
@@ -5143,7 +5150,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
5143 | nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); | 5150 | nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); |
5144 | status = nfs_ok; | 5151 | status = nfs_ok; |
5145 | put_stateid: | 5152 | put_stateid: |
5146 | up_write(&stp->st_rwsem); | 5153 | mutex_unlock(&stp->st_mutex); |
5147 | nfs4_put_stid(&stp->st_stid); | 5154 | nfs4_put_stid(&stp->st_stid); |
5148 | out: | 5155 | out: |
5149 | nfsd4_bump_seqid(cstate, status); | 5156 | nfsd4_bump_seqid(cstate, status); |
@@ -5196,7 +5203,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5196 | if (status) | 5203 | if (status) |
5197 | goto out; | 5204 | goto out; |
5198 | nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); | 5205 | nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); |
5199 | up_write(&stp->st_rwsem); | 5206 | mutex_unlock(&stp->st_mutex); |
5200 | 5207 | ||
5201 | nfsd4_close_open_stateid(stp); | 5208 | nfsd4_close_open_stateid(stp); |
5202 | 5209 | ||
@@ -5422,7 +5429,7 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, | |||
5422 | stp->st_access_bmap = 0; | 5429 | stp->st_access_bmap = 0; |
5423 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 5430 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
5424 | stp->st_openstp = open_stp; | 5431 | stp->st_openstp = open_stp; |
5425 | init_rwsem(&stp->st_rwsem); | 5432 | mutex_init(&stp->st_mutex); |
5426 | list_add(&stp->st_locks, &open_stp->st_locks); | 5433 | list_add(&stp->st_locks, &open_stp->st_locks); |
5427 | list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); | 5434 | list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); |
5428 | spin_lock(&fp->fi_lock); | 5435 | spin_lock(&fp->fi_lock); |
@@ -5591,7 +5598,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5591 | &open_stp, nn); | 5598 | &open_stp, nn); |
5592 | if (status) | 5599 | if (status) |
5593 | goto out; | 5600 | goto out; |
5594 | up_write(&open_stp->st_rwsem); | 5601 | mutex_unlock(&open_stp->st_mutex); |
5595 | open_sop = openowner(open_stp->st_stateowner); | 5602 | open_sop = openowner(open_stp->st_stateowner); |
5596 | status = nfserr_bad_stateid; | 5603 | status = nfserr_bad_stateid; |
5597 | if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, | 5604 | if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, |
@@ -5600,7 +5607,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5600 | status = lookup_or_create_lock_state(cstate, open_stp, lock, | 5607 | status = lookup_or_create_lock_state(cstate, open_stp, lock, |
5601 | &lock_stp, &new); | 5608 | &lock_stp, &new); |
5602 | if (status == nfs_ok) | 5609 | if (status == nfs_ok) |
5603 | down_write(&lock_stp->st_rwsem); | 5610 | mutex_lock(&lock_stp->st_mutex); |
5604 | } else { | 5611 | } else { |
5605 | status = nfs4_preprocess_seqid_op(cstate, | 5612 | status = nfs4_preprocess_seqid_op(cstate, |
5606 | lock->lk_old_lock_seqid, | 5613 | lock->lk_old_lock_seqid, |
@@ -5704,7 +5711,7 @@ out: | |||
5704 | seqid_mutating_err(ntohl(status))) | 5711 | seqid_mutating_err(ntohl(status))) |
5705 | lock_sop->lo_owner.so_seqid++; | 5712 | lock_sop->lo_owner.so_seqid++; |
5706 | 5713 | ||
5707 | up_write(&lock_stp->st_rwsem); | 5714 | mutex_unlock(&lock_stp->st_mutex); |
5708 | 5715 | ||
5709 | /* | 5716 | /* |
5710 | * If this is a new, never-before-used stateid, and we are | 5717 | * If this is a new, never-before-used stateid, and we are |
@@ -5874,7 +5881,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5874 | fput: | 5881 | fput: |
5875 | fput(filp); | 5882 | fput(filp); |
5876 | put_stateid: | 5883 | put_stateid: |
5877 | up_write(&stp->st_rwsem); | 5884 | mutex_unlock(&stp->st_mutex); |
5878 | nfs4_put_stid(&stp->st_stid); | 5885 | nfs4_put_stid(&stp->st_stid); |
5879 | out: | 5886 | out: |
5880 | nfsd4_bump_seqid(cstate, status); | 5887 | nfsd4_bump_seqid(cstate, status); |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 986e51e5ceac..64053eadeb81 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -535,7 +535,7 @@ struct nfs4_ol_stateid { | |||
535 | unsigned char st_access_bmap; | 535 | unsigned char st_access_bmap; |
536 | unsigned char st_deny_bmap; | 536 | unsigned char st_deny_bmap; |
537 | struct nfs4_ol_stateid *st_openstp; | 537 | struct nfs4_ol_stateid *st_openstp; |
538 | struct rw_semaphore st_rwsem; | 538 | struct mutex st_mutex; |
539 | }; | 539 | }; |
540 | 540 | ||
541 | static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) | 541 | static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) |