233 lines
9.1 KiB
Diff
233 lines
9.1 KiB
Diff
|
|
From d777d1585603aa7599ae8bac4492fafdf1e4b109 Mon Sep 17 00:00:00 2001
|
||
|
|
From: yexiao <yexiao7@huawei.com>
|
||
|
|
Date: Thu, 21 Jan 2021 15:46:50 +0800
|
||
|
|
Subject: [PATCH] block: Add error retry param setting
|
||
|
|
|
||
|
|
Add "retry_interval" and "retry_timeout" parameter for drive and device
|
||
|
|
option. These parameter are valid only when werror/rerror=retry.
|
||
|
|
|
||
|
|
eg. -device device_name,drive=drive_id,rerror=retry,retry_interval=1000,retry_timeout=5000
|
||
|
|
|
||
|
|
Signed-off-by: Jiahui Cen <cenjiahui(a)huawei.com>
|
||
|
|
Signed-off-by: Ying Fang <fangying1(a)huawei.com>
|
||
|
|
Signed-off-by: Alex Chen <alex.chen@huawei.com>
|
||
|
|
---
|
||
|
|
block/block-backend.c | 13 ++++--
|
||
|
|
blockdev.c | 50 +++++++++++++++++++++
|
||
|
|
hw/block/block.c | 10 +++++
|
||
|
|
include/hw/block/block.h | 7 ++-
|
||
|
|
include/sysemu/block-backend-common.h | 3 ++
|
||
|
|
include/sysemu/block-backend-global-state.h | 2 +
|
||
|
|
6 files changed, 81 insertions(+), 4 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/block/block-backend.c b/block/block-backend.c
|
||
|
|
index 919699bb70..85d732de7e 100644
|
||
|
|
--- a/block/block-backend.c
|
||
|
|
+++ b/block/block-backend.c
|
||
|
|
@@ -33,9 +33,6 @@
|
||
|
|
|
||
|
|
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
|
||
|
|
|
||
|
|
-/* block backend default retry interval */
|
||
|
|
-#define BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL 1000
|
||
|
|
-
|
||
|
|
typedef struct BlockBackendAioNotifier {
|
||
|
|
void (*attached_aio_context)(AioContext *new_context, void *opaque);
|
||
|
|
void (*detach_aio_context)(void *opaque);
|
||
|
|
@@ -2149,6 +2146,16 @@ void blk_drain_all(void)
|
||
|
|
bdrv_drain_all_end();
|
||
|
|
}
|
||
|
|
|
||
|
|
+void blk_set_on_error_retry_interval(BlockBackend *blk, int64_t interval)
|
||
|
|
+{
|
||
|
|
+ blk->retry_interval = interval;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void blk_set_on_error_retry_timeout(BlockBackend *blk, int64_t timeout)
|
||
|
|
+{
|
||
|
|
+ blk->retry_timeout = timeout;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static bool blk_error_retry_timeout(BlockBackend *blk)
|
||
|
|
{
|
||
|
|
/* No timeout set, infinite retries. */
|
||
|
|
diff --git a/blockdev.c b/blockdev.c
|
||
|
|
index 2817f73fad..6a229e77a5 100644
|
||
|
|
--- a/blockdev.c
|
||
|
|
+++ b/blockdev.c
|
||
|
|
@@ -484,6 +484,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||
|
|
const char *buf;
|
||
|
|
int bdrv_flags = 0;
|
||
|
|
int on_read_error, on_write_error;
|
||
|
|
+ int64_t retry_interval, retry_timeout;
|
||
|
|
OnOffAuto account_invalid, account_failed;
|
||
|
|
bool writethrough, read_only;
|
||
|
|
BlockBackend *blk;
|
||
|
|
@@ -576,6 +577,10 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
+ retry_interval = qemu_opt_get_number(opts, "retry_interval",
|
||
|
|
+ BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL);
|
||
|
|
+ retry_timeout = qemu_opt_get_number(opts, "retry_timeout", 0);
|
||
|
|
+
|
||
|
|
if (snapshot) {
|
||
|
|
bdrv_flags |= BDRV_O_SNAPSHOT;
|
||
|
|
}
|
||
|
|
@@ -639,6 +644,11 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||
|
|
|
||
|
|
blk_set_enable_write_cache(blk, !writethrough);
|
||
|
|
blk_set_on_error(blk, on_read_error, on_write_error);
|
||
|
|
+ if (on_read_error == BLOCKDEV_ON_ERROR_RETRY ||
|
||
|
|
+ on_write_error == BLOCKDEV_ON_ERROR_RETRY) {
|
||
|
|
+ blk_set_on_error_retry_interval(blk, retry_interval);
|
||
|
|
+ blk_set_on_error_retry_timeout(blk, retry_timeout);
|
||
|
|
+ }
|
||
|
|
|
||
|
|
if (!monitor_add_blk(blk, id, errp)) {
|
||
|
|
blk_unref(blk);
|
||
|
|
@@ -773,6 +783,14 @@ QemuOptsList qemu_legacy_drive_opts = {
|
||
|
|
.name = "werror",
|
||
|
|
.type = QEMU_OPT_STRING,
|
||
|
|
.help = "write error action",
|
||
|
|
+ },{
|
||
|
|
+ .name = "retry_interval",
|
||
|
|
+ .type = QEMU_OPT_NUMBER,
|
||
|
|
+ .help = "interval for retry action in millisecond",
|
||
|
|
+ },{
|
||
|
|
+ .name = "retry_timeout",
|
||
|
|
+ .type = QEMU_OPT_NUMBER,
|
||
|
|
+ .help = "timeout for retry action in millisecond",
|
||
|
|
},{
|
||
|
|
.name = "copy-on-read",
|
||
|
|
.type = QEMU_OPT_BOOL,
|
||
|
|
@@ -795,6 +813,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type,
|
||
|
|
BlockInterfaceType type;
|
||
|
|
int max_devs, bus_id, unit_id, index;
|
||
|
|
const char *werror, *rerror;
|
||
|
|
+ int64_t retry_interval, retry_timeout;
|
||
|
|
bool read_only = false;
|
||
|
|
bool copy_on_read;
|
||
|
|
const char *filename;
|
||
|
|
@@ -1013,6 +1032,29 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type,
|
||
|
|
qdict_put_str(bs_opts, "rerror", rerror);
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (qemu_opt_find(legacy_opts, "retry_interval")) {
|
||
|
|
+ if ((werror == NULL || strcmp(werror, "retry")) &&
|
||
|
|
+ (rerror == NULL || strcmp(rerror, "retry"))) {
|
||
|
|
+ error_setg(errp, "retry_interval is only supported "
|
||
|
|
+ "by werror/rerror=retry");
|
||
|
|
+ goto fail;
|
||
|
|
+ }
|
||
|
|
+ retry_interval = qemu_opt_get_number(legacy_opts, "retry_interval",
|
||
|
|
+ BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL);
|
||
|
|
+ qdict_put_int(bs_opts, "retry_interval", retry_interval);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (qemu_opt_find(legacy_opts, "retry_timeout")) {
|
||
|
|
+ if ((werror == NULL || strcmp(werror, "retry")) &&
|
||
|
|
+ (rerror == NULL || strcmp(rerror, "retry"))) {
|
||
|
|
+ error_setg(errp, "retry_timeout is only supported "
|
||
|
|
+ "by werror/rerror=retry");
|
||
|
|
+ goto fail;
|
||
|
|
+ }
|
||
|
|
+ retry_timeout = qemu_opt_get_number(legacy_opts, "retry_timeout", 0);
|
||
|
|
+ qdict_put_int(bs_opts, "retry_timeout", retry_timeout);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
/* Actual block device init: Functionality shared with blockdev-add */
|
||
|
|
blk = blockdev_init(filename, bs_opts, errp);
|
||
|
|
bs_opts = NULL;
|
||
|
|
@@ -3794,6 +3836,14 @@ QemuOptsList qemu_common_drive_opts = {
|
||
|
|
.name = "werror",
|
||
|
|
.type = QEMU_OPT_STRING,
|
||
|
|
.help = "write error action",
|
||
|
|
+ },{
|
||
|
|
+ .name = "retry_interval",
|
||
|
|
+ .type = QEMU_OPT_NUMBER,
|
||
|
|
+ .help = "interval for retry action in millisecond",
|
||
|
|
+ },{
|
||
|
|
+ .name = "retry_timeout",
|
||
|
|
+ .type = QEMU_OPT_NUMBER,
|
||
|
|
+ .help = "timeout for retry action in millisecond",
|
||
|
|
},{
|
||
|
|
.name = BDRV_OPT_READ_ONLY,
|
||
|
|
.type = QEMU_OPT_BOOL,
|
||
|
|
diff --git a/hw/block/block.c b/hw/block/block.c
|
||
|
|
index 9f52ee6e72..6bece87709 100644
|
||
|
|
--- a/hw/block/block.c
|
||
|
|
+++ b/hw/block/block.c
|
||
|
|
@@ -239,6 +239,16 @@ bool blkconf_apply_backend_options(BlockConf *conf, bool readonly,
|
||
|
|
blk_set_enable_write_cache(blk, wce);
|
||
|
|
blk_set_on_error(blk, rerror, werror);
|
||
|
|
|
||
|
|
+ if (rerror == BLOCKDEV_ON_ERROR_RETRY ||
|
||
|
|
+ werror == BLOCKDEV_ON_ERROR_RETRY) {
|
||
|
|
+ if (conf->retry_interval >= 0) {
|
||
|
|
+ blk_set_on_error_retry_interval(blk, conf->retry_interval);
|
||
|
|
+ }
|
||
|
|
+ if (conf->retry_timeout >= 0) {
|
||
|
|
+ blk_set_on_error_retry_timeout(blk, conf->retry_timeout);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
block_acct_setup(blk_get_stats(blk), conf->account_invalid,
|
||
|
|
conf->account_failed);
|
||
|
|
return true;
|
||
|
|
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
|
||
|
|
index 15fff66435..fb8c0df4a5 100644
|
||
|
|
--- a/include/hw/block/block.h
|
||
|
|
+++ b/include/hw/block/block.h
|
||
|
|
@@ -34,6 +34,8 @@ typedef struct BlockConf {
|
||
|
|
OnOffAuto account_invalid, account_failed;
|
||
|
|
BlockdevOnError rerror;
|
||
|
|
BlockdevOnError werror;
|
||
|
|
+ int64_t retry_interval;
|
||
|
|
+ int64_t retry_timeout;
|
||
|
|
} BlockConf;
|
||
|
|
|
||
|
|
static inline unsigned int get_physical_block_exp(BlockConf *conf)
|
||
|
|
@@ -84,7 +86,10 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
|
||
|
|
DEFINE_PROP_BLOCKDEV_ON_ERROR("rerror", _state, _conf.rerror, \
|
||
|
|
BLOCKDEV_ON_ERROR_AUTO), \
|
||
|
|
DEFINE_PROP_BLOCKDEV_ON_ERROR("werror", _state, _conf.werror, \
|
||
|
|
- BLOCKDEV_ON_ERROR_AUTO)
|
||
|
|
+ BLOCKDEV_ON_ERROR_AUTO), \
|
||
|
|
+ DEFINE_PROP_INT64("retry_interval", _state, _conf.retry_interval, \
|
||
|
|
+ -1), \
|
||
|
|
+ DEFINE_PROP_INT64("retry_timeout", _state, _conf.retry_timeout, -1)
|
||
|
|
|
||
|
|
/* Backend access helpers */
|
||
|
|
|
||
|
|
diff --git a/include/sysemu/block-backend-common.h b/include/sysemu/block-backend-common.h
|
||
|
|
index b76df8834a..5a1cdac9c4 100644
|
||
|
|
--- a/include/sysemu/block-backend-common.h
|
||
|
|
+++ b/include/sysemu/block-backend-common.h
|
||
|
|
@@ -16,6 +16,9 @@
|
||
|
|
#include "qemu/iov.h"
|
||
|
|
#include "block/throttle-groups.h"
|
||
|
|
|
||
|
|
+/* block backend default retry interval */
|
||
|
|
+#define BLOCK_BACKEND_DEFAULT_RETRY_INTERVAL 1000
|
||
|
|
+
|
||
|
|
/*
|
||
|
|
* TODO Have to include block/block.h for a bunch of block layer
|
||
|
|
* types. Unfortunately, this pulls in the whole BlockDriverState
|
||
|
|
diff --git a/include/sysemu/block-backend-global-state.h b/include/sysemu/block-backend-global-state.h
|
||
|
|
index 7f59fd411d..d56592c22e 100644
|
||
|
|
--- a/include/sysemu/block-backend-global-state.h
|
||
|
|
+++ b/include/sysemu/block-backend-global-state.h
|
||
|
|
@@ -84,6 +84,8 @@ int blk_commit_all(void);
|
||
|
|
bool blk_in_drain(BlockBackend *blk);
|
||
|
|
void blk_drain(BlockBackend *blk);
|
||
|
|
void blk_drain_all(void);
|
||
|
|
+void blk_set_on_error_retry_interval(BlockBackend *blk, int64_t interval);
|
||
|
|
+void blk_set_on_error_retry_timeout(BlockBackend *blk, int64_t timeout);
|
||
|
|
void blk_error_retry_reset_timeout(BlockBackend *blk);
|
||
|
|
void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,
|
||
|
|
BlockdevOnError on_write_error);
|
||
|
|
--
|
||
|
|
2.27.0
|
||
|
|
|