mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
pNFS: allow layout drivers to cancel I/O to a single device
The ->cancel_io() layout operation cancels all in-flight I/O for a layout segment that is being returned. When the return is triggered by the failure of a single mirror instance, cancelling I/O to the healthy mirrors is both unnecessary and harmful: requests that were already transmitted cannot be un-sent, and will complete on the data servers after the layout has been returned. Give ->cancel_io() a device ID argument identifying the failed device, and thread it through pnfs_error_mark_layout_for_return() and pnfs_mark_matching_lsegs_return(). The flexfiles implementation compares it against the raw device ID from the layout, so that it can identify the failed mirror instance even when its device ID node was never instantiated. A NULL device ID preserves the existing cancel-everything behavior, and all callers pass NULL for now, so this patch makes no change in behavior. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Reviewed-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
This commit is contained in:
parent
3a612faba5
commit
94dc092b20
|
|
@ -859,7 +859,8 @@ bl_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
|
|||
|
||||
if (pgio->pg_lseg &&
|
||||
test_bit(NFS_LSEG_UNAVAILABLE, &pgio->pg_lseg->pls_flags)) {
|
||||
pnfs_error_mark_layout_for_return(pgio->pg_inode, pgio->pg_lseg);
|
||||
pnfs_error_mark_layout_for_return(pgio->pg_inode, pgio->pg_lseg,
|
||||
NULL);
|
||||
pnfs_set_lo_fail(pgio->pg_lseg);
|
||||
nfs_pageio_reset_read_mds(pgio);
|
||||
}
|
||||
|
|
@ -921,7 +922,8 @@ bl_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
|
|||
if (pgio->pg_lseg &&
|
||||
test_bit(NFS_LSEG_UNAVAILABLE, &pgio->pg_lseg->pls_flags)) {
|
||||
|
||||
pnfs_error_mark_layout_for_return(pgio->pg_inode, pgio->pg_lseg);
|
||||
pnfs_error_mark_layout_for_return(pgio->pg_inode, pgio->pg_lseg,
|
||||
NULL);
|
||||
pnfs_set_lo_fail(pgio->pg_lseg);
|
||||
nfs_pageio_reset_write_mds(pgio);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
|
|||
switch (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
|
||||
&args->cbl_range,
|
||||
be32_to_cpu(args->cbl_stateid.seqid),
|
||||
args->cbl_layoutchanged)) {
|
||||
args->cbl_layoutchanged, NULL)) {
|
||||
case 0:
|
||||
case -EBUSY:
|
||||
/* There are layout segments that need to be returned */
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ static int filelayout_async_handle_error(struct rpc_task *task,
|
|||
dprintk("%s DS connection error %d\n", __func__,
|
||||
task->tk_status);
|
||||
nfs4_mark_deviceid_unavailable(devid);
|
||||
pnfs_error_mark_layout_for_return(inode, lseg);
|
||||
pnfs_error_mark_layout_for_return(inode, lseg, NULL);
|
||||
pnfs_set_lo_fail(lseg);
|
||||
rpc_wake_up(&tbl->slot_tbl_waitq);
|
||||
fallthrough;
|
||||
|
|
@ -856,7 +856,7 @@ fl_pnfs_update_layout(struct inode *ino,
|
|||
|
||||
status = filelayout_check_deviceid(lo, fl, gfp_flags);
|
||||
if (status) {
|
||||
pnfs_error_mark_layout_for_return(ino, lseg);
|
||||
pnfs_error_mark_layout_for_return(ino, lseg, NULL);
|
||||
pnfs_set_lo_fail(lseg);
|
||||
pnfs_put_lseg(lseg);
|
||||
lseg = NULL;
|
||||
|
|
|
|||
|
|
@ -1281,7 +1281,7 @@ static void ff_layout_resend_pnfs_read(struct nfs_pgio_header *hdr)
|
|||
mirror_ds = ff_layout_choose_any_ds_for_read(hdr->lseg, idx, &new_idx,
|
||||
hdr->args.offset, &dss_id);
|
||||
if (IS_ERR(mirror_ds)) {
|
||||
pnfs_error_mark_layout_for_return(hdr->inode, hdr->lseg);
|
||||
pnfs_error_mark_layout_for_return(hdr->inode, hdr->lseg, NULL);
|
||||
} else {
|
||||
nfs4_ff_layout_put_deviceid(mirror_ds);
|
||||
ff_layout_send_layouterror(hdr->lseg);
|
||||
|
|
@ -1294,7 +1294,7 @@ static void ff_layout_reset_read(struct nfs_pgio_header *hdr)
|
|||
struct rpc_task *task = &hdr->task;
|
||||
|
||||
pnfs_layoutcommit_inode(hdr->inode, false);
|
||||
pnfs_error_mark_layout_for_return(hdr->inode, hdr->lseg);
|
||||
pnfs_error_mark_layout_for_return(hdr->inode, hdr->lseg, NULL);
|
||||
|
||||
if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
|
||||
dprintk("%s Reset task %5u for i/o through MDS "
|
||||
|
|
@ -1594,7 +1594,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
|
|||
fallthrough;
|
||||
default:
|
||||
pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode,
|
||||
lseg);
|
||||
lseg, NULL);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -2256,7 +2256,7 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr)
|
|||
* FF_FLAGS_NO_IO_THRU_MDS: force fresh LAYOUTGET,
|
||||
* never fall through to MDS I/O.
|
||||
*/
|
||||
pnfs_error_mark_layout_for_return(hdr->inode, lseg);
|
||||
pnfs_error_mark_layout_for_return(hdr->inode, lseg, NULL);
|
||||
return PNFS_TRY_AGAIN;
|
||||
}
|
||||
trace_pnfs_mds_fallback_read_pagelist(hdr->inode,
|
||||
|
|
@ -2359,7 +2359,7 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
|
|||
* FF_FLAGS_NO_IO_THRU_MDS: force fresh LAYOUTGET,
|
||||
* never fall through to MDS I/O.
|
||||
*/
|
||||
pnfs_error_mark_layout_for_return(hdr->inode, lseg);
|
||||
pnfs_error_mark_layout_for_return(hdr->inode, lseg, NULL);
|
||||
return PNFS_TRY_AGAIN;
|
||||
}
|
||||
trace_pnfs_mds_fallback_write_pagelist(hdr->inode,
|
||||
|
|
@ -2490,7 +2490,8 @@ static bool ff_layout_match_io(const struct rpc_task *task, const void *data)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void ff_layout_cancel_io(struct pnfs_layout_segment *lseg)
|
||||
static void ff_layout_cancel_io(struct pnfs_layout_segment *lseg,
|
||||
const struct nfs4_deviceid *devid)
|
||||
{
|
||||
struct nfs4_ff_layout_segment *flseg = FF_LAYOUT_LSEG(lseg);
|
||||
struct nfs4_ff_layout_mirror *mirror;
|
||||
|
|
@ -2503,6 +2504,9 @@ static void ff_layout_cancel_io(struct pnfs_layout_segment *lseg)
|
|||
for (idx = 0; idx < flseg->mirror_array_cnt; idx++) {
|
||||
mirror = flseg->mirror_array[idx];
|
||||
for (dss_id = 0; dss_id < mirror->dss_count; dss_id++) {
|
||||
if (devid && memcmp(&mirror->dss[dss_id].devid, devid,
|
||||
sizeof(*devid)) != 0)
|
||||
continue;
|
||||
rcu_read_lock();
|
||||
mirror_ds = rcu_dereference(mirror->dss[dss_id].mirror_ds);
|
||||
if (IS_ERR_OR_NULL(mirror_ds) ||
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
|
|||
opnum, GFP_NOIO);
|
||||
ff_layout_send_layouterror(lseg);
|
||||
if (opnum != OP_READ || !ff_layout_has_available_ds(lseg))
|
||||
pnfs_error_mark_layout_for_return(ino, lseg);
|
||||
pnfs_error_mark_layout_for_return(ino, lseg, NULL);
|
||||
ds = ERR_PTR(status);
|
||||
out:
|
||||
return ds;
|
||||
|
|
|
|||
|
|
@ -433,7 +433,7 @@ bool nfs4_layout_refresh_old_stateid(nfs4_stateid *dst,
|
|||
}
|
||||
/* Try to update the seqid to the most recent */
|
||||
err = pnfs_mark_matching_lsegs_return(lo, &head, &range, 0,
|
||||
true);
|
||||
true, NULL);
|
||||
if (err != -EBUSY) {
|
||||
dst->seqid = lo->plh_stateid.seqid;
|
||||
*dst_range = range;
|
||||
|
|
@ -487,7 +487,8 @@ static int pnfs_mark_layout_stateid_return(struct pnfs_layout_hdr *lo,
|
|||
.length = NFS4_MAX_UINT64,
|
||||
};
|
||||
|
||||
return pnfs_mark_matching_lsegs_return(lo, lseg_list, &range, seq, true);
|
||||
return pnfs_mark_matching_lsegs_return(lo, lseg_list, &range, seq, true,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -525,7 +526,7 @@ pnfs_layout_io_set_failed(struct pnfs_layout_hdr *lo, u32 iomode)
|
|||
|
||||
spin_lock(&inode->i_lock);
|
||||
pnfs_layout_set_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode));
|
||||
pnfs_mark_matching_lsegs_return(lo, &head, &range, 0, true);
|
||||
pnfs_mark_matching_lsegs_return(lo, &head, &range, 0, true, NULL);
|
||||
spin_unlock(&inode->i_lock);
|
||||
pnfs_free_lseg_list(&head);
|
||||
dprintk("%s Setting layout IOMODE_%s fail bit\n", __func__,
|
||||
|
|
@ -740,7 +741,7 @@ pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
|
|||
if (mark_lseg_invalid(lseg, tmp_list))
|
||||
continue;
|
||||
remaining++;
|
||||
pnfs_lseg_cancel_io(server, lseg);
|
||||
pnfs_lseg_cancel_io(server, lseg, NULL);
|
||||
}
|
||||
dprintk("%s:Return %i\n", __func__, remaining);
|
||||
return remaining;
|
||||
|
|
@ -1476,7 +1477,7 @@ _pnfs_return_layout(struct inode *ino)
|
|||
}
|
||||
valid_layout = pnfs_layout_is_valid(lo);
|
||||
pnfs_clear_layoutcommit(ino, &tmp_list);
|
||||
pnfs_mark_matching_lsegs_return(lo, &tmp_list, &range, 0, true);
|
||||
pnfs_mark_matching_lsegs_return(lo, &tmp_list, &range, 0, true, NULL);
|
||||
|
||||
|
||||
/* Don't send a LAYOUTRETURN if list was initially empty */
|
||||
|
|
@ -2658,7 +2659,8 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
|
|||
.iomode = IOMODE_ANY,
|
||||
.length = NFS4_MAX_UINT64,
|
||||
};
|
||||
pnfs_mark_matching_lsegs_return(lo, &free_me, &range, 0, true);
|
||||
pnfs_mark_matching_lsegs_return(lo, &free_me, &range, 0, true,
|
||||
NULL);
|
||||
goto out_forget;
|
||||
} else {
|
||||
/* We have a completely new layout */
|
||||
|
|
@ -2691,6 +2693,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
|
|||
* @return_range: describe layout segment ranges to be returned
|
||||
* @seq: stateid seqid to match
|
||||
* @cancel_io: signal io be cancelled
|
||||
* @devid: only cancel io directed at this device (all devices if NULL)
|
||||
*
|
||||
* This function is mainly intended for use by layoutrecall. It attempts
|
||||
* to free the layout segment immediately, or else to mark it for return
|
||||
|
|
@ -2705,7 +2708,8 @@ int
|
|||
pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
||||
struct list_head *tmp_list,
|
||||
const struct pnfs_layout_range *return_range,
|
||||
u32 seq, bool cancel_io)
|
||||
u32 seq, bool cancel_io,
|
||||
const struct nfs4_deviceid *devid)
|
||||
{
|
||||
struct pnfs_layout_segment *lseg, *next;
|
||||
struct nfs_server *server = NFS_SERVER(lo->plh_inode);
|
||||
|
|
@ -2732,7 +2736,7 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
|||
remaining++;
|
||||
set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags);
|
||||
if (cancel_io)
|
||||
pnfs_lseg_cancel_io(server, lseg);
|
||||
pnfs_lseg_cancel_io(server, lseg, devid);
|
||||
}
|
||||
|
||||
if (remaining) {
|
||||
|
|
@ -2750,7 +2754,8 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
|||
|
||||
static void
|
||||
pnfs_mark_layout_for_return(struct inode *inode,
|
||||
const struct pnfs_layout_range *range)
|
||||
const struct pnfs_layout_range *range,
|
||||
const struct nfs4_deviceid *devid)
|
||||
{
|
||||
struct pnfs_layout_hdr *lo;
|
||||
bool return_now = false;
|
||||
|
|
@ -2768,7 +2773,7 @@ pnfs_mark_layout_for_return(struct inode *inode,
|
|||
* for how it works.
|
||||
*/
|
||||
if (pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs, range, 0,
|
||||
true) != -EBUSY) {
|
||||
true, devid) != -EBUSY) {
|
||||
const struct cred *cred;
|
||||
nfs4_stateid stateid;
|
||||
enum pnfs_iomode iomode;
|
||||
|
|
@ -2785,7 +2790,8 @@ pnfs_mark_layout_for_return(struct inode *inode,
|
|||
}
|
||||
|
||||
void pnfs_error_mark_layout_for_return(struct inode *inode,
|
||||
struct pnfs_layout_segment *lseg)
|
||||
struct pnfs_layout_segment *lseg,
|
||||
const struct nfs4_deviceid *devid)
|
||||
{
|
||||
struct pnfs_layout_range range = {
|
||||
.iomode = lseg->pls_range.iomode,
|
||||
|
|
@ -2793,7 +2799,7 @@ void pnfs_error_mark_layout_for_return(struct inode *inode,
|
|||
.length = NFS4_MAX_UINT64,
|
||||
};
|
||||
|
||||
pnfs_mark_layout_for_return(inode, &range);
|
||||
pnfs_mark_layout_for_return(inode, &range, devid);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pnfs_error_mark_layout_for_return);
|
||||
|
||||
|
|
@ -2883,7 +2889,7 @@ static int pnfs_layout_return_unused_byserver(struct nfs_server *server,
|
|||
pnfs_get_layout_hdr(lo);
|
||||
pnfs_set_plh_return_info(lo, range->iomode, 0);
|
||||
if (pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs,
|
||||
range, 0, true) != 0 ||
|
||||
range, 0, true, NULL) != 0 ||
|
||||
!pnfs_prepare_layoutreturn(lo, &stateid, &cred, &iomode)) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
rcu_read_unlock();
|
||||
|
|
|
|||
|
|
@ -197,7 +197,8 @@ struct pnfs_layoutdriver_type {
|
|||
int (*prepare_layoutcommit) (struct nfs4_layoutcommit_args *args);
|
||||
int (*prepare_layoutstats) (struct nfs42_layoutstat_args *args);
|
||||
|
||||
void (*cancel_io)(struct pnfs_layout_segment *lseg);
|
||||
void (*cancel_io)(struct pnfs_layout_segment *lseg,
|
||||
const struct nfs4_deviceid *devid);
|
||||
};
|
||||
|
||||
struct pnfs_commit_ops {
|
||||
|
|
@ -320,7 +321,8 @@ int pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
|
|||
int pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
||||
struct list_head *tmp_list,
|
||||
const struct pnfs_layout_range *recall_range,
|
||||
u32 seq, bool cancel_io);
|
||||
u32 seq, bool cancel_io,
|
||||
const struct nfs4_deviceid *devid);
|
||||
int pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo,
|
||||
struct list_head *lseg_list);
|
||||
bool pnfs_roc(struct inode *ino, struct nfs4_layoutreturn_args *args,
|
||||
|
|
@ -370,7 +372,8 @@ int pnfs_read_done_resend_to_mds(struct nfs_pgio_header *);
|
|||
int pnfs_write_done_resend_to_mds(struct nfs_pgio_header *);
|
||||
struct nfs4_threshold *pnfs_mdsthreshold_alloc(void);
|
||||
void pnfs_error_mark_layout_for_return(struct inode *inode,
|
||||
struct pnfs_layout_segment *lseg);
|
||||
struct pnfs_layout_segment *lseg,
|
||||
const struct nfs4_deviceid *devid);
|
||||
void pnfs_layout_return_unused_byclid(struct nfs_client *clp,
|
||||
enum pnfs_iomode iomode);
|
||||
void pnfs_layout_reresolve_deviceid_byclid(struct nfs_client *clp,
|
||||
|
|
@ -774,10 +777,11 @@ pnfs_lseg_request_intersecting(struct pnfs_layout_segment *lseg, struct nfs_page
|
|||
}
|
||||
|
||||
static inline void pnfs_lseg_cancel_io(struct nfs_server *server,
|
||||
struct pnfs_layout_segment *lseg)
|
||||
struct pnfs_layout_segment *lseg,
|
||||
const struct nfs4_deviceid *devid)
|
||||
{
|
||||
if (server->pnfs_curr_ld->cancel_io)
|
||||
server->pnfs_curr_ld->cancel_io(lseg);
|
||||
server->pnfs_curr_ld->cancel_io(lseg, devid);
|
||||
}
|
||||
|
||||
extern unsigned int layoutstats_timer;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user