Skip to content

Commit 0de4397

Browse files
author
Trond Myklebust
committed
NFS: Convert lookups of the open context to RCU
Reduce contention on the inode->i_lock by ensuring that we use RCU when looking up the NFS open context. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
1 parent 6ba0c4e commit 0de4397

File tree

6 files changed

+56
-38
lines changed

6 files changed

+56
-38
lines changed

fs/nfs/delegation.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ static int nfs_delegation_claim_opens(struct inode *inode,
136136
int err;
137137

138138
again:
139-
spin_lock(&inode->i_lock);
140-
list_for_each_entry(ctx, &nfsi->open_files, list) {
139+
rcu_read_lock();
140+
list_for_each_entry_rcu(ctx, &nfsi->open_files, list) {
141141
state = ctx->state;
142142
if (state == NULL)
143143
continue;
@@ -147,8 +147,9 @@ static int nfs_delegation_claim_opens(struct inode *inode,
147147
continue;
148148
if (!nfs4_stateid_match(&state->stateid, stateid))
149149
continue;
150-
get_nfs_open_context(ctx);
151-
spin_unlock(&inode->i_lock);
150+
if (!get_nfs_open_context(ctx))
151+
continue;
152+
rcu_read_unlock();
152153
sp = state->owner;
153154
/* Block nfs4_proc_unlck */
154155
mutex_lock(&sp->so_delegreturn_mutex);
@@ -164,7 +165,7 @@ static int nfs_delegation_claim_opens(struct inode *inode,
164165
return err;
165166
goto again;
166167
}
167-
spin_unlock(&inode->i_lock);
168+
rcu_read_unlock();
168169
return 0;
169170
}
170171

fs/nfs/inode.c

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -977,9 +977,9 @@ EXPORT_SYMBOL_GPL(alloc_nfs_open_context);
977977

978978
struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
979979
{
980-
if (ctx != NULL)
981-
refcount_inc(&ctx->lock_context.count);
982-
return ctx;
980+
if (ctx != NULL && refcount_inc_not_zero(&ctx->lock_context.count))
981+
return ctx;
982+
return NULL;
983983
}
984984
EXPORT_SYMBOL_GPL(get_nfs_open_context);
985985

@@ -988,21 +988,21 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
988988
struct inode *inode = d_inode(ctx->dentry);
989989
struct super_block *sb = ctx->dentry->d_sb;
990990

991+
if (!refcount_dec_and_test(&ctx->lock_context.count))
992+
return;
991993
if (!list_empty(&ctx->list)) {
992-
if (!refcount_dec_and_lock(&ctx->lock_context.count, &inode->i_lock))
993-
return;
994-
list_del(&ctx->list);
994+
spin_lock(&inode->i_lock);
995+
list_del_rcu(&ctx->list);
995996
spin_unlock(&inode->i_lock);
996-
} else if (!refcount_dec_and_test(&ctx->lock_context.count))
997-
return;
997+
}
998998
if (inode != NULL)
999999
NFS_PROTO(inode)->close_context(ctx, is_sync);
10001000
if (ctx->cred != NULL)
10011001
put_rpccred(ctx->cred);
10021002
dput(ctx->dentry);
10031003
nfs_sb_deactive(sb);
10041004
kfree(ctx->mdsthreshold);
1005-
kfree(ctx);
1005+
kfree_rcu(ctx, rcu_head);
10061006
}
10071007

10081008
void put_nfs_open_context(struct nfs_open_context *ctx)
@@ -1026,10 +1026,7 @@ void nfs_inode_attach_open_context(struct nfs_open_context *ctx)
10261026
struct nfs_inode *nfsi = NFS_I(inode);
10271027

10281028
spin_lock(&inode->i_lock);
1029-
if (ctx->mode & FMODE_WRITE)
1030-
list_add(&ctx->list, &nfsi->open_files);
1031-
else
1032-
list_add_tail(&ctx->list, &nfsi->open_files);
1029+
list_add_tail_rcu(&ctx->list, &nfsi->open_files);
10331030
spin_unlock(&inode->i_lock);
10341031
}
10351032
EXPORT_SYMBOL_GPL(nfs_inode_attach_open_context);
@@ -1050,16 +1047,17 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c
10501047
struct nfs_inode *nfsi = NFS_I(inode);
10511048
struct nfs_open_context *pos, *ctx = NULL;
10521049

1053-
spin_lock(&inode->i_lock);
1054-
list_for_each_entry(pos, &nfsi->open_files, list) {
1050+
rcu_read_lock();
1051+
list_for_each_entry_rcu(pos, &nfsi->open_files, list) {
10551052
if (cred != NULL && pos->cred != cred)
10561053
continue;
10571054
if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode)
10581055
continue;
10591056
ctx = get_nfs_open_context(pos);
1060-
break;
1057+
if (ctx)
1058+
break;
10611059
}
1062-
spin_unlock(&inode->i_lock);
1060+
rcu_read_unlock();
10631061
return ctx;
10641062
}
10651063

@@ -1077,9 +1075,6 @@ void nfs_file_clear_open_context(struct file *filp)
10771075
if (ctx->error < 0)
10781076
invalidate_inode_pages2(inode->i_mapping);
10791077
filp->private_data = NULL;
1080-
spin_lock(&inode->i_lock);
1081-
list_move_tail(&ctx->list, &NFS_I(inode)->open_files);
1082-
spin_unlock(&inode->i_lock);
10831078
put_nfs_open_context_sync(ctx);
10841079
}
10851080
}

fs/nfs/nfs4proc.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1933,23 +1933,41 @@ nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
19331933
return ret;
19341934
}
19351935

