Message ID | 20250326092634.1691355-3-zoudongjie@huawei.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | qapi/throttle: Fix qmp_block_set_io_throttle blocked for too long | expand |
zoudongjie via <qemu-devel@nongnu.org> writes: > From: Zhu Yangyang <zhuyangyang14@huawei.com> > > Calling qmp_block_set_io_throttle() will be blocked for a long time > when a network disk is configured and the network failure is just about > to occur. > > Therefore, we add a timeout parameter for qmp_block_set_io_throttle to control > its execution duration. What's the QMP reply when a block_set_io_throttle command times out? > > The default value of timeout is 0, that is infinite wait, consistent with > previous behavior. > > Signed-off-by: Zhu Yangyang <zhuyangyang14@huawei.com> [...] > diff --git a/qapi/block-core.json b/qapi/block-core.json > index b1937780e1..88ef593efd 100644 > --- a/qapi/block-core.json > +++ b/qapi/block-core.json > @@ -2626,6 +2626,9 @@ > # > # @group: throttle group name (Since 2.4) > # > +# @timeout: In seconds. Timeout for block_set_io_throttle, > +# 0 means no limit. Defaults to 0. (Since 10.0) Make that 10.1, since it won't make 10.0. > +# > # Features: > # > # @deprecated: Member @device is deprecated. Use @id instead. > @@ -2642,7 +2645,7 @@ > '*bps_max_length': 'int', '*bps_rd_max_length': 'int', > '*bps_wr_max_length': 'int', '*iops_max_length': 'int', > '*iops_rd_max_length': 'int', '*iops_wr_max_length': 'int', > - '*iops_size': 'int', '*group': 'str' } } > + '*iops_size': 'int', '*group': 'str', '*timeout': 'uint32'} } > > ## > # @ThrottleLimits:
On Wed, Mar 26, 2025 at 10:53:20 +0100, Markus wrote: > zoudongjie via <qemu-devel@nongnu.org> writes: > > > From: Zhu Yangyang <zhuyangyang14@huawei.com> > > > > Calling qmp_block_set_io_throttle() will be blocked for a long time > > when a network disk is configured and the network failure is just about > > to occur. > > > > Therefore, we add a timeout parameter for qmp_block_set_io_throttle to control > > its execution duration. > > What's the QMP reply when a block_set_io_throttle command times out? The reply is: {"id":"libvirt-484","error":{"class":"GenericError","desc":"Blk io limits disable timeout"}} > > > > > The default value of timeout is 0, that is infinite wait, consistent with > > previous behavior. > > > > Signed-off-by: Zhu Yangyang <zhuyangyang14@huawei.com> > > [...] > > > diff --git a/qapi/block-core.json b/qapi/block-core.json > > index b1937780e1..88ef593efd 100644 > > --- a/qapi/block-core.json > > +++ b/qapi/block-core.json > > @@ -2626,6 +2626,9 @@ > > # > > # @group: throttle group name (Since 2.4) > > # > > +# @timeout: In seconds. Timeout for block_set_io_throttle, > > +# 0 means no limit. Defaults to 0. (Since 10.0) > > Make that 10.1, since it won't make 10.0. Ok, I'll correct it in the next version. > > > +# > > # Features: > > # > > # @deprecated: Member @device is deprecated. Use @id instead. > > @@ -2642,7 +2645,7 @@ > > '*bps_max_length': 'int', '*bps_rd_max_length': 'int', > > '*bps_wr_max_length': 'int', '*iops_max_length': 'int', > > '*iops_rd_max_length': 'int', '*iops_wr_max_length': 'int', > > - '*iops_size': 'int', '*group': 'str' } } > > + '*iops_size': 'int', '*group': 'str', '*timeout': 'uint32'} } > > > > ## > > # @ThrottleLimits:
zoudongjie <zoudongjie@huawei.com> writes: > On Wed, Mar 26, 2025 at 10:53:20 +0100, Markus wrote: >> zoudongjie via <qemu-devel@nongnu.org> writes: >> >> > From: Zhu Yangyang <zhuyangyang14@huawei.com> >> > >> > Calling qmp_block_set_io_throttle() will be blocked for a long time >> > when a network disk is configured and the network failure is just about >> > to occur. What other commands could similarly block? >> > Therefore, we add a timeout parameter for qmp_block_set_io_throttle to control >> > its execution duration. >> >> What's the QMP reply when a block_set_io_throttle command times out? > > The reply is: > {"id":"libvirt-484","error":{"class":"GenericError","desc":"Blk io limits disable timeout"}} I find the error message confusing. Suggest "command timed out". >> > >> > The default value of timeout is 0, that is infinite wait, consistent with >> > previous behavior. >> > >> > Signed-off-by: Zhu Yangyang <zhuyangyang14@huawei.com> [...]
On Thu, 27 Mar 2025 09:04:51 +0100, Markus wrote: > zoudongjie <zoudongjie@huawei.com> writes: > > > On Wed, Mar 26, 2025 at 10:53:20 +0100, Markus wrote: > >> zoudongjie via <qemu-devel@nongnu.org> writes: > >> > >> > From: Zhu Yangyang <zhuyangyang14@huawei.com> > >> > > >> > Calling qmp_block_set_io_throttle() will be blocked for a long time > >> > when a network disk is configured and the network failure is just about > >> > to occur. > > What other commands could similarly block? In theory, any command may be blocked if it calls bdrv_drained_begin(). I did a quick check, qmp_block_resize() could similarly block, since it called bdrv_drained_begin(), I'm going to verify it later. > > >> > Therefore, we add a timeout parameter for qmp_block_set_io_throttle to control > >> > its execution duration. > >> > >> What's the QMP reply when a block_set_io_throttle command times out? > > > > The reply is: > > {"id":"libvirt-484","error":{"class":"GenericError","desc":"Blk io limits disable timeout"}} > > I find the error message confusing. Suggest "command timed out". This message doesn't provide more details about the error, especially for developers. How about using "command timed out: disable I/O limits" > > >> > > >> > The default value of timeout is 0, that is infinite wait, consistent with > >> > previous behavior. > >> > > >> > Signed-off-by: Zhu Yangyang <zhuyangyang14@huawei.com> > > [...]
zoudongjie <zoudongjie@huawei.com> writes: > On Thu, 27 Mar 2025 09:04:51 +0100, Markus wrote: >> zoudongjie <zoudongjie@huawei.com> writes: >> >> > On Wed, Mar 26, 2025 at 10:53:20 +0100, Markus wrote: >> >> zoudongjie via <qemu-devel@nongnu.org> writes: >> >> >> >> > From: Zhu Yangyang <zhuyangyang14@huawei.com> >> >> > >> >> > Calling qmp_block_set_io_throttle() will be blocked for a long time >> >> > when a network disk is configured and the network failure is just about >> >> > to occur. >> >> What other commands could similarly block? > > In theory, any command may be blocked if it calls bdrv_drained_begin(). > I did a quick check, qmp_block_resize() could similarly block, since it called > bdrv_drained_begin(), I'm going to verify it later. Please do. Should all these commands support time out? >> >> > Therefore, we add a timeout parameter for qmp_block_set_io_throttle to control >> >> > its execution duration. >> >> >> >> What's the QMP reply when a block_set_io_throttle command times out? >> > >> > The reply is: >> > {"id":"libvirt-484","error":{"class":"GenericError","desc":"Blk io limits disable timeout"}} >> >> I find the error message confusing. Suggest "command timed out". > > This message doesn't provide more details about the error, especially for developers. > How about using "command timed out: disable I/O limits" I don't get what "disable I/O limits" is trying to tell the user. Can you explain? >> >> > The default value of timeout is 0, that is infinite wait, consistent with >> >> > previous behavior. >> >> > >> >> > Signed-off-by: Zhu Yangyang <zhuyangyang14@huawei.com> >> >> [...]
On Thu, 27 Mar 2025 09:04:51 +0100, Markus wrote: > zoudongjie <zoudongjie@huawei.com> writes: > > > On Wed, Mar 26, 2025 at 10:53:20 +0100, Markus wrote: > >> zoudongjie via <qemu-devel@nongnu.org> writes: > >> > >> > From: Zhu Yangyang <zhuyangyang14@huawei.com> > >> > > >> > Calling qmp_block_set_io_throttle() will be blocked for a long time > >> > when a network disk is configured and the network failure is just about > >> > to occur. > > What other commands could similarly block? In theory, any command may be blocked if it calls bdrv_drained_begin(). I did a quick check, qmp_block_resize() could similarly block, since it called bdrv_drained_begin(), I'm going to verify it later. > > >> > Therefore, we add a timeout parameter for qmp_block_set_io_throttle to control > >> > its execution duration. > >> > >> What's the QMP reply when a block_set_io_throttle command times out? > > > > The reply is: > > {"id":"libvirt-484","error":{"class":"GenericError","desc":"Blk io limits disable timeout"}} > > I find the error message confusing. Suggest "command timed out". This message doesn't provide more details about the error, especially for developers. How about using "command timed out: disable I/O limits" > > >> > > >> > The default value of timeout is 0, that is infinite wait, consistent with > >> > previous behavior. > >> > > >> > Signed-off-by: Zhu Yangyang <zhuyangyang14@huawei.com> > > [...]
I'm sorry for the delay in replying. On Thu, 27 Mar 2025 14:43:54 +0100, Markus wrote: > zoudongjie <zoudongjie@huawei.com> writes: > > On Thu, 27 Mar 2025 09:04:51 +0100, Markus wrote: > >> zoudongjie <zoudongjie@huawei.com> writes: > >> > >> > On Wed, Mar 26, 2025 at 10:53:20 +0100, Markus wrote: > >> >> zoudongjie via <qemu-devel@nongnu.org> writes: > >> >> > >> >> > From: Zhu Yangyang <zhuyangyang14@huawei.com> > >> >> > > >> >> > Calling qmp_block_set_io_throttle() will be blocked for a long time > >> >> > when a network disk is configured and the network failure is just about > >> >> > to occur. > >> > >> What other commands could similarly block? > > > > In theory, any command may be blocked if it calls bdrv_drained_begin(). > > I did a quick check, qmp_block_resize() could similarly block, since it called > > bdrv_drained_begin(), I'm going to verify it later. > > Please do. > > Should all these commands support time out? Yes, I think it is. Later in v4, I'll add timeout support for qmp_block_resize(). If I find a similar block command in the future, I'll email again. > > >> >> > Therefore, we add a timeout parameter for qmp_block_set_io_throttle to control > >> >> > its execution duration. > >> >> > >> >> What's the QMP reply when a block_set_io_throttle command times out? > >> > > >> > The reply is: > >> > {"id":"libvirt-484","error":{"class":"GenericError","desc":"Blk io limits disable timeout"}} > >> > >> I find the error message confusing. Suggest "command timed out". > > > > This message doesn't provide more details about the error, especially for developers. > > How about using "command timed out: disable I/O limits" > > I don't get what "disable I/O limits" is trying to tell the user. Can > you explain? In fact, block_set_io_throttle() has two branches: enable io limits and disable io limits. If there is a possibility of timeout in both branches in command, detailed reason may be useful. But now "command timed out" is enough and I will use it in v4. > > >> >> > The default value of timeout is 0, that is infinite wait, consistent with > >> >> > previous behavior. > >> >> > > >> >> > Signed-off-by: Zhu Yangyang <zhuyangyang14@huawei.com> > >> > >> [...]
diff --git a/block/block-backend.c b/block/block-backend.c index a402db13f2..fc1554ea55 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2679,20 +2679,32 @@ void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg) } void blk_io_limits_disable(BlockBackend *blk) +{ + blk_io_limits_disable_timeout(blk, 0); +} + +int blk_io_limits_disable_timeout(BlockBackend *blk, uint64_t timeout_ns) { BlockDriverState *bs = blk_bs(blk); ThrottleGroupMember *tgm = &blk->public.throttle_group_member; + int ret = 0; + assert(tgm->throttle_state); GLOBAL_STATE_CODE(); if (bs) { bdrv_ref(bs); - bdrv_drained_begin(bs); + ret = bdrv_drained_begin_timeout(bs, timeout_ns); + if (ret < 0) { + goto out; + } } throttle_group_unregister_tgm(tgm); +out: if (bs) { bdrv_drained_end(bs); bdrv_unref(bs); } + return ret; } /* should be called before blk_set_io_limits if a limit is set */ diff --git a/block/qapi-system.c b/block/qapi-system.c index 54b7409b2b..3b7ba0959c 100644 --- a/block/qapi-system.c +++ b/block/qapi-system.c @@ -423,6 +423,7 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp) ThrottleConfig cfg; BlockDriverState *bs; BlockBackend *blk; + uint64_t timeout_ns; blk = qmp_get_blk(arg->device, arg->id, errp); if (!blk) { @@ -444,6 +445,10 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp) cfg.buckets[THROTTLE_OPS_READ].avg = arg->iops_rd; cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr; + timeout_ns = 0; /* 0 means infinite */ + if (arg->has_timeout) { + timeout_ns = arg->timeout * NANOSECONDS_PER_SECOND; + } if (arg->has_bps_max) { cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max; } @@ -502,7 +507,10 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp) blk_set_io_limits(blk, &cfg); } else if (blk_get_public(blk)->throttle_group_member.throttle_state) { /* If all throttling settings are set to 0, disable I/O limits */ - blk_io_limits_disable(blk); + if (blk_io_limits_disable_timeout(blk, timeout_ns) < 0) { + error_setg(errp, "Blk io limits disable timeout"); + return; + } } } diff --git a/include/system/block-backend-global-state.h b/include/system/block-backend-global-state.h index 35b5e8380b..8a2a6cbda4 100644 --- a/include/system/block-backend-global-state.h +++ b/include/system/block-backend-global-state.h @@ -110,6 +110,7 @@ int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo); void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg); void blk_io_limits_disable(BlockBackend *blk); +int blk_io_limits_disable_timeout(BlockBackend *blk, uint64_t timeout_ns); void blk_io_limits_enable(BlockBackend *blk, const char *group); void blk_io_limits_update_group(BlockBackend *blk, const char *group); void blk_set_force_allow_inactivate(BlockBackend *blk); diff --git a/qapi/block-core.json b/qapi/block-core.json index b1937780e1..88ef593efd 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2626,6 +2626,9 @@ # # @group: throttle group name (Since 2.4) # +# @timeout: In seconds. Timeout for block_set_io_throttle, +# 0 means no limit. Defaults to 0. (Since 10.0) +# # Features: # # @deprecated: Member @device is deprecated. Use @id instead. @@ -2642,7 +2645,7 @@ '*bps_max_length': 'int', '*bps_rd_max_length': 'int', '*bps_wr_max_length': 'int', '*iops_max_length': 'int', '*iops_rd_max_length': 'int', '*iops_wr_max_length': 'int', - '*iops_size': 'int', '*group': 'str' } } + '*iops_size': 'int', '*group': 'str', '*timeout': 'uint32'} } ## # @ThrottleLimits: