Commit 3dc14735 authored by Trond Myklebust's avatar Trond Myklebust

pNFS/flexfiles: Fix an Oopsable condition when connection to the DS fails

If the attempt to connect to a DS fails inside ff_layout_pg_init_read or
ff_layout_pg_init_write, then we currently end up clearing the layout
segment carried by the struct nfs_pageio_descriptor, causing an Oops
when we later call into ff_layout_read_pagelist/ff_layout_write_pagelist.

The fix is to ensure we return the layout and then retry.

Fixes: 446ca219 ("pNFS/flexfiles: When initing reads or writes, we...")
Cc: stable@vger.kernel.org # v4.7+
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent d138027a
...@@ -806,11 +806,14 @@ ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg, ...@@ -806,11 +806,14 @@ ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg,
{ {
struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg); struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg);
struct nfs4_pnfs_ds *ds; struct nfs4_pnfs_ds *ds;
bool fail_return = false;
int idx; int idx;
/* mirrors are sorted by efficiency */ /* mirrors are sorted by efficiency */
for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) { for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) {
ds = nfs4_ff_layout_prepare_ds(lseg, idx, false); if (idx+1 == fls->mirror_array_cnt)
fail_return = true;
ds = nfs4_ff_layout_prepare_ds(lseg, idx, fail_return);
if (ds) { if (ds) {
*best_idx = idx; *best_idx = idx;
return ds; return ds;
...@@ -859,6 +862,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio, ...@@ -859,6 +862,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
struct nfs4_pnfs_ds *ds; struct nfs4_pnfs_ds *ds;
int ds_idx; int ds_idx;
retry:
/* Use full layout for now */ /* Use full layout for now */
if (!pgio->pg_lseg) if (!pgio->pg_lseg)
ff_layout_pg_get_read(pgio, req, false); ff_layout_pg_get_read(pgio, req, false);
...@@ -871,10 +875,13 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio, ...@@ -871,10 +875,13 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
ds = ff_layout_choose_best_ds_for_read(pgio->pg_lseg, 0, &ds_idx); ds = ff_layout_choose_best_ds_for_read(pgio->pg_lseg, 0, &ds_idx);
if (!ds) { if (!ds) {
if (ff_layout_no_fallback_to_mds(pgio->pg_lseg)) if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg))
goto out_pnfs;
else
goto out_mds; goto out_mds;
pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL;
/* Sleep for 1 second before retrying */
ssleep(1);
goto retry;
} }
mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx); mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx);
...@@ -890,12 +897,6 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio, ...@@ -890,12 +897,6 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
pnfs_put_lseg(pgio->pg_lseg); pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL; pgio->pg_lseg = NULL;
nfs_pageio_reset_read_mds(pgio); nfs_pageio_reset_read_mds(pgio);
return;
out_pnfs:
pnfs_set_lo_fail(pgio->pg_lseg);
pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL;
} }
static void static void
...@@ -909,6 +910,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio, ...@@ -909,6 +910,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
int i; int i;
int status; int status;
retry:
if (!pgio->pg_lseg) { if (!pgio->pg_lseg) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context, req->wb_context,
...@@ -940,10 +942,13 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio, ...@@ -940,10 +942,13 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
for (i = 0; i < pgio->pg_mirror_count; i++) { for (i = 0; i < pgio->pg_mirror_count; i++) {
ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, i, true); ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, i, true);
if (!ds) { if (!ds) {
if (ff_layout_no_fallback_to_mds(pgio->pg_lseg)) if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg))
goto out_pnfs;
else
goto out_mds; goto out_mds;
pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL;
/* Sleep for 1 second before retrying */
ssleep(1);
goto retry;
} }
pgm = &pgio->pg_mirrors[i]; pgm = &pgio->pg_mirrors[i];
mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i); mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i);
...@@ -956,12 +961,6 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio, ...@@ -956,12 +961,6 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
pnfs_put_lseg(pgio->pg_lseg); pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL; pgio->pg_lseg = NULL;
nfs_pageio_reset_write_mds(pgio); nfs_pageio_reset_write_mds(pgio);
return;
out_pnfs:
pnfs_set_lo_fail(pgio->pg_lseg);
pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL;
} }
static unsigned int static unsigned int
......
...@@ -379,7 +379,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, ...@@ -379,7 +379,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
devid = &mirror->mirror_ds->id_node; devid = &mirror->mirror_ds->id_node;
if (ff_layout_test_devid_unavailable(devid)) if (ff_layout_test_devid_unavailable(devid))
goto out; goto out_fail;
ds = mirror->mirror_ds->ds; ds = mirror->mirror_ds->ds;
/* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */ /* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */
...@@ -405,15 +405,16 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, ...@@ -405,15 +405,16 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
mirror->mirror_ds->ds_versions[0].rsize = max_payload; mirror->mirror_ds->ds_versions[0].rsize = max_payload;
if (mirror->mirror_ds->ds_versions[0].wsize > max_payload) if (mirror->mirror_ds->ds_versions[0].wsize > max_payload)
mirror->mirror_ds->ds_versions[0].wsize = max_payload; mirror->mirror_ds->ds_versions[0].wsize = max_payload;
} else { goto out;
}
ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout), ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout),
mirror, lseg->pls_range.offset, mirror, lseg->pls_range.offset,
lseg->pls_range.length, NFS4ERR_NXIO, lseg->pls_range.length, NFS4ERR_NXIO,
OP_ILLEGAL, GFP_NOIO); OP_ILLEGAL, GFP_NOIO);
out_fail:
if (fail_return || !ff_layout_has_available_ds(lseg)) if (fail_return || !ff_layout_has_available_ds(lseg))
pnfs_error_mark_layout_for_return(ino, lseg); pnfs_error_mark_layout_for_return(ino, lseg);
ds = NULL; ds = NULL;
}
out: out:
return ds; return ds;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment