Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+18 −19
Original line number Diff line number Diff line
@@ -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_pnfs_ds *ds;
	bool fail_return = false;
	int idx;

	/* mirrors are sorted by efficiency */
	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) {
			*best_idx = idx;
			return ds;
@@ -859,6 +862,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
	struct nfs4_pnfs_ds *ds;
	int ds_idx;

retry:
	/* Use full layout for now */
	if (!pgio->pg_lseg)
		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);
	if (!ds) {
		if (ff_layout_no_fallback_to_mds(pgio->pg_lseg))
			goto out_pnfs;
		else
		if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg))
			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);
@@ -890,12 +897,6 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
	pnfs_put_lseg(pgio->pg_lseg);
	pgio->pg_lseg = NULL;
	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
@@ -909,6 +910,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
	int i;
	int status;

retry:
	if (!pgio->pg_lseg) {
		pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
						   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++) {
		ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, i, true);
		if (!ds) {
			if (ff_layout_no_fallback_to_mds(pgio->pg_lseg))
				goto out_pnfs;
			else
			if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg))
				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];
		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);
	pgio->pg_lseg = NULL;
	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
+10 −9
Original line number Diff line number Diff line
@@ -379,7 +379,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,

	devid = &mirror->mirror_ds->id_node;
	if (ff_layout_test_devid_unavailable(devid))
		goto out;
		goto out_fail;

	ds = mirror->mirror_ds->ds;
	/* 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;
		if (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);
out_fail:
	if (fail_return || !ff_layout_has_available_ds(lseg))
		pnfs_error_mark_layout_for_return(ino, lseg);
	ds = NULL;
	}
out:
	return ds;
}