diff options
author | Fred Isaman <fred.isaman@gmail.com> | 2016-09-30 14:37:41 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-12-08 21:49:57 -0500 |
commit | 65990d1afbd2d6fc23c6ecbd6f1899aa760a024f (patch) | |
tree | 3a18ac67020a08d0e7aec06158902b10f0644c4f /fs/nfs/flexfilelayout/flexfilelayoutdev.c | |
parent | 2f065ddb64193ebf9cd600395d4782287cd0f58e (diff) |
pNFS/flexfiles: Fix a deadlock on LAYOUTGET
We encountered a deadlock where the SEQUENCE that accompanied the
LAYOUTGET triggered a session drain, while ff_layout_alloc_lseg
triggered a GETDEVICEINFO. The GETDEVICEINFO hung waiting for the
session drain, while the LAYOUTGET held the slot waiting for
alloc_lseg to finish.
Avoid this by moving the call to nfs4_find_get_deviceid out of
ff_layout_alloc_lseg and into nfs4_ff_layout_prepare_ds.
Signed-off-by: Fred Isaman <fred.isaman@gmail.com>
[dros@primarydata.com: pNFS/flexfiles: fix races in ff_layout_mirror_valid]
Signed-off-by: Weston Andros Adamson <dros@primarydata.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs/flexfilelayout/flexfilelayoutdev.c')
-rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayoutdev.c | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index 142bfd0b1663..3cc39d1c1206 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c | |||
@@ -20,9 +20,11 @@ | |||
20 | static unsigned int dataserver_timeo = NFS_DEF_TCP_RETRANS; | 20 | static unsigned int dataserver_timeo = NFS_DEF_TCP_RETRANS; |
21 | static unsigned int dataserver_retrans; | 21 | static unsigned int dataserver_retrans; |
22 | 22 | ||
23 | static bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg); | ||
24 | |||
23 | void nfs4_ff_layout_put_deviceid(struct nfs4_ff_layout_ds *mirror_ds) | 25 | void nfs4_ff_layout_put_deviceid(struct nfs4_ff_layout_ds *mirror_ds) |
24 | { | 26 | { |
25 | if (mirror_ds) | 27 | if (!IS_ERR_OR_NULL(mirror_ds)) |
26 | nfs4_put_deviceid_node(&mirror_ds->id_node); | 28 | nfs4_put_deviceid_node(&mirror_ds->id_node); |
27 | } | 29 | } |
28 | 30 | ||
@@ -182,12 +184,29 @@ static void ff_layout_mark_devid_invalid(struct pnfs_layout_segment *lseg, | |||
182 | } | 184 | } |
183 | 185 | ||
184 | static bool ff_layout_mirror_valid(struct pnfs_layout_segment *lseg, | 186 | static bool ff_layout_mirror_valid(struct pnfs_layout_segment *lseg, |
185 | struct nfs4_ff_layout_mirror *mirror) | 187 | struct nfs4_ff_layout_mirror *mirror, |
188 | bool create) | ||
186 | { | 189 | { |
187 | if (mirror == NULL || mirror->mirror_ds == NULL) { | 190 | if (mirror == NULL || IS_ERR(mirror->mirror_ds)) |
188 | pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode, | 191 | goto outerr; |
189 | lseg); | 192 | if (mirror->mirror_ds == NULL) { |
190 | return false; | 193 | if (create) { |
194 | struct nfs4_deviceid_node *node; | ||
195 | struct pnfs_layout_hdr *lh = lseg->pls_layout; | ||
196 | struct nfs4_ff_layout_ds *mirror_ds = ERR_PTR(-ENODEV); | ||
197 | |||
198 | node = nfs4_find_get_deviceid(NFS_SERVER(lh->plh_inode), | ||
199 | &mirror->devid, lh->plh_lc_cred, | ||
200 | GFP_KERNEL); | ||
201 | if (node) | ||
202 | mirror_ds = FF_LAYOUT_MIRROR_DS(node); | ||
203 | |||
204 | /* check for race with another call to this function */ | ||
205 | if (cmpxchg(&mirror->mirror_ds, NULL, mirror_ds) && | ||
206 | mirror_ds != ERR_PTR(-ENODEV)) | ||
207 | nfs4_put_deviceid_node(node); | ||
208 | } else | ||
209 | goto outerr; | ||
191 | } | 210 | } |
192 | if (mirror->mirror_ds->ds == NULL) { | 211 | if (mirror->mirror_ds->ds == NULL) { |
193 | struct nfs4_deviceid_node *devid; | 212 | struct nfs4_deviceid_node *devid; |
@@ -196,6 +215,9 @@ static bool ff_layout_mirror_valid(struct pnfs_layout_segment *lseg, | |||
196 | return false; | 215 | return false; |
197 | } | 216 | } |
198 | return true; | 217 | return true; |
218 | outerr: | ||
219 | pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode, lseg); | ||
220 | return false; | ||
199 | } | 221 | } |
200 | 222 | ||
201 | static void extend_ds_error(struct nfs4_ff_layout_ds_err *err, | 223 | static void extend_ds_error(struct nfs4_ff_layout_ds_err *err, |
@@ -323,7 +345,7 @@ nfs4_ff_layout_select_ds_fh(struct pnfs_layout_segment *lseg, u32 mirror_idx) | |||
323 | struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, mirror_idx); | 345 | struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, mirror_idx); |
324 | struct nfs_fh *fh = NULL; | 346 | struct nfs_fh *fh = NULL; |
325 | 347 | ||
326 | if (!ff_layout_mirror_valid(lseg, mirror)) { | 348 | if (!ff_layout_mirror_valid(lseg, mirror, false)) { |
327 | pr_err_ratelimited("NFS: %s: No data server for mirror offset index %d\n", | 349 | pr_err_ratelimited("NFS: %s: No data server for mirror offset index %d\n", |
328 | __func__, mirror_idx); | 350 | __func__, mirror_idx); |
329 | goto out; | 351 | goto out; |
@@ -363,7 +385,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, | |||
363 | struct nfs_server *s = NFS_SERVER(ino); | 385 | struct nfs_server *s = NFS_SERVER(ino); |
364 | unsigned int max_payload; | 386 | unsigned int max_payload; |
365 | 387 | ||
366 | if (!ff_layout_mirror_valid(lseg, mirror)) { | 388 | if (!ff_layout_mirror_valid(lseg, mirror, true)) { |
367 | pr_err_ratelimited("NFS: %s: No data server for offset index %d\n", | 389 | pr_err_ratelimited("NFS: %s: No data server for offset index %d\n", |
368 | __func__, ds_idx); | 390 | __func__, ds_idx); |
369 | goto out; | 391 | goto out; |
@@ -547,7 +569,11 @@ static bool ff_read_layout_has_available_ds(struct pnfs_layout_segment *lseg) | |||
547 | 569 | ||
548 | for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) { | 570 | for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) { |
549 | mirror = FF_LAYOUT_COMP(lseg, idx); | 571 | mirror = FF_LAYOUT_COMP(lseg, idx); |
550 | if (mirror && mirror->mirror_ds) { | 572 | if (mirror) { |
573 | if (!mirror->mirror_ds) | ||
574 | return true; | ||
575 | if (IS_ERR(mirror->mirror_ds)) | ||
576 | continue; | ||
551 | devid = &mirror->mirror_ds->id_node; | 577 | devid = &mirror->mirror_ds->id_node; |
552 | if (!ff_layout_test_devid_unavailable(devid)) | 578 | if (!ff_layout_test_devid_unavailable(devid)) |
553 | return true; | 579 | return true; |
@@ -565,8 +591,10 @@ static bool ff_rw_layout_has_available_ds(struct pnfs_layout_segment *lseg) | |||
565 | 591 | ||
566 | for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) { | 592 | for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) { |
567 | mirror = FF_LAYOUT_COMP(lseg, idx); | 593 | mirror = FF_LAYOUT_COMP(lseg, idx); |
568 | if (!mirror || !mirror->mirror_ds) | 594 | if (!mirror || IS_ERR(mirror->mirror_ds)) |
569 | return false; | 595 | return false; |
596 | if (!mirror->mirror_ds) | ||
597 | continue; | ||
570 | devid = &mirror->mirror_ds->id_node; | 598 | devid = &mirror->mirror_ds->id_node; |
571 | if (ff_layout_test_devid_unavailable(devid)) | 599 | if (ff_layout_test_devid_unavailable(devid)) |
572 | return false; | 600 | return false; |
@@ -575,7 +603,7 @@ static bool ff_rw_layout_has_available_ds(struct pnfs_layout_segment *lseg) | |||
575 | return FF_LAYOUT_MIRROR_COUNT(lseg) != 0; | 603 | return FF_LAYOUT_MIRROR_COUNT(lseg) != 0; |
576 | } | 604 | } |
577 | 605 | ||
578 | bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg) | 606 | static bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg) |
579 | { | 607 | { |
580 | if (lseg->pls_range.iomode == IOMODE_READ) | 608 | if (lseg->pls_range.iomode == IOMODE_READ) |
581 | return ff_read_layout_has_available_ds(lseg); | 609 | return ff_read_layout_has_available_ds(lseg); |