aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJeff Layton <jlayton@poochiereds.net>2015-09-17 07:58:24 -0400
committerJ. Bruce Fields <bfields@redhat.com>2015-10-23 15:57:32 -0400
commitcc8a55320b5f1196bee5bd14e4bb2ebd3b983317 (patch)
treed5b6e13f764cc2c0a37d8676662302e09e1ec020 /fs/nfsd
parent4eaea13425078272895ec37814c6878d78b8db9f (diff)
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>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4layouts.c25
-rw-r--r--fs/nfsd/nfs4proc.c4
-rw-r--r--fs/nfsd/state.h1
3 files changed, 26 insertions, 4 deletions
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c
index ebf90e487c75..4a68ab901b4b 100644
--- a/fs/nfsd/nfs4layouts.c
+++ b/fs/nfsd/nfs4layouts.c
@@ -201,6 +201,7 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
201 INIT_LIST_HEAD(&ls->ls_perfile); 201 INIT_LIST_HEAD(&ls->ls_perfile);
202 spin_lock_init(&ls->ls_lock); 202 spin_lock_init(&ls->ls_lock);
203 INIT_LIST_HEAD(&ls->ls_layouts); 203 INIT_LIST_HEAD(&ls->ls_layouts);
204 mutex_init(&ls->ls_mutex);
204 ls->ls_layout_type = layout_type; 205 ls->ls_layout_type = layout_type;
205 nfsd4_init_cb(&ls->ls_recall, clp, &nfsd4_cb_layout_ops, 206 nfsd4_init_cb(&ls->ls_recall, clp, &nfsd4_cb_layout_ops,
206 NFSPROC4_CLNT_CB_LAYOUT); 207 NFSPROC4_CLNT_CB_LAYOUT);
@@ -262,19 +263,23 @@ nfsd4_preprocess_layout_stateid(struct svc_rqst *rqstp,
262 status = nfserr_jukebox; 263 status = nfserr_jukebox;
263 if (!ls) 264 if (!ls)
264 goto out; 265 goto out;
266 mutex_lock(&ls->ls_mutex);
265 } else { 267 } else {
266 ls = container_of(stid, struct nfs4_layout_stateid, ls_stid); 268 ls = container_of(stid, struct nfs4_layout_stateid, ls_stid);
267 269
268 status = nfserr_bad_stateid; 270 status = nfserr_bad_stateid;
271 mutex_lock(&ls->ls_mutex);
269 if (stateid->si_generation > stid->sc_stateid.si_generation) 272 if (stateid->si_generation > stid->sc_stateid.si_generation)
270 goto out_put_stid; 273 goto out_unlock_stid;
271 if (layout_type != ls->ls_layout_type) 274 if (layout_type != ls->ls_layout_type)
272 goto out_put_stid; 275 goto out_unlock_stid;
273 } 276 }
274 277
275 *lsp = ls; 278 *lsp = ls;
276 return 0; 279 return 0;
277 280
281out_unlock_stid:
282 mutex_unlock(&ls->ls_mutex);
278out_put_stid: 283out_put_stid:
279 nfs4_put_stid(stid); 284 nfs4_put_stid(stid);
280out: 285out:
@@ -296,8 +301,6 @@ nfsd4_recall_file_layout(struct nfs4_layout_stateid *ls)
296 trace_layout_recall(&ls->ls_stid.sc_stateid); 301 trace_layout_recall(&ls->ls_stid.sc_stateid);
297 302
298 atomic_inc(&ls->ls_stid.sc_count); 303 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));
301 nfsd4_run_cb(&ls->ls_recall); 304 nfsd4_run_cb(&ls->ls_recall);
302 305
303out_unlock: 306out_unlock:
@@ -494,6 +497,7 @@ nfsd4_return_file_layouts(struct svc_rqst *rqstp,
494 } 497 }
495 spin_unlock(&ls->ls_lock); 498 spin_unlock(&ls->ls_lock);
496 499
500 mutex_unlock(&ls->ls_mutex);
497 nfs4_put_stid(&ls->ls_stid); 501 nfs4_put_stid(&ls->ls_stid);
498 nfsd4_free_layouts(&reaplist); 502 nfsd4_free_layouts(&reaplist);
499 return nfs_ok; 503 return nfs_ok;
@@ -608,6 +612,17 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls)
608 } 612 }
609} 613}
610 614
615static void
616nfsd4_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
611static int 626static int
612nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task) 627nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
613{ 628{
@@ -649,12 +664,14 @@ nfsd4_cb_layout_release(struct nfsd4_callback *cb)
649 664
650 trace_layout_recall_release(&ls->ls_stid.sc_stateid); 665 trace_layout_recall_release(&ls->ls_stid.sc_stateid);
651 666
667 mutex_unlock(&ls->ls_mutex);
652 nfsd4_return_all_layouts(ls, &reaplist); 668 nfsd4_return_all_layouts(ls, &reaplist);
653 nfsd4_free_layouts(&reaplist); 669 nfsd4_free_layouts(&reaplist);
654 nfs4_put_stid(&ls->ls_stid); 670 nfs4_put_stid(&ls->ls_stid);
655} 671}
656 672
657static struct nfsd4_callback_ops nfsd4_cb_layout_ops = { 673static struct nfsd4_callback_ops nfsd4_cb_layout_ops = {
674 .prepare = nfsd4_cb_layout_prepare,
658 .done = nfsd4_cb_layout_done, 675 .done = nfsd4_cb_layout_done,
659 .release = nfsd4_cb_layout_release, 676 .release = nfsd4_cb_layout_release,
660}; 677};
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 4ce6b97b31ad..a9f096c7e99f 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1309,6 +1309,7 @@ nfsd4_layoutget(struct svc_rqst *rqstp,
1309 nfserr = nfsd4_insert_layout(lgp, ls); 1309 nfserr = nfsd4_insert_layout(lgp, ls);
1310 1310
1311out_put_stid: 1311out_put_stid:
1312 mutex_unlock(&ls->ls_mutex);
1312 nfs4_put_stid(&ls->ls_stid); 1313 nfs4_put_stid(&ls->ls_stid);
1313out: 1314out:
1314 return nfserr; 1315 return nfserr;
@@ -1362,6 +1363,9 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp,
1362 goto out; 1363 goto out;
1363 } 1364 }
1364 1365
1366 /* LAYOUTCOMMIT does not require any serialization */
1367 mutex_unlock(&ls->ls_mutex);
1368
1365 if (new_size > i_size_read(inode)) { 1369 if (new_size > i_size_read(inode)) {
1366 lcp->lc_size_chg = 1; 1370 lcp->lc_size_chg = 1;
1367 lcp->lc_newsize = new_size; 1371 lcp->lc_newsize = new_size;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 31bde12feefe..1fa0f3848d4e 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -562,6 +562,7 @@ struct nfs4_layout_stateid {
562 struct nfsd4_callback ls_recall; 562 struct nfsd4_callback ls_recall;
563 stateid_t ls_recall_sid; 563 stateid_t ls_recall_sid;
564 bool ls_recalled; 564 bool ls_recalled;
565 struct mutex ls_mutex;
565}; 566};
566 567
567static inline struct nfs4_layout_stateid *layoutstateid(struct nfs4_stid *s) 568static inline struct nfs4_layout_stateid *layoutstateid(struct nfs4_stid *s)