@@ -1359,21 +1359,47 @@ static void destroy_delegation(struct nfs4_delegation *dp)
1359
1359
destroy_unhashed_deleg (dp );
1360
1360
}
1361
1361
1362
+ /**
1363
+ * revoke_delegation - perform nfs4 delegation structure cleanup
1364
+ * @dp: pointer to the delegation
1365
+ *
1366
+ * This function assumes that it's called either from the administrative
1367
+ * interface (nfsd4_revoke_states()) that's revoking a specific delegation
1368
+ * stateid or it's called from a laundromat thread (nfsd4_landromat()) that
1369
+ * determined that this specific state has expired and needs to be revoked
1370
+ * (both mark state with the appropriate stid sc_status mode). It is also
1371
+ * assumed that a reference was taken on the @dp state.
1372
+ *
1373
+ * If this function finds that the @dp state is SC_STATUS_FREED it means
1374
+ * that a FREE_STATEID operation for this stateid has been processed and
1375
+ * we can proceed to removing it from recalled list. However, if @dp state
1376
+ * isn't marked SC_STATUS_FREED, it means we need place it on the cl_revoked
1377
+ * list and wait for the FREE_STATEID to arrive from the client. At the same
1378
+ * time, we need to mark it as SC_STATUS_FREEABLE to indicate to the
1379
+ * nfsd4_free_stateid() function that this stateid has already been added
1380
+ * to the cl_revoked list and that nfsd4_free_stateid() is now responsible
1381
+ * for removing it from the list. Inspection of where the delegation state
1382
+ * in the revocation process is protected by the clp->cl_lock.
1383
+ */
1362
1384
static void revoke_delegation (struct nfs4_delegation * dp )
1363
1385
{
1364
1386
struct nfs4_client * clp = dp -> dl_stid .sc_client ;
1365
1387
1366
1388
WARN_ON (!list_empty (& dp -> dl_recall_lru ));
1389
+ WARN_ON_ONCE (!(dp -> dl_stid .sc_status &
1390
+ (SC_STATUS_REVOKED | SC_STATUS_ADMIN_REVOKED )));
1367
1391
1368
1392
trace_nfsd_stid_revoke (& dp -> dl_stid );
1369
1393
1370
- if (dp -> dl_stid .sc_status &
1371
- (SC_STATUS_REVOKED | SC_STATUS_ADMIN_REVOKED )) {
1372
- spin_lock (& clp -> cl_lock );
1373
- refcount_inc (& dp -> dl_stid .sc_count );
1374
- list_add (& dp -> dl_recall_lru , & clp -> cl_revoked );
1375
- spin_unlock (& clp -> cl_lock );
1394
+ spin_lock (& clp -> cl_lock );
1395
+ if (dp -> dl_stid .sc_status & SC_STATUS_FREED ) {
1396
+ list_del_init (& dp -> dl_recall_lru );
1397
+ goto out ;
1376
1398
}
1399
+ list_add (& dp -> dl_recall_lru , & clp -> cl_revoked );
1400
+ dp -> dl_stid .sc_status |= SC_STATUS_FREEABLE ;
1401
+ out :
1402
+ spin_unlock (& clp -> cl_lock );
1377
1403
destroy_unhashed_deleg (dp );
1378
1404
}
1379
1405
@@ -1780,6 +1806,7 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb)
1780
1806
mutex_unlock (& stp -> st_mutex );
1781
1807
break ;
1782
1808
case SC_TYPE_DELEG :
1809
+ refcount_inc (& stid -> sc_count );
1783
1810
dp = delegstateid (stid );
1784
1811
spin_lock (& state_lock );
1785
1812
if (!unhash_delegation_locked (
@@ -6545,6 +6572,7 @@ nfs4_laundromat(struct nfsd_net *nn)
6545
6572
dp = list_entry (pos , struct nfs4_delegation , dl_recall_lru );
6546
6573
if (!state_expired (& lt , dp -> dl_time ))
6547
6574
break ;
6575
+ refcount_inc (& dp -> dl_stid .sc_count );
6548
6576
unhash_delegation_locked (dp , SC_STATUS_REVOKED );
6549
6577
list_add (& dp -> dl_recall_lru , & reaplist );
6550
6578
}
@@ -7157,7 +7185,9 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
7157
7185
s -> sc_status |= SC_STATUS_CLOSED ;
7158
7186
spin_unlock (& s -> sc_lock );
7159
7187
dp = delegstateid (s );
7160
- list_del_init (& dp -> dl_recall_lru );
7188
+ if (s -> sc_status & SC_STATUS_FREEABLE )
7189
+ list_del_init (& dp -> dl_recall_lru );
7190
+ s -> sc_status |= SC_STATUS_FREED ;
7161
7191
spin_unlock (& cl -> cl_lock );
7162
7192
nfs4_put_stid (s );
7163
7193
ret = nfs_ok ;
@@ -7487,7 +7517,9 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
7487
7517
if ((status = fh_verify (rqstp , & cstate -> current_fh , S_IFREG , 0 )))
7488
7518
return status ;
7489
7519
7490
- status = nfsd4_lookup_stateid (cstate , stateid , SC_TYPE_DELEG , 0 , & s , nn );
7520
+ status = nfsd4_lookup_stateid (cstate , stateid , SC_TYPE_DELEG ,
7521
+ SC_STATUS_REVOKED | SC_STATUS_FREEABLE ,
7522
+ & s , nn );
7491
7523
if (status )
7492
7524
goto out ;
7493
7525
dp = delegstateid (s );
@@ -8684,7 +8716,7 @@ nfs4_state_shutdown_net(struct net *net)
8684
8716
struct nfsd_net * nn = net_generic (net , nfsd_net_id );
8685
8717
8686
8718
shrinker_free (nn -> nfsd_client_shrinker );
8687
- cancel_work (& nn -> nfsd_shrinker_work );
8719
+ cancel_work_sync (& nn -> nfsd_shrinker_work );
8688
8720
cancel_delayed_work_sync (& nn -> laundromat_work );
8689
8721
locks_end_grace (& nn -> nfsd4_manager );
8690
8722
0 commit comments