this patch introduces a new ioctl that prevents requests being aborted on a socket error and instead the request is retried on the next connection or is cleaned up on timeout, disconnect or clear_sock. Signed-off-by: Tim Dawson <tim.dawson@xxxxxxxxxx> --- drivers/block/nbd.c | 80 +++++++++++++++++++++++++++++++++++++++--------- include/uapi/linux/nbd.h | 1 + 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index ba405b5..727f5b5 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -43,6 +43,7 @@ #define NBD_TIMEDOUT 0 #define NBD_DISCONNECT_REQUESTED 1 +#define NBD_RESEND_DO_IT 2 struct nbd_device { u32 flags; @@ -433,8 +434,6 @@ static int nbd_thread_recv(struct nbd_device *nbd, struct block_device *bdev) return ret; } - nbd_size_update(nbd, bdev); - while (1) { cmd = nbd_read_stat(nbd); if (IS_ERR(cmd)) { @@ -442,10 +441,19 @@ static int nbd_thread_recv(struct nbd_device *nbd, struct block_device *bdev) break; } + struct request *req = blk_mq_rq_from_pdu(cmd); + + if (test_bit(NBD_RESEND_DO_IT, &nbd->runtime_flags) && req->errors) { + /* reset errors - we will reconnect and fix these */ + req->errors = 0; + ret = -EIO; + dev_warn(disk_to_dev(nbd->disk), "Handling failed recv %p\n", req); + break; + } + nbd_end_request(cmd); - } - nbd_size_clear(nbd, bdev); + } device_remove_file(disk_to_dev(nbd->disk), &pid_attr); return ret; @@ -503,7 +511,10 @@ static void nbd_handle_cmd(struct nbd_cmd *cmd) goto error_out; } - if (nbd_send_cmd(nbd, cmd) != 0) { + /* if not NBD_RESEND_DO_IT and there is an error, + * we dont want to nbd_end_request if we can retry later + */ + if (nbd_send_cmd(nbd, cmd) != 0 && !test_bit(NBD_RESEND_DO_IT, &nbd->runtime_flags)) { dev_err(disk_to_dev(nbd->disk), "Request send failed\n"); req->errors++; nbd_end_request(cmd); @@ -515,8 +526,32 @@ static void nbd_handle_cmd(struct nbd_cmd *cmd) return; error_out: - req->errors++; - nbd_end_request(cmd); + if (test_bit(NBD_RESEND_DO_IT, &nbd->runtime_flags)) { + nbd->task_send = NULL; + mutex_unlock(&nbd->tx_lock); + return; + } + + req->errors++; + nbd_end_request(cmd); +} + + +static void nbd_resend_req(struct request *req, void *data, bool reserved) +{ + struct nbd_device *nbd = data; + struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req); + + dev_err(nbd_to_dev(nbd), "resend request %p\n", cmd); + nbd_handle_cmd(cmd); +} + +static void nbd_resend_pending(struct nbd_device *nbd) +{ + BUG_ON(nbd->magic != NBD_MAGIC); + + blk_mq_tagset_busy_iter(&nbd->tag_set, nbd_resend_req, nbd); + dev_dbg(disk_to_dev(nbd->disk), "queue cleared\n"); } static int nbd_queue_rq(struct blk_mq_hw_ctx *hctx, @@ -661,6 +696,10 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, nbd->flags = arg; return 0; + case NBD_SET_RESEND: + set_bit(NBD_RESEND_DO_IT, &nbd->runtime_flags); + return 0; + case NBD_DO_IT: { int error; @@ -675,26 +714,37 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, nbd_parse_flags(nbd, bdev); + /* Resend remaining commands from last connection */ + if (test_bit(NBD_RESEND_DO_IT, &nbd->runtime_flags)) + nbd_resend_pending(nbd); + + nbd_size_update(nbd, bdev); + nbd_dev_dbg_init(nbd); - error = nbd_thread_recv(nbd, bdev); + error = nbd_thread_recv(nbd, bdev); //blocking nbd_dev_dbg_close(nbd); mutex_lock(&nbd->tx_lock); nbd->task_recv = NULL; sock_shutdown(nbd); - nbd_clear_que(nbd); - kill_bdev(bdev); - nbd_bdev_reset(bdev); + if (!test_bit(NBD_RESEND_DO_IT, &nbd->runtime_flags) || + test_bit(NBD_DISCONNECT_REQUESTED, &nbd->runtime_flags)) { - /* user requested, ignore socket errors */ - if (test_bit(NBD_DISCONNECT_REQUESTED, &nbd->runtime_flags)) + dev_info(disk_to_dev(nbd->disk), "NBD_DO_IT cleanup\n"); + nbd_size_clear(nbd, bdev); + nbd_clear_que(nbd); + kill_bdev(bdev); + nbd_bdev_reset(bdev); + nbd_reset(nbd); + + /* user requested, ignore socket errors */ error = 0; + } + if (test_bit(NBD_TIMEDOUT, &nbd->runtime_flags)) error = -ETIMEDOUT; - nbd_reset(nbd); - return error; } diff --git a/include/uapi/linux/nbd.h b/include/uapi/linux/nbd.h index e08e413..9031c87 100644 --- a/include/uapi/linux/nbd.h +++ b/include/uapi/linux/nbd.h @@ -28,6 +28,7 @@ #define NBD_DISCONNECT _IO( 0xab, 8 ) #define NBD_SET_TIMEOUT _IO( 0xab, 9 ) #define NBD_SET_FLAGS _IO( 0xab, 10) +#define NBD_SET_RESEND _IO( 0xab, 11) enum { NBD_CMD_READ = 0, -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-block" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html