Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

nfsd: convert global state_lock to per-net deleg_lock

Replace the global state_lock spinlock with a per-nfsd_net deleg_lock.
The state_lock was only used to protect delegation lifecycle operations
(the del_recall_lru list and delegation hash/unhash), all of which are
scoped to a single network namespace. Making the lock per-net removes
a source of unnecessary contention between containers.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

authored by

Jeff Layton and committed by
Chuck Lever
8be12e0c facc4e3c

+36 -31
+3
fs/nfsd/netns.h
··· 99 99 */ 100 100 struct list_head client_lru; 101 101 struct list_head close_lru; 102 + 103 + /* protects del_recall_lru and delegation hash/unhash */ 104 + spinlock_t deleg_lock ____cacheline_aligned; 102 105 struct list_head del_recall_lru; 103 106 104 107 /* protected by blocked_locks_lock */
+32 -30
fs/nfsd/nfs4state.c
··· 93 93 94 94 /* Locking: */ 95 95 96 - /* 97 - * Currently used for the del_recall_lru and file hash table. In an 98 - * effort to decrease the scope of the client_mutex, this spinlock may 99 - * eventually cover more: 100 - */ 101 - static DEFINE_SPINLOCK(state_lock); 102 - 103 96 enum nfsd4_st_mutex_lock_subclass { 104 97 OPEN_STATEID_MUTEX = 0, 105 98 LOCK_STATEID_MUTEX = 1, ··· 1288 1295 { 1289 1296 struct nfs4_delegation *searchdp = NULL; 1290 1297 struct nfs4_client *searchclp = NULL; 1298 + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1291 1299 1292 - lockdep_assert_held(&state_lock); 1300 + lockdep_assert_held(&nn->deleg_lock); 1293 1301 lockdep_assert_held(&fp->fi_lock); 1294 1302 1295 1303 list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { ··· 1319 1325 hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 1320 1326 { 1321 1327 struct nfs4_client *clp = dp->dl_stid.sc_client; 1328 + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1322 1329 1323 - lockdep_assert_held(&state_lock); 1330 + lockdep_assert_held(&nn->deleg_lock); 1324 1331 lockdep_assert_held(&fp->fi_lock); 1325 1332 lockdep_assert_held(&clp->cl_lock); 1326 1333 ··· 1343 1348 unhash_delegation_locked(struct nfs4_delegation *dp, unsigned short statusmask) 1344 1349 { 1345 1350 struct nfs4_file *fp = dp->dl_stid.sc_file; 1351 + struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 1352 + nfsd_net_id); 1346 1353 1347 - lockdep_assert_held(&state_lock); 1354 + lockdep_assert_held(&nn->deleg_lock); 1348 1355 1349 1356 if (!delegation_hashed(dp)) 1350 1357 return false; ··· 1371 1374 static void destroy_delegation(struct nfs4_delegation *dp) 1372 1375 { 1373 1376 bool unhashed; 1377 + struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 1378 + nfsd_net_id); 1374 1379 1375 - spin_lock(&state_lock); 1380 + spin_lock(&nn->deleg_lock); 1376 1381 unhashed = unhash_delegation_locked(dp, SC_STATUS_CLOSED); 1377 - spin_unlock(&state_lock); 1382 + spin_unlock(&nn->deleg_lock); 1378 1383 if (unhashed) 1379 1384 destroy_unhashed_deleg(dp); 1380 1385 } ··· 1839 1840 case SC_TYPE_DELEG: 1840 1841 refcount_inc(&stid->sc_count); 1841 1842 dp = delegstateid(stid); 1842 - spin_lock(&state_lock); 1843 + spin_lock(&nn->deleg_lock); 1843 1844 if (!unhash_delegation_locked( 1844 1845 dp, SC_STATUS_ADMIN_REVOKED)) 1845 1846 dp = NULL; 1846 - spin_unlock(&state_lock); 1847 + spin_unlock(&nn->deleg_lock); 1847 1848 if (dp) 1848 1849 revoke_delegation(dp); 1849 1850 break; ··· 2509 2510 struct nfs4_delegation *dp; 2510 2511 LIST_HEAD(reaplist); 2511 2512 2512 - spin_lock(&state_lock); 2513 + spin_lock(&nn->deleg_lock); 2513 2514 while (!list_empty(&clp->cl_delegations)) { 2514 2515 dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 2515 2516 unhash_delegation_locked(dp, SC_STATUS_CLOSED); 2516 2517 list_add(&dp->dl_recall_lru, &reaplist); 2517 2518 } 2518 - spin_unlock(&state_lock); 2519 + spin_unlock(&nn->deleg_lock); 2519 2520 while (!list_empty(&reaplist)) { 2520 2521 dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 2521 2522 list_del_init(&dp->dl_recall_lru); ··· 5426 5427 * If the dl_time != 0, then we know that it has already been 5427 5428 * queued for a lease break. Don't queue it again. 5428 5429 */ 5429 - spin_lock(&state_lock); 5430 + spin_lock(&nn->deleg_lock); 5430 5431 if (delegation_hashed(dp) && dp->dl_time == 0) { 5431 5432 dp->dl_time = ktime_get_boottime_seconds(); 5432 5433 list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 5433 5434 } 5434 - spin_unlock(&state_lock); 5435 + spin_unlock(&nn->deleg_lock); 5435 5436 } 5436 5437 5437 5438 static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, ··· 6063 6064 { 6064 6065 bool deleg_ts = nfsd4_want_deleg_timestamps(open); 6065 6066 struct nfs4_client *clp = stp->st_stid.sc_client; 6067 + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 6066 6068 struct nfs4_file *fp = stp->st_stid.sc_file; 6067 6069 struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate; 6068 6070 struct nfs4_delegation *dp; ··· 6123 6123 return ERR_PTR(-EOPNOTSUPP); 6124 6124 } 6125 6125 6126 - spin_lock(&state_lock); 6126 + spin_lock(&nn->deleg_lock); 6127 6127 spin_lock(&fp->fi_lock); 6128 6128 if (nfs4_delegation_exists(clp, fp)) 6129 6129 status = -EAGAIN; ··· 6138 6138 } else 6139 6139 fp->fi_delegees++; 6140 6140 spin_unlock(&fp->fi_lock); 6141 - spin_unlock(&state_lock); 6141 + spin_unlock(&nn->deleg_lock); 6142 6142 if (nf) 6143 6143 nfsd_file_put(nf); 6144 6144 if (status) ··· 6182 6182 if (fp->fi_had_conflict) 6183 6183 goto out_unlock; 6184 6184 6185 - spin_lock(&state_lock); 6185 + spin_lock(&nn->deleg_lock); 6186 6186 spin_lock(&clp->cl_lock); 6187 6187 spin_lock(&fp->fi_lock); 6188 6188 status = hash_delegation_locked(dp, fp); 6189 6189 spin_unlock(&fp->fi_lock); 6190 6190 spin_unlock(&clp->cl_lock); 6191 - spin_unlock(&state_lock); 6191 + spin_unlock(&nn->deleg_lock); 6192 6192 6193 6193 if (status) 6194 6194 goto out_unlock; ··· 6964 6964 6965 6965 nfs40_clean_admin_revoked(nn, &lt); 6966 6966 6967 - spin_lock(&state_lock); 6967 + spin_lock(&nn->deleg_lock); 6968 6968 list_for_each_safe(pos, next, &nn->del_recall_lru) { 6969 6969 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 6970 6970 if (!state_expired(&lt, dp->dl_time)) ··· 6973 6973 unhash_delegation_locked(dp, SC_STATUS_REVOKED); 6974 6974 list_add(&dp->dl_recall_lru, &reaplist); 6975 6975 } 6976 - spin_unlock(&state_lock); 6976 + spin_unlock(&nn->deleg_lock); 6977 6977 while (!list_empty(&reaplist)) { 6978 6978 dp = list_first_entry(&reaplist, struct nfs4_delegation, 6979 6979 dl_recall_lru); ··· 8996 8996 INIT_LIST_HEAD(&nn->client_lru); 8997 8997 INIT_LIST_HEAD(&nn->close_lru); 8998 8998 INIT_LIST_HEAD(&nn->del_recall_lru); 8999 + spin_lock_init(&nn->deleg_lock); 8999 9000 spin_lock_init(&nn->client_lock); 9000 9001 spin_lock_init(&nn->s2s_cp_lock); 9001 9002 idr_init(&nn->s2s_cp_stateids); ··· 9128 9127 locks_end_grace(&nn->nfsd4_manager); 9129 9128 9130 9129 INIT_LIST_HEAD(&reaplist); 9131 - spin_lock(&state_lock); 9130 + spin_lock(&nn->deleg_lock); 9132 9131 list_for_each_safe(pos, next, &nn->del_recall_lru) { 9133 9132 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 9134 9133 unhash_delegation_locked(dp, SC_STATUS_CLOSED); 9135 9134 list_add(&dp->dl_recall_lru, &reaplist); 9136 9135 } 9137 - spin_unlock(&state_lock); 9136 + spin_unlock(&nn->deleg_lock); 9138 9137 list_for_each_safe(pos, next, &reaplist) { 9139 9138 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 9140 9139 list_del_init(&dp->dl_recall_lru); ··· 9457 9456 struct nfsd_file *nf) 9458 9457 { 9459 9458 struct nfs4_client *clp = cstate->clp; 9459 + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 9460 9460 struct nfs4_delegation *dp; 9461 9461 struct file_lease *fl; 9462 9462 struct nfs4_file *fp, *rfp; ··· 9481 9479 } 9482 9480 9483 9481 /* if this client already has one, return that it's unavailable */ 9484 - spin_lock(&state_lock); 9482 + spin_lock(&nn->deleg_lock); 9485 9483 spin_lock(&fp->fi_lock); 9486 9484 /* existing delegation? */ 9487 9485 if (nfs4_delegation_exists(clp, fp)) { ··· 9493 9491 ++fp->fi_delegees; 9494 9492 } 9495 9493 spin_unlock(&fp->fi_lock); 9496 - spin_unlock(&state_lock); 9494 + spin_unlock(&nn->deleg_lock); 9497 9495 9498 9496 if (status) { 9499 9497 put_nfs4_file(fp); ··· 9522 9520 * trying to set a delegation on the same file. If that happens, 9523 9521 * then just say UNAVAIL. 9524 9522 */ 9525 - spin_lock(&state_lock); 9523 + spin_lock(&nn->deleg_lock); 9526 9524 spin_lock(&clp->cl_lock); 9527 9525 spin_lock(&fp->fi_lock); 9528 9526 status = hash_delegation_locked(dp, fp); 9529 9527 spin_unlock(&fp->fi_lock); 9530 9528 spin_unlock(&clp->cl_lock); 9531 - spin_unlock(&state_lock); 9529 + spin_unlock(&nn->deleg_lock); 9532 9530 9533 9531 if (!status) { 9534 9532 put_nfs4_file(fp);
+1 -1
fs/nfsd/state.h
··· 123 123 #define SC_TYPE_LAYOUT BIT(3) 124 124 unsigned short sc_type; 125 125 126 - /* state_lock protects sc_status for delegation stateids. 126 + /* nn->deleg_lock protects sc_status for delegation stateids. 127 127 * ->cl_lock protects sc_status for open and lock stateids. 128 128 * ->st_mutex also protect sc_status for open stateids. 129 129 * ->ls_lock protects sc_status for layout stateids.