Skip to content

Commit cc8a553

Browse files
jtlaytonJ. Bruce Fields
authored andcommitted
nfsd: serialize layout stateid morphing operations
In order to allow the client to make a sane determination of what happened with racing LAYOUTGET/LAYOUTRETURN/CB_LAYOUTRECALL calls, we must ensure that the seqids return accurately represent the order of operations. The simplest way to do that is to ensure that operations on a single stateid are serialized. This patch adds a mutex to the layout stateid, and locks it when checking the layout stateid's seqid. The mutex is held over the entire operation and released after the seqid is bumped. Note that in the case of CB_LAYOUTRECALL we must move the increment of the seqid and setting into a new cb "prepare" operation. The lease infrastructure will call the lm_break callback with a spinlock held, so and we can't take the mutex in that codepath. Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: Jeff Layton <jeff.layton@primarydata.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
1 parent 4eaea13 commit cc8a553

File tree

3 files changed

+26
-4
lines changed

3 files changed

+26
-4
lines changed

fs/nfsd/nfs4layouts.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
201201
INIT_LIST_HEAD(&ls->ls_perfile);
202202
spin_lock_init(&ls->ls_lock);
203203
INIT_LIST_HEAD(&ls->ls_layouts);
204+
mutex_init(&ls->ls_mutex);
204205
ls->ls_layout_type = layout_type;
205206
nfsd4_init_cb(&ls->ls_recall, clp, &nfsd4_cb_layout_ops,
206207
NFSPROC4_CLNT_CB_LAYOUT);
@@ -262,19 +263,23 @@ nfsd4_preprocess_layout_stateid(struct svc_rqst *rqstp,
262263
status = nfserr_jukebox;
263264
if (!ls)
264265
goto out;
266+
mutex_lock(&ls->ls_mutex);
265267
} else {
266268
ls = container_of(stid, struct nfs4_layout_stateid, ls_stid);
267269

268270
status = nfserr_bad_stateid;
271+
mutex_lock(&ls->ls_mutex);
269272
if (stateid->si_generation > stid->sc_stateid.si_generation)
270-
goto out_put_stid;
273+
goto out_unlock_stid;
271274
if (layout_type != ls->ls_layout_type)
272-
goto out_put_stid;
275+
goto out_unlock_stid;
273276
}
274277

275278
*lsp = ls;
276279
return 0;
277280

281+
out_unlock_stid:
282+
mutex_unlock(&ls->ls_mutex);
278283
out_put_stid:
279284
nfs4_put_stid(stid);
280285
out:
@@ -296,8 +301,6 @@ nfsd4_recall_file_layout(struct nfs4_layout_stateid *ls)
296301
trace_layout_recall(&ls->ls_stid.sc_stateid);
297302

298303
atomic_inc(&ls->ls_stid.sc_count);
299-
update_stateid(&ls->ls_stid.sc_stateid);
300-
memcpy(&ls->ls_recall_sid, &ls->ls_stid.sc_stateid, sizeof(stateid_t));
301304
nfsd4_run_cb(&ls->ls_recall);
302305

303306
out_unlock:
@@ -494,6 +497,7 @@ nfsd4_return_file_layouts(struct svc_rqst *rqstp,
494497
}
495498
spin_unlock(&ls->ls_lock);
496499

500+
mutex_unlock(&ls->ls_mutex);
497501
nfs4_put_stid(&ls->ls_stid);
498502
nfsd4_free_layouts(&reaplist);
499503
return nfs_ok;
@@ -608,6 +612,17 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls)
608612
}
609613
}
610614

615+
static void
616+
nfsd4_cb_layout_prepare(struct nfsd4_callback *cb)
617+
{
618+
struct nfs4_layout_stateid *ls =
619+
container_of(cb, struct nfs4_layout_stateid, ls_recall);
620+
621+
mutex_lock(&ls->ls_mutex);
622+
update_stateid(&ls->ls_stid.sc_stateid);
623+
memcpy(&ls->ls_recall_sid, &ls->ls_stid.sc_stateid, sizeof(stateid_t));
624+
}
625+
611626
static int
612627
nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
613628
{
@@ -649,12 +664,14 @@ nfsd4_cb_layout_release(struct nfsd4_callback *cb)
649664

650665
trace_layout_recall_release(&ls->ls_stid.sc_stateid);
651666

667+
mutex_unlock(&ls->ls_mutex);
652668
nfsd4_return_all_layouts(ls, &reaplist);
653669
nfsd4_free_layouts(&reaplist);
654670
nfs4_put_stid(&ls->ls_stid);
655671
}
656672

657673
static struct nfsd4_callback_ops nfsd4_cb_layout_ops = {
674+
.prepare = nfsd4_cb_layout_prepare,
658675
.done = nfsd4_cb_layout_done,
659676
.release = nfsd4_cb_layout_release,
660677
};

fs/nfsd/nfs4proc.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,7 @@ nfsd4_layoutget(struct svc_rqst *rqstp,
13091309
nfserr = nfsd4_insert_layout(lgp, ls);
13101310

13111311
out_put_stid:
1312+
mutex_unlock(&ls->ls_mutex);
13121313
nfs4_put_stid(&ls->ls_stid);
13131314
out:
13141315
return nfserr;
@@ -1362,6 +1363,9 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp,
13621363
goto out;
13631364
}
13641365

1366+
/* LAYOUTCOMMIT does not require any serialization */
1367+
mutex_unlock(&ls->ls_mutex);
1368+
13651369
if (new_size > i_size_read(inode)) {
13661370
lcp->lc_size_chg = 1;
13671371
lcp->lc_newsize = new_size;

fs/nfsd/state.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ struct nfs4_layout_stateid {
562562
struct nfsd4_callback ls_recall;
563563
stateid_t ls_recall_sid;
564564
bool ls_recalled;
565+
struct mutex ls_mutex;
565566
};
566567

567568
static inline struct nfs4_layout_stateid *layoutstateid(struct nfs4_stid *s)

0 commit comments

Comments
 (0)