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: 446ca21953
("pNFS/flexfiles: When initing reads or writes, we...")
Cc: stable@vger.kernel.org # v4.7+
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
This commit is contained in:
parent
d138027a82
commit
3dc147359e
|
@ -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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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),
|
|
||||||
mirror, lseg->pls_range.offset,
|
|
||||||
lseg->pls_range.length, NFS4ERR_NXIO,
|
|
||||||
OP_ILLEGAL, GFP_NOIO);
|
|
||||||
if (fail_return || !ff_layout_has_available_ds(lseg))
|
|
||||||
pnfs_error_mark_layout_for_return(ino, lseg);
|
|
||||||
ds = NULL;
|
|
||||||
}
|
}
|
||||||
|
ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout),
|
||||||
|
mirror, lseg->pls_range.offset,
|
||||||
|
lseg->pls_range.length, NFS4ERR_NXIO,
|
||||||
|
OP_ILLEGAL, GFP_NOIO);
|
||||||
|
out_fail:
|
||||||
|
if (fail_return || !ff_layout_has_available_ds(lseg))
|
||||||
|
pnfs_error_mark_layout_for_return(ino, lseg);
|
||||||
|
ds = NULL;
|
||||||
out:
|
out:
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue