block: Mark bdrv_snapshot_fallback() and callers GRAPH_RDLOCK

This adds GRAPH_RDLOCK annotations to declare that callers of
bdrv_snapshot_fallback() need to hold a reader lock for the graph
because it accesses the children list of a node.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20230929145157.45443-8-kwolf@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Kevin Wolf 2023-09-29 16:51:42 +02:00
parent 7859c45a46
commit a32e781838
5 changed files with 67 additions and 24 deletions

View file

@ -155,11 +155,15 @@ bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
* back if the given BDS does not support snapshots. * back if the given BDS does not support snapshots.
* Return NULL if there is no BDS to (safely) fall back to. * Return NULL if there is no BDS to (safely) fall back to.
*/ */
static BdrvChild *bdrv_snapshot_fallback_child(BlockDriverState *bs) static BdrvChild * GRAPH_RDLOCK
bdrv_snapshot_fallback_child(BlockDriverState *bs)
{ {
BdrvChild *fallback = bdrv_primary_child(bs); BdrvChild *fallback = bdrv_primary_child(bs);
BdrvChild *child; BdrvChild *child;
GLOBAL_STATE_CODE();
assert_bdrv_graph_readable();
/* We allow fallback only to primary child */ /* We allow fallback only to primary child */
if (!fallback) { if (!fallback) {
return NULL; return NULL;
@ -182,8 +186,10 @@ static BdrvChild *bdrv_snapshot_fallback_child(BlockDriverState *bs)
return fallback; return fallback;
} }
static BlockDriverState *bdrv_snapshot_fallback(BlockDriverState *bs) static BlockDriverState * GRAPH_RDLOCK
bdrv_snapshot_fallback(BlockDriverState *bs)
{ {
GLOBAL_STATE_CODE();
return child_bs(bdrv_snapshot_fallback_child(bs)); return child_bs(bdrv_snapshot_fallback_child(bs));
} }
@ -254,7 +260,10 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
return ret; return ret;
} }
bdrv_graph_rdlock_main_loop();
fallback = bdrv_snapshot_fallback_child(bs); fallback = bdrv_snapshot_fallback_child(bs);
bdrv_graph_rdunlock_main_loop();
if (fallback) { if (fallback) {
QDict *options; QDict *options;
QDict *file_options; QDict *file_options;
@ -374,10 +383,12 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
int bdrv_snapshot_list(BlockDriverState *bs, int bdrv_snapshot_list(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info) QEMUSnapshotInfo **psn_info)
{ {
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs); BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs);
GLOBAL_STATE_CODE();
if (!drv) { if (!drv) {
return -ENOMEDIUM; return -ENOMEDIUM;
} }
@ -498,6 +509,9 @@ bdrv_all_get_snapshot_devices(bool has_devices, strList *devices,
static bool GRAPH_RDLOCK bdrv_all_snapshots_includes_bs(BlockDriverState *bs) static bool GRAPH_RDLOCK bdrv_all_snapshots_includes_bs(BlockDriverState *bs)
{ {
GLOBAL_STATE_CODE();
assert_bdrv_graph_readable();
if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
return false; return false;
} }
@ -595,11 +609,15 @@ int bdrv_all_goto_snapshot(const char *name,
{ {
g_autoptr(GList) bdrvs = NULL; g_autoptr(GList) bdrvs = NULL;
GList *iterbdrvs; GList *iterbdrvs;
int ret;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { bdrv_graph_rdlock_main_loop();
ret = bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp);
bdrv_graph_rdunlock_main_loop();
if (ret < 0) {
return -1; return -1;
} }
@ -608,9 +626,14 @@ int bdrv_all_goto_snapshot(const char *name,
BlockDriverState *bs = iterbdrvs->data; BlockDriverState *bs = iterbdrvs->data;
AioContext *ctx = bdrv_get_aio_context(bs); AioContext *ctx = bdrv_get_aio_context(bs);
int ret = 0; int ret = 0;
bool all_snapshots_includes_bs;
aio_context_acquire(ctx); aio_context_acquire(ctx);
if (devices || bdrv_all_snapshots_includes_bs(bs)) { bdrv_graph_rdlock_main_loop();
all_snapshots_includes_bs = bdrv_all_snapshots_includes_bs(bs);
bdrv_graph_rdunlock_main_loop();
if (devices || all_snapshots_includes_bs) {
ret = bdrv_snapshot_goto(bs, name, errp); ret = bdrv_snapshot_goto(bs, name, errp);
} }
aio_context_release(ctx); aio_context_release(ctx);

View file

@ -1138,6 +1138,9 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
SnapshotInfo *info = NULL; SnapshotInfo *info = NULL;
int ret; int ret;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
bs = qmp_get_root_bs(device, errp); bs = qmp_get_root_bs(device, errp);
if (!bs) { if (!bs) {
return NULL; return NULL;
@ -1223,6 +1226,9 @@ static void internal_snapshot_action(BlockdevSnapshotInternal *internal,
AioContext *aio_context; AioContext *aio_context;
int ret1; int ret1;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
tran_add(tran, &internal_snapshot_drv, state); tran_add(tran, &internal_snapshot_drv, state);
device = internal->device; device = internal->device;
@ -1311,6 +1317,9 @@ static void internal_snapshot_abort(void *opaque)
AioContext *aio_context; AioContext *aio_context;
Error *local_error = NULL; Error *local_error = NULL;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!state->created) { if (!state->created) {
return; return;
} }

View file

@ -313,14 +313,16 @@ struct BlockDriver {
int GRAPH_RDLOCK_PTR (*bdrv_inactivate)(BlockDriverState *bs); int GRAPH_RDLOCK_PTR (*bdrv_inactivate)(BlockDriverState *bs);
int (*bdrv_snapshot_create)(BlockDriverState *bs, int GRAPH_RDLOCK_PTR (*bdrv_snapshot_create)(
QEMUSnapshotInfo *sn_info); BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
int (*bdrv_snapshot_goto)(BlockDriverState *bs,
const char *snapshot_id); int GRAPH_UNLOCKED_PTR (*bdrv_snapshot_goto)(
int (*bdrv_snapshot_delete)(BlockDriverState *bs, BlockDriverState *bs, const char *snapshot_id);
const char *snapshot_id,
const char *name, int GRAPH_RDLOCK_PTR (*bdrv_snapshot_delete)(
Error **errp); BlockDriverState *bs, const char *snapshot_id, const char *name,
Error **errp);
int (*bdrv_snapshot_list)(BlockDriverState *bs, int (*bdrv_snapshot_list)(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info); QEMUSnapshotInfo **psn_info);
int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs, int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,

View file

@ -25,6 +25,7 @@
#ifndef SNAPSHOT_H #ifndef SNAPSHOT_H
#define SNAPSHOT_H #define SNAPSHOT_H
#include "block/graph-lock.h"
#include "qapi/qapi-builtin-types.h" #include "qapi/qapi-builtin-types.h"
#define SNAPSHOT_OPT_BASE "snapshot." #define SNAPSHOT_OPT_BASE "snapshot."
@ -59,16 +60,19 @@ bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
const char *name, const char *name,
QEMUSnapshotInfo *sn_info, QEMUSnapshotInfo *sn_info,
Error **errp); Error **errp);
int bdrv_can_snapshot(BlockDriverState *bs);
int bdrv_snapshot_create(BlockDriverState *bs, int GRAPH_RDLOCK bdrv_can_snapshot(BlockDriverState *bs);
QEMUSnapshotInfo *sn_info);
int bdrv_snapshot_goto(BlockDriverState *bs, int GRAPH_RDLOCK
const char *snapshot_id, bdrv_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
Error **errp);
int bdrv_snapshot_delete(BlockDriverState *bs, int GRAPH_UNLOCKED
const char *snapshot_id, bdrv_snapshot_goto(BlockDriverState *bs, const char *snapshot_id, Error **errp);
const char *name,
Error **errp); int GRAPH_RDLOCK
bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id,
const char *name, Error **errp);
int bdrv_snapshot_list(BlockDriverState *bs, int bdrv_snapshot_list(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info); QEMUSnapshotInfo **psn_info);
int bdrv_snapshot_load_tmp(BlockDriverState *bs, int bdrv_snapshot_load_tmp(BlockDriverState *bs,

View file

@ -3470,7 +3470,10 @@ static int img_snapshot(int argc, char **argv)
sn.date_sec = rt / G_USEC_PER_SEC; sn.date_sec = rt / G_USEC_PER_SEC;
sn.date_nsec = (rt % G_USEC_PER_SEC) * 1000; sn.date_nsec = (rt % G_USEC_PER_SEC) * 1000;
bdrv_graph_rdlock_main_loop();
ret = bdrv_snapshot_create(bs, &sn); ret = bdrv_snapshot_create(bs, &sn);
bdrv_graph_rdunlock_main_loop();
if (ret) { if (ret) {
error_report("Could not create snapshot '%s': %s", error_report("Could not create snapshot '%s': %s",
snapshot_name, strerror(-ret)); snapshot_name, strerror(-ret));
@ -3486,6 +3489,7 @@ static int img_snapshot(int argc, char **argv)
break; break;
case SNAPSHOT_DELETE: case SNAPSHOT_DELETE:
bdrv_graph_rdlock_main_loop();
ret = bdrv_snapshot_find(bs, &sn, snapshot_name); ret = bdrv_snapshot_find(bs, &sn, snapshot_name);
if (ret < 0) { if (ret < 0) {
error_report("Could not delete snapshot '%s': snapshot not " error_report("Could not delete snapshot '%s': snapshot not "
@ -3499,6 +3503,7 @@ static int img_snapshot(int argc, char **argv)
ret = 1; ret = 1;
} }
} }
bdrv_graph_rdunlock_main_loop();
break; break;
} }