Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 446ca2195303 ("pNFS/flexfiles: When initing reads or writes, we...")
Cc: stable@vger.kernel.org # v4.7+
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

+28 -28
+18 -19
fs/nfs/flexfilelayout/flexfilelayout.c
··· 806 806 { 807 807 struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg); 808 808 struct nfs4_pnfs_ds *ds; 809 + bool fail_return = false; 809 810 int idx; 810 811 811 812 /* mirrors are sorted by efficiency */ 812 813 for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) { 813 - ds = nfs4_ff_layout_prepare_ds(lseg, idx, false); 814 + if (idx+1 == fls->mirror_array_cnt) 815 + fail_return = true; 816 + ds = nfs4_ff_layout_prepare_ds(lseg, idx, fail_return); 814 817 if (ds) { 815 818 *best_idx = idx; 816 819 return ds; ··· 862 859 struct nfs4_pnfs_ds *ds; 863 860 int ds_idx; 864 861 862 + retry: 865 863 /* Use full layout for now */ 866 864 if (!pgio->pg_lseg) 867 865 ff_layout_pg_get_read(pgio, req, false); ··· 875 871 876 872 ds = ff_layout_choose_best_ds_for_read(pgio->pg_lseg, 0, &ds_idx); 877 873 if (!ds) { 878 - if (ff_layout_no_fallback_to_mds(pgio->pg_lseg)) 879 - goto out_pnfs; 880 - else 874 + if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg)) 881 875 goto out_mds; 876 + pnfs_put_lseg(pgio->pg_lseg); 877 + pgio->pg_lseg = NULL; 878 + /* Sleep for 1 second before retrying */ 879 + ssleep(1); 880 + goto retry; 882 881 } 883 882 884 883 mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx); ··· 897 890 pnfs_put_lseg(pgio->pg_lseg); 898 891 pgio->pg_lseg = NULL; 899 892 nfs_pageio_reset_read_mds(pgio); 900 - return; 901 - 902 - out_pnfs: 903 - pnfs_set_lo_fail(pgio->pg_lseg); 904 - pnfs_put_lseg(pgio->pg_lseg); 905 - pgio->pg_lseg = NULL; 906 893 } 907 894 908 895 static void ··· 910 909 int i; 911 910 int status; 912 911 912 + retry: 913 913 if (!pgio->pg_lseg) { 914 914 pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, 915 915 req->wb_context, ··· 942 940 for (i = 0; i < pgio->pg_mirror_count; i++) { 943 941 ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, i, true); 944 942 if (!ds) { 945 - if (ff_layout_no_fallback_to_mds(pgio->pg_lseg)) 946 - goto out_pnfs; 947 - else 943 + if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg)) 948 944 goto out_mds; 945 + pnfs_put_lseg(pgio->pg_lseg); 946 + pgio->pg_lseg = NULL; 947 + /* Sleep for 1 second before retrying */ 948 + ssleep(1); 949 + goto retry; 949 950 } 950 951 pgm = &pgio->pg_mirrors[i]; 951 952 mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i); ··· 961 956 pnfs_put_lseg(pgio->pg_lseg); 962 957 pgio->pg_lseg = NULL; 963 958 nfs_pageio_reset_write_mds(pgio); 964 - return; 965 - 966 - out_pnfs: 967 - pnfs_set_lo_fail(pgio->pg_lseg); 968 - pnfs_put_lseg(pgio->pg_lseg); 969 - pgio->pg_lseg = NULL; 970 959 } 971 960 972 961 static unsigned int
+10 -9
fs/nfs/flexfilelayout/flexfilelayoutdev.c
··· 379 379 380 380 devid = &mirror->mirror_ds->id_node; 381 381 if (ff_layout_test_devid_unavailable(devid)) 382 - goto out; 382 + goto out_fail; 383 383 384 384 ds = mirror->mirror_ds->ds; 385 385 /* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */ ··· 405 405 mirror->mirror_ds->ds_versions[0].rsize = max_payload; 406 406 if (mirror->mirror_ds->ds_versions[0].wsize > max_payload) 407 407 mirror->mirror_ds->ds_versions[0].wsize = max_payload; 408 - } else { 409 - ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout), 410 - mirror, lseg->pls_range.offset, 411 - lseg->pls_range.length, NFS4ERR_NXIO, 412 - OP_ILLEGAL, GFP_NOIO); 413 - if (fail_return || !ff_layout_has_available_ds(lseg)) 414 - pnfs_error_mark_layout_for_return(ino, lseg); 415 - ds = NULL; 408 + goto out; 416 409 } 410 + ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout), 411 + mirror, lseg->pls_range.offset, 412 + lseg->pls_range.length, NFS4ERR_NXIO, 413 + OP_ILLEGAL, GFP_NOIO); 414 + out_fail: 415 + if (fail_return || !ff_layout_has_available_ds(lseg)) 416 + pnfs_error_mark_layout_for_return(ino, lseg); 417 + ds = NULL; 417 418 out: 418 419 return ds; 419 420 }