@@ -4903,14 +4903,39 @@ nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4903
4903
return nfs_ok ;
4904
4904
}
4905
4905
4906
+ static __be32
4907
+ nfsd4_free_lock_stateid (stateid_t * stateid , struct nfs4_stid * s )
4908
+ {
4909
+ struct nfs4_ol_stateid * stp = openlockstateid (s );
4910
+ __be32 ret ;
4911
+
4912
+ mutex_lock (& stp -> st_mutex );
4913
+
4914
+ ret = check_stateid_generation (stateid , & s -> sc_stateid , 1 );
4915
+ if (ret )
4916
+ goto out ;
4917
+
4918
+ ret = nfserr_locks_held ;
4919
+ if (check_for_locks (stp -> st_stid .sc_file ,
4920
+ lockowner (stp -> st_stateowner )))
4921
+ goto out ;
4922
+
4923
+ release_lock_stateid (stp );
4924
+ ret = nfs_ok ;
4925
+
4926
+ out :
4927
+ mutex_unlock (& stp -> st_mutex );
4928
+ nfs4_put_stid (s );
4929
+ return ret ;
4930
+ }
4931
+
4906
4932
__be32
4907
4933
nfsd4_free_stateid (struct svc_rqst * rqstp , struct nfsd4_compound_state * cstate ,
4908
4934
struct nfsd4_free_stateid * free_stateid )
4909
4935
{
4910
4936
stateid_t * stateid = & free_stateid -> fr_stateid ;
4911
4937
struct nfs4_stid * s ;
4912
4938
struct nfs4_delegation * dp ;
4913
- struct nfs4_ol_stateid * stp ;
4914
4939
struct nfs4_client * cl = cstate -> session -> se_client ;
4915
4940
__be32 ret = nfserr_bad_stateid ;
4916
4941
@@ -4929,18 +4954,9 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4929
4954
ret = nfserr_locks_held ;
4930
4955
break ;
4931
4956
case NFS4_LOCK_STID :
4932
- ret = check_stateid_generation (stateid , & s -> sc_stateid , 1 );
4933
- if (ret )
4934
- break ;
4935
- stp = openlockstateid (s );
4936
- ret = nfserr_locks_held ;
4937
- if (check_for_locks (stp -> st_stid .sc_file ,
4938
- lockowner (stp -> st_stateowner )))
4939
- break ;
4940
- WARN_ON (!unhash_lock_stateid (stp ));
4957
+ atomic_inc (& s -> sc_count );
4941
4958
spin_unlock (& cl -> cl_lock );
4942
- nfs4_put_stid (s );
4943
- ret = nfs_ok ;
4959
+ ret = nfsd4_free_lock_stateid (stateid , s );
4944
4960
goto out ;
4945
4961
case NFS4_REVOKED_DELEG_STID :
4946
4962
dp = delegstateid (s );
@@ -5507,15 +5523,17 @@ static __be32
5507
5523
lookup_or_create_lock_state (struct nfsd4_compound_state * cstate ,
5508
5524
struct nfs4_ol_stateid * ost ,
5509
5525
struct nfsd4_lock * lock ,
5510
- struct nfs4_ol_stateid * * lst , bool * new )
5526
+ struct nfs4_ol_stateid * * plst , bool * new )
5511
5527
{
5512
5528
__be32 status ;
5513
5529
struct nfs4_file * fi = ost -> st_stid .sc_file ;
5514
5530
struct nfs4_openowner * oo = openowner (ost -> st_stateowner );
5515
5531
struct nfs4_client * cl = oo -> oo_owner .so_client ;
5516
5532
struct inode * inode = d_inode (cstate -> current_fh .fh_dentry );
5517
5533
struct nfs4_lockowner * lo ;
5534
+ struct nfs4_ol_stateid * lst ;
5518
5535
unsigned int strhashval ;
5536
+ bool hashed ;
5519
5537
5520
5538
lo = find_lockowner_str (cl , & lock -> lk_new_owner );
5521
5539
if (!lo ) {
@@ -5531,12 +5549,27 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
5531
5549
goto out ;
5532
5550
}
5533
5551
5534
- * lst = find_or_create_lock_stateid (lo , fi , inode , ost , new );
5535
- if (* lst == NULL ) {
5552
+ retry :
5553
+ lst = find_or_create_lock_stateid (lo , fi , inode , ost , new );
5554
+ if (lst == NULL ) {
5536
5555
status = nfserr_jukebox ;
5537
5556
goto out ;
5538
5557
}
5558
+
5559
+ mutex_lock (& lst -> st_mutex );
5560
+
5561
+ /* See if it's still hashed to avoid race with FREE_STATEID */
5562
+ spin_lock (& cl -> cl_lock );
5563
+ hashed = !list_empty (& lst -> st_perfile );
5564
+ spin_unlock (& cl -> cl_lock );
5565
+
5566
+ if (!hashed ) {
5567
+ mutex_unlock (& lst -> st_mutex );
5568
+ nfs4_put_stid (& lst -> st_stid );
5569
+ goto retry ;
5570
+ }
5539
5571
status = nfs_ok ;
5572
+ * plst = lst ;
5540
5573
out :
5541
5574
nfs4_put_stateowner (& lo -> lo_owner );
5542
5575
return status ;
@@ -5603,8 +5636,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5603
5636
goto out ;
5604
5637
status = lookup_or_create_lock_state (cstate , open_stp , lock ,
5605
5638
& lock_stp , & new );
5606
- if (status == nfs_ok )
5607
- mutex_lock (& lock_stp -> st_mutex );
5608
5639
} else {
5609
5640
status = nfs4_preprocess_seqid_op (cstate ,
5610
5641
lock -> lk_old_lock_seqid ,
0 commit comments