1936-
static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state)
1936+
static struct nfs_open_context *
1937+
nfs4_state_find_open_context_mode(struct nfs4_state *state, fmode_t mode)
19371938
{
19381939
struct nfs_inode *nfsi = NFS_I(state->inode);
19391940
struct nfs_open_context *ctx;
19401941

1941-
spin_lock(&state->inode->i_lock);
1942-
list_for_each_entry(ctx, &nfsi->open_files, list) {
1942+
rcu_read_lock();
1943+
list_for_each_entry_rcu(ctx, &nfsi->open_files, list) {
19431944
if (ctx->state != state)
19441945
continue;
1945-
get_nfs_open_context(ctx);
1946-
spin_unlock(&state->inode->i_lock);
1946+
if ((ctx->mode & mode) != mode)
1947+
continue;
1948+
if (!get_nfs_open_context(ctx))
1949+
continue;
1950+
rcu_read_unlock();
19471951
return ctx;
19481952
}
1949-
spin_unlock(&state->inode->i_lock);
1953+
rcu_read_unlock();
19501954
return ERR_PTR(-ENOENT);
19511955
}
19521956

1957+
static struct nfs_open_context *
1958+
nfs4_state_find_open_context(struct nfs4_state *state)
1959+
{
1960+
struct nfs_open_context *ctx;
1961+
1962+
ctx = nfs4_state_find_open_context_mode(state, FMODE_READ|FMODE_WRITE);
1963+
if (!IS_ERR(ctx))
1964+
return ctx;
1965+
ctx = nfs4_state_find_open_context_mode(state, FMODE_WRITE);
1966+
if (!IS_ERR(ctx))
1967+
return ctx;
1968+
return nfs4_state_find_open_context_mode(state, FMODE_READ);
1969+
}
1970+
19531971
static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx,
19541972
struct nfs4_state *state, enum open_claim_type4 claim)
19551973
{

fs/nfs/nfs4state.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,8 +1437,8 @@ void nfs_inode_find_state_and_recover(struct inode *inode,
14371437
struct nfs4_state *state;
14381438
bool found = false;
14391439

1440-
spin_lock(&inode->i_lock);
1441-
list_for_each_entry(ctx, &nfsi->open_files, list) {
1440+
rcu_read_lock();
1441+
list_for_each_entry_rcu(ctx, &nfsi->open_files, list) {
14421442
state = ctx->state;
14431443
if (state == NULL)
14441444
continue;
@@ -1456,7 +1456,7 @@ void nfs_inode_find_state_and_recover(struct inode *inode,
14561456
nfs4_state_mark_reclaim_nograce(clp, state))
14571457
found = true;
14581458
}
1459-
spin_unlock(&inode->i_lock);
1459+
rcu_read_unlock();
14601460

14611461
nfs_inode_find_delegation_state_and_recover(inode, stateid);
14621462
if (found)
@@ -1469,13 +1469,13 @@ static void nfs4_state_mark_open_context_bad(struct nfs4_state *state)
14691469
struct nfs_inode *nfsi = NFS_I(inode);
14701470
struct nfs_open_context *ctx;
14711471

1472-
spin_lock(&inode->i_lock);
1473-
list_for_each_entry(ctx, &nfsi->open_files, list) {
1472+
rcu_read_lock();
1473+
list_for_each_entry_rcu(ctx, &nfsi->open_files, list) {
14741474
if (ctx->state != state)
14751475
continue;
14761476
set_bit(NFS_CONTEXT_BAD, &ctx->flags);
14771477
}
1478-
spin_unlock(&inode->i_lock);
1478+
rcu_read_unlock();
14791479
}
14801480

14811481
static void nfs4_state_mark_recovery_failed(struct nfs4_state *state, int error)

fs/nfs/pnfs.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,7 @@ bool pnfs_roc(struct inode *ino,
13391339
if (!nfs_have_layout(ino))
13401340
return false;
13411341
retry:
1342+
rcu_read_lock();
13421343
spin_lock(&ino->i_lock);
13431344
lo = nfsi->layout;
13441345
if (!lo || !pnfs_layout_is_valid(lo) ||
@@ -1349,6 +1350,7 @@ bool pnfs_roc(struct inode *ino,
13491350
pnfs_get_layout_hdr(lo);
13501351
if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) {
13511352
spin_unlock(&ino->i_lock);
1353+
rcu_read_unlock();
13521354
wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN,
13531355
TASK_UNINTERRUPTIBLE);
13541356
pnfs_put_layout_hdr(lo);
@@ -1362,7 +1364,7 @@ bool pnfs_roc(struct inode *ino,
13621364
skip_read = true;
13631365
}
13641366

1365-
list_for_each_entry(ctx, &nfsi->open_files, list) {
1367+
list_for_each_entry_rcu(ctx, &nfsi->open_files, list) {
13661368
state = ctx->state;
13671369
if (state == NULL)
13681370
continue;
@@ -1410,6 +1412,7 @@ bool pnfs_roc(struct inode *ino,
14101412

14111413
out_noroc:
14121414
spin_unlock(&ino->i_lock);
1415+
rcu_read_unlock();
14131416
pnfs_layoutcommit_inode(ino, true);
14141417
if (roc) {
14151418
struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld;

include/linux/nfs_fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ struct nfs_open_context {
8383

8484
struct list_head list;
8585
struct nfs4_threshold *mdsthreshold;
86+
struct rcu_head rcu_head;
8687
};
8788

8889
struct nfs_open_dir_context {

0 commit comments

Comments
 (0)