@@ -313,14 +313,16 @@ struct BlockDriver {
int GRAPH_RDLOCK_PTR (*bdrv_inactivate)(BlockDriverState *bs);
- int (*bdrv_snapshot_create)(BlockDriverState *bs,
- QEMUSnapshotInfo *sn_info);
- int (*bdrv_snapshot_goto)(BlockDriverState *bs,
- const char *snapshot_id);
- int (*bdrv_snapshot_delete)(BlockDriverState *bs,
- const char *snapshot_id,
- const char *name,
- Error **errp);
+ int GRAPH_RDLOCK_PTR (*bdrv_snapshot_create)(
+ BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
+
+ int GRAPH_UNLOCKED_PTR (*bdrv_snapshot_goto)(
+ BlockDriverState *bs, const char *snapshot_id);
+
+ int GRAPH_RDLOCK_PTR (*bdrv_snapshot_delete)(
+ BlockDriverState *bs, const char *snapshot_id, const char *name,
+ Error **errp);
+
int (*bdrv_snapshot_list)(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info);
int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,
@@ -25,6 +25,7 @@
#ifndef SNAPSHOT_H
#define SNAPSHOT_H
+#include "block/graph-lock.h"
#include "qapi/qapi-builtin-types.h"
#define SNAPSHOT_OPT_BASE "snapshot."
@@ -59,16 +60,19 @@ bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
const char *name,
QEMUSnapshotInfo *sn_info,
Error **errp);
-int bdrv_can_snapshot(BlockDriverState *bs);
-int bdrv_snapshot_create(BlockDriverState *bs,
- QEMUSnapshotInfo *sn_info);
-int bdrv_snapshot_goto(BlockDriverState *bs,
- const char *snapshot_id,
- Error **errp);
-int bdrv_snapshot_delete(BlockDriverState *bs,
- const char *snapshot_id,
- const char *name,
- Error **errp);
+
+int GRAPH_RDLOCK bdrv_can_snapshot(BlockDriverState *bs);
+
+int GRAPH_RDLOCK
+bdrv_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
+
+int GRAPH_UNLOCKED
+bdrv_snapshot_goto(BlockDriverState *bs, const char *snapshot_id, 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,
QEMUSnapshotInfo **psn_info);
int bdrv_snapshot_load_tmp(BlockDriverState *bs,
@@ -155,11 +155,15 @@ bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
* back if the given BDS does not support snapshots.
* 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 *child;
+ GLOBAL_STATE_CODE();
+ assert_bdrv_graph_readable();
+
/* We allow fallback only to primary child */
if (!fallback) {
return NULL;
@@ -182,8 +186,10 @@ static BdrvChild *bdrv_snapshot_fallback_child(BlockDriverState *bs)
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));
}
@@ -254,7 +260,10 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
return ret;
}
+ bdrv_graph_rdlock_main_loop();
fallback = bdrv_snapshot_fallback_child(bs);
+ bdrv_graph_rdunlock_main_loop();
+
if (fallback) {
QDict *options;
QDict *file_options;
@@ -374,10 +383,12 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
int bdrv_snapshot_list(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info)
{
+ GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
BlockDriver *drv = bs->drv;
BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs);
- GLOBAL_STATE_CODE();
if (!drv) {
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)
{
+ GLOBAL_STATE_CODE();
+ assert_bdrv_graph_readable();
+
if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
return false;
}
@@ -595,11 +609,15 @@ int bdrv_all_goto_snapshot(const char *name,
{
g_autoptr(GList) bdrvs = NULL;
GList *iterbdrvs;
+ int ret;
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;
}
@@ -608,9 +626,14 @@ int bdrv_all_goto_snapshot(const char *name,
BlockDriverState *bs = iterbdrvs->data;
AioContext *ctx = bdrv_get_aio_context(bs);
int ret = 0;
+ bool all_snapshots_includes_bs;
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);
}
aio_context_release(ctx);
@@ -1138,6 +1138,9 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
SnapshotInfo *info = NULL;
int ret;
+ GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
bs = qmp_get_root_bs(device, errp);
if (!bs) {
return NULL;
@@ -1223,6 +1226,9 @@ static void internal_snapshot_action(BlockdevSnapshotInternal *internal,
AioContext *aio_context;
int ret1;
+ GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
tran_add(tran, &internal_snapshot_drv, state);
device = internal->device;
@@ -1311,6 +1317,9 @@ static void internal_snapshot_abort(void *opaque)
AioContext *aio_context;
Error *local_error = NULL;
+ GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
if (!state->created) {
return;
}
@@ -3470,7 +3470,10 @@ static int img_snapshot(int argc, char **argv)
sn.date_sec = rt / G_USEC_PER_SEC;
sn.date_nsec = (rt % G_USEC_PER_SEC) * 1000;
+ bdrv_graph_rdlock_main_loop();
ret = bdrv_snapshot_create(bs, &sn);
+ bdrv_graph_rdunlock_main_loop();
+
if (ret) {
error_report("Could not create snapshot '%s': %s",
snapshot_name, strerror(-ret));
@@ -3486,6 +3489,7 @@ static int img_snapshot(int argc, char **argv)
break;
case SNAPSHOT_DELETE:
+ bdrv_graph_rdlock_main_loop();
ret = bdrv_snapshot_find(bs, &sn, snapshot_name);
if (ret < 0) {
error_report("Could not delete snapshot '%s': snapshot not "
@@ -3499,6 +3503,7 @@ static int img_snapshot(int argc, char **argv)
ret = 1;
}
}
+ bdrv_graph_rdunlock_main_loop();
break;
}