aboutsummaryrefslogtreecommitdiff
path: root/block/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/io.c')
-rw-r--r--block/io.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/block/io.c b/block/io.c
index ca2dca3007..35b6c56efc 100644
--- a/block/io.c
+++ b/block/io.c
@@ -133,13 +133,40 @@ static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src)
dst->max_iov = MIN_NON_ZERO(dst->max_iov, src->max_iov);
}
-void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
+typedef struct BdrvRefreshLimitsState {
+ BlockDriverState *bs;
+ BlockLimits old_bl;
+} BdrvRefreshLimitsState;
+
+static void bdrv_refresh_limits_abort(void *opaque)
+{
+ BdrvRefreshLimitsState *s = opaque;
+
+ s->bs->bl = s->old_bl;
+}
+
+static TransactionActionDrv bdrv_refresh_limits_drv = {
+ .abort = bdrv_refresh_limits_abort,
+ .clean = g_free,
+};
+
+/* @tran is allowed to be NULL, in this case no rollback is possible. */
+void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp)
{
ERRP_GUARD();
BlockDriver *drv = bs->drv;
BdrvChild *c;
bool have_limits;
+ if (tran) {
+ BdrvRefreshLimitsState *s = g_new(BdrvRefreshLimitsState, 1);
+ *s = (BdrvRefreshLimitsState) {
+ .bs = bs,
+ .old_bl = bs->bl,
+ };
+ tran_add(tran, &bdrv_refresh_limits_drv, s);
+ }
+
memset(&bs->bl, 0, sizeof(bs->bl));
if (!drv) {
@@ -156,7 +183,7 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
QLIST_FOREACH(c, &bs->children, next) {
if (c->role & (BDRV_CHILD_DATA | BDRV_CHILD_FILTERED | BDRV_CHILD_COW))
{
- bdrv_refresh_limits(c->bs, errp);
+ bdrv_refresh_limits(c->bs, tran, errp);
if (*errp) {
return;
}