NFS/flexfiles: Send LAYOUTERROR when failing over mirrored reads

When a read to the preferred mirror returns an error, the flexfiles
driver records the error in the inode list and currently marks the
layout for return before failing over the attempted read to the next
mirror.
What we actually want to do is fire off a LAYOUTERROR to notify the
MDS that there is an issue with the preferred mirror, then we fail
over. Only once we've failed to read from all mirrors should we
return the layout.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
Trond Myklebust
2019-02-10 22:38:43 -05:00
parent 3eb86093ea
commit f0922a6c0c
3 changed files with 57 additions and 6 deletions

View File

@@ -1252,7 +1252,7 @@ static int ff_layout_read_done_cb(struct rpc_task *task,
if (ff_layout_choose_best_ds_for_read(hdr->lseg,
hdr->pgio_mirror_idx + 1,
&hdr->pgio_mirror_idx))
goto out_eagain;
goto out_layouterror;
set_bit(NFS_IOHDR_RESEND_PNFS, &hdr->flags);
return task->tk_status;
case -NFS4ERR_RESET_TO_MDS:
@@ -1263,6 +1263,8 @@ static int ff_layout_read_done_cb(struct rpc_task *task,
}
return 0;
out_layouterror:
ff_layout_send_layouterror(hdr->lseg);
out_eagain:
rpc_restart_call_prepare(task);
return -EAGAIN;
@@ -1412,9 +1414,10 @@ static void ff_layout_read_release(void *data)
struct nfs_pgio_header *hdr = data;
ff_layout_read_record_layoutstats_done(&hdr->task, hdr);
if (test_bit(NFS_IOHDR_RESEND_PNFS, &hdr->flags))
if (test_bit(NFS_IOHDR_RESEND_PNFS, &hdr->flags)) {
ff_layout_send_layouterror(hdr->lseg);
pnfs_read_resend_pnfs(hdr);
else if (test_bit(NFS_IOHDR_RESEND_MDS, &hdr->flags))
} else if (test_bit(NFS_IOHDR_RESEND_MDS, &hdr->flags))
ff_layout_reset_read(hdr);
pnfs_generic_rw_release(data);
}
@@ -1586,9 +1589,10 @@ static void ff_layout_write_release(void *data)
struct nfs_pgio_header *hdr = data;
ff_layout_write_record_layoutstats_done(&hdr->task, hdr);
if (test_bit(NFS_IOHDR_RESEND_PNFS, &hdr->flags))
if (test_bit(NFS_IOHDR_RESEND_PNFS, &hdr->flags)) {
ff_layout_send_layouterror(hdr->lseg);
ff_layout_reset_write(hdr, true);
else if (test_bit(NFS_IOHDR_RESEND_MDS, &hdr->flags))
} else if (test_bit(NFS_IOHDR_RESEND_MDS, &hdr->flags))
ff_layout_reset_write(hdr, false);
pnfs_generic_rw_release(data);
}
@@ -2119,6 +2123,52 @@ out_nomem:
return -ENOMEM;
}
#ifdef CONFIG_NFS_V4_2
void
ff_layout_send_layouterror(struct pnfs_layout_segment *lseg)
{
struct pnfs_layout_hdr *lo = lseg->pls_layout;
struct nfs42_layout_error *errors;
LIST_HEAD(head);
if (!nfs_server_capable(lo->plh_inode, NFS_CAP_LAYOUTERROR))
return;
ff_layout_fetch_ds_ioerr(lo, &lseg->pls_range, &head, -1);
if (list_empty(&head))
return;
errors = kmalloc_array(NFS42_LAYOUTERROR_MAX,
sizeof(*errors), GFP_NOFS);
if (errors != NULL) {
const struct nfs4_ff_layout_ds_err *pos;
size_t n = 0;
list_for_each_entry(pos, &head, list) {
errors[n].offset = pos->offset;
errors[n].length = pos->length;
nfs4_stateid_copy(&errors[n].stateid, &pos->stateid);
errors[n].errors[0].dev_id = pos->deviceid;
errors[n].errors[0].status = pos->status;
errors[n].errors[0].opnum = pos->opnum;
n++;
if (!list_is_last(&pos->list, &head) &&
n < NFS42_LAYOUTERROR_MAX)
continue;
if (nfs42_proc_layouterror(lseg, errors, n) < 0)
break;
n = 0;
}
kfree(errors);
}
ff_layout_free_ds_ioerr(&head);
}
#else
void
ff_layout_send_layouterror(struct pnfs_layout_segment *lseg)
{
}
#endif
static int
ff_layout_ntop4(const struct sockaddr *sap, char *buf, const size_t buflen)
{