From: Tim Dawson <tim.dawson@nyriad.com>
To: axboe@kernel.dk
Cc: linux-block@vger.kernel.org
Subject: [PATCH] nbd: allow socket reconnect without block IO errors
Date: Fri, 21 Oct 2016 20:24:55 +1300 [thread overview]
Message-ID: <20161021072455.GA7101@tim-dev> (raw)
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@nyriad.com>
---
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
reply other threads:[~2016-10-21 7:24 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20161021072455.GA7101@tim-dev \
--to=tim.dawson@nyriad.com \
--cc=axboe@kernel.dk \
--cc=linux-block@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.