|
@@ -50,6 +50,8 @@
|
|
|
#include "block/qapi.h"
|
|
|
#include "crypto/init.h"
|
|
|
#include "trace/control.h"
|
|
|
+#include "qemu/throttle.h"
|
|
|
+#include "block/throttle-groups.h"
|
|
|
|
|
|
#define QEMU_IMG_VERSION "qemu-img version " QEMU_FULL_VERSION \
|
|
|
"\n" QEMU_COPYRIGHT "\n"
|
|
@@ -980,6 +982,7 @@ static int img_commit(int argc, char **argv)
|
|
|
CommonBlockJobCBInfo cbi;
|
|
|
bool image_opts = false;
|
|
|
AioContext *aio_context;
|
|
|
+ int64_t rate_limit = 0;
|
|
|
|
|
|
fmt = NULL;
|
|
|
cache = BDRV_DEFAULT_CACHE;
|
|
@@ -991,7 +994,7 @@ static int img_commit(int argc, char **argv)
|
|
|
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
|
|
|
{0, 0, 0, 0}
|
|
|
};
|
|
|
- c = getopt_long(argc, argv, ":f:ht:b:dpq",
|
|
|
+ c = getopt_long(argc, argv, ":f:ht:b:dpqr:",
|
|
|
long_options, NULL);
|
|
|
if (c == -1) {
|
|
|
break;
|
|
@@ -1026,6 +1029,12 @@ static int img_commit(int argc, char **argv)
|
|
|
case 'q':
|
|
|
quiet = true;
|
|
|
break;
|
|
|
+ case 'r':
|
|
|
+ rate_limit = cvtnum("rate limit", optarg);
|
|
|
+ if (rate_limit < 0) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ break;
|
|
|
case OPTION_OBJECT: {
|
|
|
QemuOpts *opts;
|
|
|
opts = qemu_opts_parse_noisily(&qemu_object_opts,
|
|
@@ -1099,7 +1108,7 @@ static int img_commit(int argc, char **argv)
|
|
|
|
|
|
aio_context = bdrv_get_aio_context(bs);
|
|
|
aio_context_acquire(aio_context);
|
|
|
- commit_active_start("commit", bs, base_bs, JOB_DEFAULT, 0,
|
|
|
+ commit_active_start("commit", bs, base_bs, JOB_DEFAULT, rate_limit,
|
|
|
BLOCKDEV_ON_ERROR_REPORT, NULL, common_block_job_cb,
|
|
|
&cbi, false, &local_err);
|
|
|
aio_context_release(aio_context);
|
|
@@ -1662,6 +1671,7 @@ enum ImgConvertBlockStatus {
|
|
|
};
|
|
|
|
|
|
#define MAX_COROUTINES 16
|
|
|
+#define CONVERT_THROTTLE_GROUP "img_convert"
|
|
|
|
|
|
typedef struct ImgConvertState {
|
|
|
BlockBackend **src;
|
|
@@ -2177,6 +2187,17 @@ static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst)
|
|
|
|
|
|
#define MAX_BUF_SECTORS 32768
|
|
|
|
|
|
+static void set_rate_limit(BlockBackend *blk, int64_t rate_limit)
|
|
|
+{
|
|
|
+ ThrottleConfig cfg;
|
|
|
+
|
|
|
+ throttle_config_init(&cfg);
|
|
|
+ cfg.buckets[THROTTLE_BPS_WRITE].avg = rate_limit;
|
|
|
+
|
|
|
+ blk_io_limits_enable(blk, CONVERT_THROTTLE_GROUP);
|
|
|
+ blk_set_io_limits(blk, &cfg);
|
|
|
+}
|
|
|
+
|
|
|
static int img_convert(int argc, char **argv)
|
|
|
{
|
|
|
int c, bs_i, flags, src_flags = 0;
|
|
@@ -2197,6 +2218,7 @@ static int img_convert(int argc, char **argv)
|
|
|
bool force_share = false;
|
|
|
bool explict_min_sparse = false;
|
|
|
bool bitmaps = false;
|
|
|
+ int64_t rate_limit = 0;
|
|
|
|
|
|
ImgConvertState s = (ImgConvertState) {
|
|
|
/* Need at least 4k of zeros for sparse detection */
|
|
@@ -2219,7 +2241,7 @@ static int img_convert(int argc, char **argv)
|
|
|
{"bitmaps", no_argument, 0, OPTION_BITMAPS},
|
|
|
{0, 0, 0, 0}
|
|
|
};
|
|
|
- c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU",
|
|
|
+ c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WUr:",
|
|
|
long_options, NULL);
|
|
|
if (c == -1) {
|
|
|
break;
|
|
@@ -2316,6 +2338,12 @@ static int img_convert(int argc, char **argv)
|
|
|
case 'U':
|
|
|
force_share = true;
|
|
|
break;
|
|
|
+ case 'r':
|
|
|
+ rate_limit = cvtnum("rate limit", optarg);
|
|
|
+ if (rate_limit < 0) {
|
|
|
+ goto fail_getopt;
|
|
|
+ }
|
|
|
+ break;
|
|
|
case OPTION_OBJECT: {
|
|
|
QemuOpts *object_opts;
|
|
|
object_opts = qemu_opts_parse_noisily(&qemu_object_opts,
|
|
@@ -2705,6 +2733,10 @@ static int img_convert(int argc, char **argv)
|
|
|
s.cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;
|
|
|
}
|
|
|
|
|
|
+ if (rate_limit) {
|
|
|
+ set_rate_limit(s.target, rate_limit);
|
|
|
+ }
|
|
|
+
|
|
|
ret = convert_do_copy(&s);
|
|
|
|
|
|
/* Now copy the bitmaps */
|