Block layer patches
- Graph locking part 6 (bs->file/backing) - ahci: trigger either error IRQ or regular IRQ, not both -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmVLvccRHGt3b2xmQHJl ZGhhdC5jb20ACgkQfwmycsiPL9ZkFg//awQoPiGnYzHpqcx2tGCM2AqBV+mFkbZr BKI5vp8FYfJtgMuHjC8jabL24NRMPpT+HbCzoxwjJU+nnnr85qr7R5iGwG6kfgX6 HJlAXYXdY6e7l+FV44PBJ52vOoGCsh1GHg8HlKsHMaxSdXi9C1axHJ6rCAjnWXE0 FQ4znCBVs/9HiKsvu4Wdm5muX2ShftFRM/toAwA+fLEOealX8WEXoRFJXI40bYbR OR7aJXWMDQrljlqdKk2FXvK337/tpofXmXf3NIE1R2pmY4x5Fg8bfChZn4UaaCdN n+0AhmE4ScI0rXuaXXYOvTO9vdTzXeBROG6tX03t9rrQfB6wPcGVeXRo/uusslAW sDH8NLz7uHFOooV02Fs8CKDdVrNNw5qjziclSGa0Po7vqOV1TKI8OTiNpsDLmdI5 +DQvC6N+IU1pSOXImATSHkheGWggsegrsgN6PdrlzHEXJwWoAaRD0T06MRn74/pL gCegK2ez4RJYsci7C5b0gaqY/QBsMj8EUfEGVHvVyuVSoPRwiq4ehPqSQ+siA3xP KxYR0e4+QIfRmxqCzaJhiQ3DDGdt8UcO3yF0XcKXEqWwgFAGQKNeUG314jginvmA iaJzC0dHbiGcagAk7Ey8iyzfxQDWM6ixzJtGv7VLILepzCuu8vaJXy5qeEtTM/ZI EXoDGceNSvw= =ikBW -----END PGP SIGNATURE----- Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging Block layer patches - Graph locking part 6 (bs->file/backing) - ahci: trigger either error IRQ or regular IRQ, not both # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmVLvccRHGt3b2xmQHJl # ZGhhdC5jb20ACgkQfwmycsiPL9ZkFg//awQoPiGnYzHpqcx2tGCM2AqBV+mFkbZr # BKI5vp8FYfJtgMuHjC8jabL24NRMPpT+HbCzoxwjJU+nnnr85qr7R5iGwG6kfgX6 # HJlAXYXdY6e7l+FV44PBJ52vOoGCsh1GHg8HlKsHMaxSdXi9C1axHJ6rCAjnWXE0 # FQ4znCBVs/9HiKsvu4Wdm5muX2ShftFRM/toAwA+fLEOealX8WEXoRFJXI40bYbR # OR7aJXWMDQrljlqdKk2FXvK337/tpofXmXf3NIE1R2pmY4x5Fg8bfChZn4UaaCdN # n+0AhmE4ScI0rXuaXXYOvTO9vdTzXeBROG6tX03t9rrQfB6wPcGVeXRo/uusslAW # sDH8NLz7uHFOooV02Fs8CKDdVrNNw5qjziclSGa0Po7vqOV1TKI8OTiNpsDLmdI5 # +DQvC6N+IU1pSOXImATSHkheGWggsegrsgN6PdrlzHEXJwWoAaRD0T06MRn74/pL # gCegK2ez4RJYsci7C5b0gaqY/QBsMj8EUfEGVHvVyuVSoPRwiq4ehPqSQ+siA3xP # KxYR0e4+QIfRmxqCzaJhiQ3DDGdt8UcO3yF0XcKXEqWwgFAGQKNeUG314jginvmA # iaJzC0dHbiGcagAk7Ey8iyzfxQDWM6ixzJtGv7VLILepzCuu8vaJXy5qeEtTM/ZI # EXoDGceNSvw= # =ikBW # -----END PGP SIGNATURE----- # gpg: Signature made Thu 09 Nov 2023 00:56:39 HKT # gpg: using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6 # gpg: issuer "kwolf@redhat.com" # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full] # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * tag 'for-upstream' of https://repo.or.cz/qemu/kevin: (25 commits) hw/ide/ahci: trigger either error IRQ or regular IRQ, not both block: Protect bs->file with graph_lock block: Take graph lock for most of .bdrv_open vhdx: Take locks for accessing bs->file qcow2: Take locks for accessing bs->file block: Add missing GRAPH_RDLOCK annotations block: Introduce bdrv_co_change_backing_file() blkverify: Add locking for request_fn block: Protect bs->backing with graph_lock block: Mark bdrv_replace_node() GRAPH_WRLOCK block: Mark bdrv_replace_node_common() GRAPH_WRLOCK block: Inline bdrv_set_backing_noperm() block: Mark bdrv_set_backing_hd_drained() GRAPH_WRLOCK block: Mark bdrv_cow_child() and callers GRAPH_RDLOCK block: Mark bdrv_filter_child() and callers GRAPH_RDLOCK block: Mark bdrv_chain_contains() and callers GRAPH_RDLOCK block: Mark bdrv_(un)freeze_backing_chain() and callers GRAPH_RDLOCK block: Mark bdrv_skip_filters() and callers GRAPH_RDLOCK block: Mark bdrv_skip_implicit_filters() and callers GRAPH_RDLOCK block: Mark bdrv_filter_or_cow_bs() and callers GRAPH_RDLOCK ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
		
						commit
						ad6ef0a42e
					
				
							
								
								
									
										192
									
								
								block.c
									
									
									
									
									
								
							
							
						
						
									
										192
									
								
								block.c
									
									
									
									
									
								
							@ -820,12 +820,17 @@ int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
 | 
				
			|||||||
int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
 | 
					int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriver *drv = bs->drv;
 | 
					    BlockDriver *drv = bs->drv;
 | 
				
			||||||
    BlockDriverState *filtered = bdrv_filter_bs(bs);
 | 
					    BlockDriverState *filtered;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (drv && drv->bdrv_probe_geometry) {
 | 
					    if (drv && drv->bdrv_probe_geometry) {
 | 
				
			||||||
        return drv->bdrv_probe_geometry(bs, geo);
 | 
					        return drv->bdrv_probe_geometry(bs, geo);
 | 
				
			||||||
    } else if (filtered) {
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    filtered = bdrv_filter_bs(bs);
 | 
				
			||||||
 | 
					    if (filtered) {
 | 
				
			||||||
        return bdrv_probe_geometry(filtered, geo);
 | 
					        return bdrv_probe_geometry(filtered, geo);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1702,12 +1707,14 @@ bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name,
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
open_failed:
 | 
					open_failed:
 | 
				
			||||||
    bs->drv = NULL;
 | 
					    bs->drv = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(NULL);
 | 
				
			||||||
    if (bs->file != NULL) {
 | 
					    if (bs->file != NULL) {
 | 
				
			||||||
        bdrv_graph_wrlock(NULL);
 | 
					 | 
				
			||||||
        bdrv_unref_child(bs, bs->file);
 | 
					        bdrv_unref_child(bs, bs->file);
 | 
				
			||||||
        bdrv_graph_wrunlock();
 | 
					 | 
				
			||||||
        assert(!bs->file);
 | 
					        assert(!bs->file);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_free(bs->opaque);
 | 
					    g_free(bs->opaque);
 | 
				
			||||||
    bs->opaque = NULL;
 | 
					    bs->opaque = NULL;
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
@ -1849,9 +1856,12 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
 | 
				
			|||||||
    Error *local_err = NULL;
 | 
					    Error *local_err = NULL;
 | 
				
			||||||
    bool ro;
 | 
					    bool ro;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    assert(bs->file == NULL);
 | 
					    assert(bs->file == NULL);
 | 
				
			||||||
    assert(options != NULL && bs->options != options);
 | 
					    assert(options != NULL && bs->options != options);
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
 | 
					    opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
 | 
				
			||||||
    if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 | 
					    if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 | 
				
			||||||
@ -3209,8 +3219,6 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_graph_wrlock(child_bs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    child = bdrv_attach_child_common(child_bs, child_name, child_class,
 | 
					    child = bdrv_attach_child_common(child_bs, child_name, child_class,
 | 
				
			||||||
                                   child_role, perm, shared_perm, opaque,
 | 
					                                   child_role, perm, shared_perm, opaque,
 | 
				
			||||||
                                   tran, errp);
 | 
					                                   tran, errp);
 | 
				
			||||||
@ -3223,9 +3231,8 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
    tran_finalize(tran, ret);
 | 
					    tran_finalize(tran, ret);
 | 
				
			||||||
    bdrv_graph_wrunlock();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_unref(child_bs);
 | 
					    bdrv_schedule_unref(child_bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ret < 0 ? NULL : child;
 | 
					    return ret < 0 ? NULL : child;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -3530,19 +3537,7 @@ out:
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * If a backing child is already present (i.e. we're detaching a node), that
 | 
					 * If a backing child is already present (i.e. we're detaching a node), that
 | 
				
			||||||
 * child node must be drained.
 | 
					 * child node must be drained.
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * After calling this function, the transaction @tran may only be completed
 | 
					 | 
				
			||||||
 * while holding a writer lock for the graph.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int GRAPH_WRLOCK
 | 
					 | 
				
			||||||
bdrv_set_backing_noperm(BlockDriverState *bs,
 | 
					 | 
				
			||||||
                        BlockDriverState *backing_hd,
 | 
					 | 
				
			||||||
                        Transaction *tran, Error **errp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					 | 
				
			||||||
    return bdrv_set_file_or_backing_noperm(bs, backing_hd, true, tran, errp);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int bdrv_set_backing_hd_drained(BlockDriverState *bs,
 | 
					int bdrv_set_backing_hd_drained(BlockDriverState *bs,
 | 
				
			||||||
                                BlockDriverState *backing_hd,
 | 
					                                BlockDriverState *backing_hd,
 | 
				
			||||||
                                Error **errp)
 | 
					                                Error **errp)
 | 
				
			||||||
@ -3555,9 +3550,8 @@ int bdrv_set_backing_hd_drained(BlockDriverState *bs,
 | 
				
			|||||||
    if (bs->backing) {
 | 
					    if (bs->backing) {
 | 
				
			||||||
        assert(bs->backing->bs->quiesce_counter > 0);
 | 
					        assert(bs->backing->bs->quiesce_counter > 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    bdrv_graph_wrlock(backing_hd);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_set_backing_noperm(bs, backing_hd, tran, errp);
 | 
					    ret = bdrv_set_file_or_backing_noperm(bs, backing_hd, true, tran, errp);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -3565,20 +3559,25 @@ int bdrv_set_backing_hd_drained(BlockDriverState *bs,
 | 
				
			|||||||
    ret = bdrv_refresh_perms(bs, tran, errp);
 | 
					    ret = bdrv_refresh_perms(bs, tran, errp);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
    tran_finalize(tran, ret);
 | 
					    tran_finalize(tran, ret);
 | 
				
			||||||
    bdrv_graph_wrunlock();
 | 
					 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
 | 
					int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
 | 
				
			||||||
                        Error **errp)
 | 
					                        Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriverState *drain_bs = bs->backing ? bs->backing->bs : bs;
 | 
					    BlockDriverState *drain_bs;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					    drain_bs = bs->backing ? bs->backing->bs : bs;
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_ref(drain_bs);
 | 
					    bdrv_ref(drain_bs);
 | 
				
			||||||
    bdrv_drained_begin(drain_bs);
 | 
					    bdrv_drained_begin(drain_bs);
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(backing_hd);
 | 
				
			||||||
    ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
 | 
					    ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
    bdrv_drained_end(drain_bs);
 | 
					    bdrv_drained_end(drain_bs);
 | 
				
			||||||
    bdrv_unref(drain_bs);
 | 
					    bdrv_unref(drain_bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3612,6 +3611,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
 | 
				
			|||||||
    Error *local_err = NULL;
 | 
					    Error *local_err = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bs->backing != NULL) {
 | 
					    if (bs->backing != NULL) {
 | 
				
			||||||
        goto free_exit;
 | 
					        goto free_exit;
 | 
				
			||||||
@ -3653,10 +3653,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
 | 
				
			|||||||
            implicit_backing = !strcmp(bs->auto_backing_file, bs->backing_file);
 | 
					            implicit_backing = !strcmp(bs->auto_backing_file, bs->backing_file);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
        backing_filename = bdrv_get_full_backing_filename(bs, &local_err);
 | 
					        backing_filename = bdrv_get_full_backing_filename(bs, &local_err);
 | 
				
			||||||
        bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (local_err) {
 | 
					        if (local_err) {
 | 
				
			||||||
            ret = -EINVAL;
 | 
					            ret = -EINVAL;
 | 
				
			||||||
            error_propagate(errp, local_err);
 | 
					            error_propagate(errp, local_err);
 | 
				
			||||||
@ -3687,9 +3684,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (implicit_backing) {
 | 
					    if (implicit_backing) {
 | 
				
			||||||
        bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
        bdrv_refresh_filename(backing_hd);
 | 
					        bdrv_refresh_filename(backing_hd);
 | 
				
			||||||
        bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
        pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file),
 | 
					        pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file),
 | 
				
			||||||
                backing_hd->filename);
 | 
					                backing_hd->filename);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -4760,8 +4755,8 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriverState *bs = reopen_state->bs;
 | 
					    BlockDriverState *bs = reopen_state->bs;
 | 
				
			||||||
    BlockDriverState *new_child_bs;
 | 
					    BlockDriverState *new_child_bs;
 | 
				
			||||||
    BlockDriverState *old_child_bs = is_backing ? child_bs(bs->backing) :
 | 
					    BlockDriverState *old_child_bs;
 | 
				
			||||||
                                                  child_bs(bs->file);
 | 
					
 | 
				
			||||||
    const char *child_name = is_backing ? "backing" : "file";
 | 
					    const char *child_name = is_backing ? "backing" : "file";
 | 
				
			||||||
    QObject *value;
 | 
					    QObject *value;
 | 
				
			||||||
    const char *str;
 | 
					    const char *str;
 | 
				
			||||||
@ -4776,6 +4771,8 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
 | 
				
			|||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (qobject_type(value)) {
 | 
					    switch (qobject_type(value)) {
 | 
				
			||||||
    case QTYPE_QNULL:
 | 
					    case QTYPE_QNULL:
 | 
				
			||||||
        assert(is_backing); /* The 'file' option does not allow a null value */
 | 
					        assert(is_backing); /* The 'file' option does not allow a null value */
 | 
				
			||||||
@ -4785,17 +4782,16 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
 | 
				
			|||||||
        str = qstring_get_str(qobject_to(QString, value));
 | 
					        str = qstring_get_str(qobject_to(QString, value));
 | 
				
			||||||
        new_child_bs = bdrv_lookup_bs(NULL, str, errp);
 | 
					        new_child_bs = bdrv_lookup_bs(NULL, str, errp);
 | 
				
			||||||
        if (new_child_bs == NULL) {
 | 
					        if (new_child_bs == NULL) {
 | 
				
			||||||
            return -EINVAL;
 | 
					            ret = -EINVAL;
 | 
				
			||||||
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
        has_child = bdrv_recurse_has_child(new_child_bs, bs);
 | 
					        has_child = bdrv_recurse_has_child(new_child_bs, bs);
 | 
				
			||||||
        bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (has_child) {
 | 
					        if (has_child) {
 | 
				
			||||||
            error_setg(errp, "Making '%s' a %s child of '%s' would create a "
 | 
					            error_setg(errp, "Making '%s' a %s child of '%s' would create a "
 | 
				
			||||||
                       "cycle", str, child_name, bs->node_name);
 | 
					                       "cycle", str, child_name, bs->node_name);
 | 
				
			||||||
            return -EINVAL;
 | 
					            ret = -EINVAL;
 | 
				
			||||||
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
@ -4806,19 +4802,23 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
 | 
				
			|||||||
        g_assert_not_reached();
 | 
					        g_assert_not_reached();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    old_child_bs = is_backing ? child_bs(bs->backing) : child_bs(bs->file);
 | 
				
			||||||
    if (old_child_bs == new_child_bs) {
 | 
					    if (old_child_bs == new_child_bs) {
 | 
				
			||||||
        return 0;
 | 
					        ret = 0;
 | 
				
			||||||
 | 
					        goto out_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (old_child_bs) {
 | 
					    if (old_child_bs) {
 | 
				
			||||||
        if (bdrv_skip_implicit_filters(old_child_bs) == new_child_bs) {
 | 
					        if (bdrv_skip_implicit_filters(old_child_bs) == new_child_bs) {
 | 
				
			||||||
            return 0;
 | 
					            ret = 0;
 | 
				
			||||||
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (old_child_bs->implicit) {
 | 
					        if (old_child_bs->implicit) {
 | 
				
			||||||
            error_setg(errp, "Cannot replace implicit %s child of %s",
 | 
					            error_setg(errp, "Cannot replace implicit %s child of %s",
 | 
				
			||||||
                       child_name, bs->node_name);
 | 
					                       child_name, bs->node_name);
 | 
				
			||||||
            return -EPERM;
 | 
					            ret = -EPERM;
 | 
				
			||||||
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -4829,7 +4829,8 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
 | 
				
			|||||||
         */
 | 
					         */
 | 
				
			||||||
        error_setg(errp, "'%s' is a %s filter node that does not support a "
 | 
					        error_setg(errp, "'%s' is a %s filter node that does not support a "
 | 
				
			||||||
                   "%s child", bs->node_name, bs->drv->format_name, child_name);
 | 
					                   "%s child", bs->node_name, bs->drv->format_name, child_name);
 | 
				
			||||||
        return -EINVAL;
 | 
					        ret = -EINVAL;
 | 
				
			||||||
 | 
					        goto out_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (is_backing) {
 | 
					    if (is_backing) {
 | 
				
			||||||
@ -4850,6 +4851,7 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
 | 
				
			|||||||
        aio_context_acquire(ctx);
 | 
					        aio_context_acquire(ctx);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
    bdrv_graph_wrlock(new_child_bs);
 | 
					    bdrv_graph_wrlock(new_child_bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
 | 
					    ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
 | 
				
			||||||
@ -4868,6 +4870,10 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_rdlock:
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@ -5008,13 +5014,16 @@ bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
 | 
				
			|||||||
     * file or if the image file has a backing file name as part of
 | 
					     * file or if the image file has a backing file name as part of
 | 
				
			||||||
     * its metadata. Otherwise the 'backing' option can be omitted.
 | 
					     * its metadata. Otherwise the 'backing' option can be omitted.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    if (drv->supports_backing && reopen_state->backing_missing &&
 | 
					    if (drv->supports_backing && reopen_state->backing_missing &&
 | 
				
			||||||
        (reopen_state->bs->backing || reopen_state->bs->backing_file[0])) {
 | 
					        (reopen_state->bs->backing || reopen_state->bs->backing_file[0])) {
 | 
				
			||||||
        error_setg(errp, "backing is missing for '%s'",
 | 
					        error_setg(errp, "backing is missing for '%s'",
 | 
				
			||||||
                   reopen_state->bs->node_name);
 | 
					                   reopen_state->bs->node_name);
 | 
				
			||||||
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
        ret = -EINVAL;
 | 
					        ret = -EINVAL;
 | 
				
			||||||
        goto error;
 | 
					        goto error;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Allow changing the 'backing' option. The new value can be
 | 
					     * Allow changing the 'backing' option. The new value can be
 | 
				
			||||||
@ -5204,10 +5213,11 @@ static void bdrv_close(BlockDriverState *bs)
 | 
				
			|||||||
    QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
 | 
					    QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
 | 
				
			||||||
        bdrv_unref_child(bs, child);
 | 
					        bdrv_unref_child(bs, child);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    bdrv_graph_wrunlock();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert(!bs->backing);
 | 
					    assert(!bs->backing);
 | 
				
			||||||
    assert(!bs->file);
 | 
					    assert(!bs->file);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_free(bs->opaque);
 | 
					    g_free(bs->opaque);
 | 
				
			||||||
    bs->opaque = NULL;
 | 
					    bs->opaque = NULL;
 | 
				
			||||||
    qatomic_set(&bs->copy_on_read, 0);
 | 
					    qatomic_set(&bs->copy_on_read, 0);
 | 
				
			||||||
@ -5412,6 +5422,9 @@ bdrv_replace_node_noperm(BlockDriverState *from,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 | 
					 * Switch all parents of @from to point to @to instead. @from and @to must be in
 | 
				
			||||||
 | 
					 * the same AioContext and both must be drained.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * With auto_skip=true bdrv_replace_node_common skips updating from parents
 | 
					 * With auto_skip=true bdrv_replace_node_common skips updating from parents
 | 
				
			||||||
 * if it creates a parent-child relation loop or if parent is block-job.
 | 
					 * if it creates a parent-child relation loop or if parent is block-job.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@ -5421,10 +5434,9 @@ bdrv_replace_node_noperm(BlockDriverState *from,
 | 
				
			|||||||
 * With @detach_subchain=true @to must be in a backing chain of @from. In this
 | 
					 * With @detach_subchain=true @to must be in a backing chain of @from. In this
 | 
				
			||||||
 * case backing link of the cow-parent of @to is removed.
 | 
					 * case backing link of the cow-parent of @to is removed.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int bdrv_replace_node_common(BlockDriverState *from,
 | 
					static int GRAPH_WRLOCK
 | 
				
			||||||
                                    BlockDriverState *to,
 | 
					bdrv_replace_node_common(BlockDriverState *from, BlockDriverState *to,
 | 
				
			||||||
                                    bool auto_skip, bool detach_subchain,
 | 
					                         bool auto_skip, bool detach_subchain, Error **errp)
 | 
				
			||||||
                                    Error **errp)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Transaction *tran = tran_new();
 | 
					    Transaction *tran = tran_new();
 | 
				
			||||||
    g_autoptr(GSList) refresh_list = NULL;
 | 
					    g_autoptr(GSList) refresh_list = NULL;
 | 
				
			||||||
@ -5433,6 +5445,10 @@ static int bdrv_replace_node_common(BlockDriverState *from,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(from->quiesce_counter);
 | 
				
			||||||
 | 
					    assert(to->quiesce_counter);
 | 
				
			||||||
 | 
					    assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (detach_subchain) {
 | 
					    if (detach_subchain) {
 | 
				
			||||||
        assert(bdrv_chain_contains(from, to));
 | 
					        assert(bdrv_chain_contains(from, to));
 | 
				
			||||||
        assert(from != to);
 | 
					        assert(from != to);
 | 
				
			||||||
@ -5444,17 +5460,6 @@ static int bdrv_replace_node_common(BlockDriverState *from,
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Make sure that @from doesn't go away until we have successfully attached
 | 
					 | 
				
			||||||
     * all of its parents to @to. */
 | 
					 | 
				
			||||||
    bdrv_ref(from);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert(qemu_get_current_aio_context() == qemu_get_aio_context());
 | 
					 | 
				
			||||||
    assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
 | 
					 | 
				
			||||||
    bdrv_drained_begin(from);
 | 
					 | 
				
			||||||
    bdrv_drained_begin(to);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bdrv_graph_wrlock(to);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Do the replacement without permission update.
 | 
					     * Do the replacement without permission update.
 | 
				
			||||||
     * Replacement may influence the permissions, we should calculate new
 | 
					     * Replacement may influence the permissions, we should calculate new
 | 
				
			||||||
@ -5483,29 +5488,33 @@ static int bdrv_replace_node_common(BlockDriverState *from,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
    tran_finalize(tran, ret);
 | 
					    tran_finalize(tran, ret);
 | 
				
			||||||
    bdrv_graph_wrunlock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bdrv_drained_end(to);
 | 
					 | 
				
			||||||
    bdrv_drained_end(from);
 | 
					 | 
				
			||||||
    bdrv_unref(from);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
 | 
					int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
 | 
				
			||||||
                      Error **errp)
 | 
					                      Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return bdrv_replace_node_common(from, to, true, false, errp);
 | 
					    return bdrv_replace_node_common(from, to, true, false, errp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bdrv_drop_filter(BlockDriverState *bs, Error **errp)
 | 
					int bdrv_drop_filter(BlockDriverState *bs, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    BlockDriverState *child_bs;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return bdrv_replace_node_common(bs, bdrv_filter_or_cow_bs(bs), true, true,
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
                                    errp);
 | 
					    child_bs = bdrv_filter_or_cow_bs(bs);
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_drained_begin(child_bs);
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(bs);
 | 
				
			||||||
 | 
					    ret = bdrv_replace_node_common(bs, child_bs, true, true, errp);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					    bdrv_drained_end(child_bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@ -5532,7 +5541,9 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    assert(!bs_new->backing);
 | 
					    assert(!bs_new->backing);
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    old_context = bdrv_get_aio_context(bs_top);
 | 
					    old_context = bdrv_get_aio_context(bs_top);
 | 
				
			||||||
    bdrv_drained_begin(bs_top);
 | 
					    bdrv_drained_begin(bs_top);
 | 
				
			||||||
@ -5700,9 +5711,19 @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options,
 | 
				
			|||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Make sure that @bs doesn't go away until we have successfully attached
 | 
				
			||||||
 | 
					     * all of its parents to @new_node_bs and undrained it again.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    bdrv_ref(bs);
 | 
				
			||||||
    bdrv_drained_begin(bs);
 | 
					    bdrv_drained_begin(bs);
 | 
				
			||||||
 | 
					    bdrv_drained_begin(new_node_bs);
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(new_node_bs);
 | 
				
			||||||
    ret = bdrv_replace_node(bs, new_node_bs, errp);
 | 
					    ret = bdrv_replace_node(bs, new_node_bs, errp);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					    bdrv_drained_end(new_node_bs);
 | 
				
			||||||
    bdrv_drained_end(bs);
 | 
					    bdrv_drained_end(bs);
 | 
				
			||||||
 | 
					    bdrv_unref(bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        error_prepend(errp, "Could not replace node: ");
 | 
					        error_prepend(errp, "Could not replace node: ");
 | 
				
			||||||
@ -5748,13 +5769,14 @@ int coroutine_fn bdrv_co_check(BlockDriverState *bs,
 | 
				
			|||||||
 *            image file header
 | 
					 *            image file header
 | 
				
			||||||
 * -ENOTSUP - format driver doesn't support changing the backing file
 | 
					 * -ENOTSUP - format driver doesn't support changing the backing file
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
 | 
					int coroutine_fn
 | 
				
			||||||
                             const char *backing_fmt, bool require)
 | 
					bdrv_co_change_backing_file(BlockDriverState *bs, const char *backing_file,
 | 
				
			||||||
 | 
					                            const char *backing_fmt, bool require)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriver *drv = bs->drv;
 | 
					    BlockDriver *drv = bs->drv;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    IO_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!drv) {
 | 
					    if (!drv) {
 | 
				
			||||||
        return -ENOMEDIUM;
 | 
					        return -ENOMEDIUM;
 | 
				
			||||||
@ -5769,8 +5791,8 @@ int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
 | 
				
			|||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (drv->bdrv_change_backing_file != NULL) {
 | 
					    if (drv->bdrv_co_change_backing_file != NULL) {
 | 
				
			||||||
        ret = drv->bdrv_change_backing_file(bs, backing_file, backing_fmt);
 | 
					        ret = drv->bdrv_co_change_backing_file(bs, backing_file, backing_fmt);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        ret = -ENOTSUP;
 | 
					        ret = -ENOTSUP;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -5827,8 +5849,9 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs)
 | 
				
			|||||||
 * between @bs and @base is frozen. @errp is set if that's the case.
 | 
					 * between @bs and @base is frozen. @errp is set if that's the case.
 | 
				
			||||||
 * @base must be reachable from @bs, or NULL.
 | 
					 * @base must be reachable from @bs, or NULL.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
 | 
					static bool GRAPH_RDLOCK
 | 
				
			||||||
                                  Error **errp)
 | 
					bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
 | 
				
			||||||
 | 
					                             Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriverState *i;
 | 
					    BlockDriverState *i;
 | 
				
			||||||
    BdrvChild *child;
 | 
					    BdrvChild *child;
 | 
				
			||||||
@ -5952,15 +5975,15 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    bdrv_ref(top);
 | 
					    bdrv_ref(top);
 | 
				
			||||||
    bdrv_drained_begin(base);
 | 
					    bdrv_drained_begin(base);
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					    bdrv_graph_wrlock(base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!top->drv || !base->drv) {
 | 
					    if (!top->drv || !base->drv) {
 | 
				
			||||||
        goto exit;
 | 
					        goto exit_wrlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Make sure that base is in the backing chain of top */
 | 
					    /* Make sure that base is in the backing chain of top */
 | 
				
			||||||
    if (!bdrv_chain_contains(top, base)) {
 | 
					    if (!bdrv_chain_contains(top, base)) {
 | 
				
			||||||
        goto exit;
 | 
					        goto exit_wrlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* If 'base' recursively inherits from 'top' then we should set
 | 
					    /* If 'base' recursively inherits from 'top' then we should set
 | 
				
			||||||
@ -5992,6 +6015,8 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
 | 
				
			|||||||
     * That's a FIXME.
 | 
					     * That's a FIXME.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    bdrv_replace_node_common(top, base, false, false, &local_err);
 | 
					    bdrv_replace_node_common(top, base, false, false, &local_err);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (local_err) {
 | 
					    if (local_err) {
 | 
				
			||||||
        error_report_err(local_err);
 | 
					        error_report_err(local_err);
 | 
				
			||||||
        goto exit;
 | 
					        goto exit;
 | 
				
			||||||
@ -6024,8 +6049,11 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = 0;
 | 
					    ret = 0;
 | 
				
			||||||
 | 
					    goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit_wrlock:
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
exit:
 | 
					exit:
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
    bdrv_drained_end(base);
 | 
					    bdrv_drained_end(base);
 | 
				
			||||||
    bdrv_unref(top);
 | 
					    bdrv_unref(top);
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
@ -6587,7 +6615,7 @@ int bdrv_has_zero_init_1(BlockDriverState *bs)
 | 
				
			|||||||
    return 1;
 | 
					    return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bdrv_has_zero_init(BlockDriverState *bs)
 | 
					int coroutine_mixed_fn bdrv_has_zero_init(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriverState *filtered;
 | 
					    BlockDriverState *filtered;
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
@ -8100,7 +8128,7 @@ static bool append_strong_runtime_options(QDict *d, BlockDriverState *bs)
 | 
				
			|||||||
/* Note: This function may return false positives; it may return true
 | 
					/* Note: This function may return false positives; it may return true
 | 
				
			||||||
 * even if opening the backing file specified by bs's image header
 | 
					 * even if opening the backing file specified by bs's image header
 | 
				
			||||||
 * would result in exactly bs->backing. */
 | 
					 * would result in exactly bs->backing. */
 | 
				
			||||||
static bool bdrv_backing_overridden(BlockDriverState *bs)
 | 
					static bool GRAPH_RDLOCK bdrv_backing_overridden(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
    if (bs->backing) {
 | 
					    if (bs->backing) {
 | 
				
			||||||
@ -8474,8 +8502,8 @@ BdrvChild *bdrv_primary_child(BlockDriverState *bs)
 | 
				
			|||||||
    return found;
 | 
					    return found;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BlockDriverState *bdrv_do_skip_filters(BlockDriverState *bs,
 | 
					static BlockDriverState * GRAPH_RDLOCK
 | 
				
			||||||
                                              bool stop_on_explicit_filter)
 | 
					bdrv_do_skip_filters(BlockDriverState *bs, bool stop_on_explicit_filter)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BdrvChild *c;
 | 
					    BdrvChild *c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -374,7 +374,6 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
    assert(bs);
 | 
					    assert(bs);
 | 
				
			||||||
    assert(target);
 | 
					    assert(target);
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* QMP interface protects us from these cases */
 | 
					    /* QMP interface protects us from these cases */
 | 
				
			||||||
    assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL);
 | 
					    assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL);
 | 
				
			||||||
@ -385,31 +384,33 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    if (!bdrv_is_inserted(bs)) {
 | 
					    if (!bdrv_is_inserted(bs)) {
 | 
				
			||||||
        error_setg(errp, "Device is not inserted: %s",
 | 
					        error_setg(errp, "Device is not inserted: %s",
 | 
				
			||||||
                   bdrv_get_device_name(bs));
 | 
					                   bdrv_get_device_name(bs));
 | 
				
			||||||
        return NULL;
 | 
					        goto error_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!bdrv_is_inserted(target)) {
 | 
					    if (!bdrv_is_inserted(target)) {
 | 
				
			||||||
        error_setg(errp, "Device is not inserted: %s",
 | 
					        error_setg(errp, "Device is not inserted: %s",
 | 
				
			||||||
                   bdrv_get_device_name(target));
 | 
					                   bdrv_get_device_name(target));
 | 
				
			||||||
        return NULL;
 | 
					        goto error_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (compress && !bdrv_supports_compressed_writes(target)) {
 | 
					    if (compress && !bdrv_supports_compressed_writes(target)) {
 | 
				
			||||||
        error_setg(errp, "Compression is not supported for this drive %s",
 | 
					        error_setg(errp, "Compression is not supported for this drive %s",
 | 
				
			||||||
                   bdrv_get_device_name(target));
 | 
					                   bdrv_get_device_name(target));
 | 
				
			||||||
        return NULL;
 | 
					        goto error_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
 | 
					    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
 | 
				
			||||||
        return NULL;
 | 
					        goto error_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) {
 | 
					    if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) {
 | 
				
			||||||
        return NULL;
 | 
					        goto error_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (perf->max_workers < 1 || perf->max_workers > INT_MAX) {
 | 
					    if (perf->max_workers < 1 || perf->max_workers > INT_MAX) {
 | 
				
			||||||
        error_setg(errp, "max-workers must be between 1 and %d", INT_MAX);
 | 
					        error_setg(errp, "max-workers must be between 1 and %d", INT_MAX);
 | 
				
			||||||
@ -437,6 +438,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    len = bdrv_getlength(bs);
 | 
					    len = bdrv_getlength(bs);
 | 
				
			||||||
    if (len < 0) {
 | 
					    if (len < 0) {
 | 
				
			||||||
 | 
					        GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
        error_setg_errno(errp, -len, "Unable to get length for '%s'",
 | 
					        error_setg_errno(errp, -len, "Unable to get length for '%s'",
 | 
				
			||||||
                         bdrv_get_device_or_node_name(bs));
 | 
					                         bdrv_get_device_or_node_name(bs));
 | 
				
			||||||
        goto error;
 | 
					        goto error;
 | 
				
			||||||
@ -444,6 +446,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    target_len = bdrv_getlength(target);
 | 
					    target_len = bdrv_getlength(target);
 | 
				
			||||||
    if (target_len < 0) {
 | 
					    if (target_len < 0) {
 | 
				
			||||||
 | 
					        GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
        error_setg_errno(errp, -target_len, "Unable to get length for '%s'",
 | 
					        error_setg_errno(errp, -target_len, "Unable to get length for '%s'",
 | 
				
			||||||
                         bdrv_get_device_or_node_name(bs));
 | 
					                         bdrv_get_device_or_node_name(bs));
 | 
				
			||||||
        goto error;
 | 
					        goto error;
 | 
				
			||||||
@ -493,8 +496,10 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
    block_copy_set_speed(bcs, speed);
 | 
					    block_copy_set_speed(bcs, speed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Required permissions are taken by copy-before-write filter target */
 | 
					    /* Required permissions are taken by copy-before-write filter target */
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(target);
 | 
				
			||||||
    block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
 | 
					    block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
 | 
				
			||||||
                       &error_abort);
 | 
					                       &error_abort);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return &job->common;
 | 
					    return &job->common;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -507,4 +512,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error_rdlock:
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -508,6 +508,8 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
 | 
					    bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
 | 
				
			||||||
        (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
 | 
					        (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
 | 
				
			||||||
    bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
 | 
					    bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
 | 
				
			||||||
@ -520,7 +522,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    if (s->align && (s->align >= INT_MAX || !is_power_of_2(s->align))) {
 | 
					    if (s->align && (s->align >= INT_MAX || !is_power_of_2(s->align))) {
 | 
				
			||||||
        error_setg(errp, "Cannot meet constraints with align %" PRIu64,
 | 
					        error_setg(errp, "Cannot meet constraints with align %" PRIu64,
 | 
				
			||||||
                   s->align);
 | 
					                   s->align);
 | 
				
			||||||
        goto out;
 | 
					        goto out_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    align = MAX(s->align, bs->file->bs->bl.request_alignment);
 | 
					    align = MAX(s->align, bs->file->bs->bl.request_alignment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -530,7 +532,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
         !QEMU_IS_ALIGNED(s->max_transfer, align))) {
 | 
					         !QEMU_IS_ALIGNED(s->max_transfer, align))) {
 | 
				
			||||||
        error_setg(errp, "Cannot meet constraints with max-transfer %" PRIu64,
 | 
					        error_setg(errp, "Cannot meet constraints with max-transfer %" PRIu64,
 | 
				
			||||||
                   s->max_transfer);
 | 
					                   s->max_transfer);
 | 
				
			||||||
        goto out;
 | 
					        goto out_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->opt_write_zero = qemu_opt_get_size(opts, "opt-write-zero", 0);
 | 
					    s->opt_write_zero = qemu_opt_get_size(opts, "opt-write-zero", 0);
 | 
				
			||||||
@ -539,7 +541,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
         !QEMU_IS_ALIGNED(s->opt_write_zero, align))) {
 | 
					         !QEMU_IS_ALIGNED(s->opt_write_zero, align))) {
 | 
				
			||||||
        error_setg(errp, "Cannot meet constraints with opt-write-zero %" PRIu64,
 | 
					        error_setg(errp, "Cannot meet constraints with opt-write-zero %" PRIu64,
 | 
				
			||||||
                   s->opt_write_zero);
 | 
					                   s->opt_write_zero);
 | 
				
			||||||
        goto out;
 | 
					        goto out_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->max_write_zero = qemu_opt_get_size(opts, "max-write-zero", 0);
 | 
					    s->max_write_zero = qemu_opt_get_size(opts, "max-write-zero", 0);
 | 
				
			||||||
@ -549,7 +551,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
                          MAX(s->opt_write_zero, align)))) {
 | 
					                          MAX(s->opt_write_zero, align)))) {
 | 
				
			||||||
        error_setg(errp, "Cannot meet constraints with max-write-zero %" PRIu64,
 | 
					        error_setg(errp, "Cannot meet constraints with max-write-zero %" PRIu64,
 | 
				
			||||||
                   s->max_write_zero);
 | 
					                   s->max_write_zero);
 | 
				
			||||||
        goto out;
 | 
					        goto out_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->opt_discard = qemu_opt_get_size(opts, "opt-discard", 0);
 | 
					    s->opt_discard = qemu_opt_get_size(opts, "opt-discard", 0);
 | 
				
			||||||
@ -558,7 +560,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
         !QEMU_IS_ALIGNED(s->opt_discard, align))) {
 | 
					         !QEMU_IS_ALIGNED(s->opt_discard, align))) {
 | 
				
			||||||
        error_setg(errp, "Cannot meet constraints with opt-discard %" PRIu64,
 | 
					        error_setg(errp, "Cannot meet constraints with opt-discard %" PRIu64,
 | 
				
			||||||
                   s->opt_discard);
 | 
					                   s->opt_discard);
 | 
				
			||||||
        goto out;
 | 
					        goto out_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->max_discard = qemu_opt_get_size(opts, "max-discard", 0);
 | 
					    s->max_discard = qemu_opt_get_size(opts, "max-discard", 0);
 | 
				
			||||||
@ -568,12 +570,14 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
                          MAX(s->opt_discard, align)))) {
 | 
					                          MAX(s->opt_discard, align)))) {
 | 
				
			||||||
        error_setg(errp, "Cannot meet constraints with max-discard %" PRIu64,
 | 
					        error_setg(errp, "Cannot meet constraints with max-discard %" PRIu64,
 | 
				
			||||||
                   s->max_discard);
 | 
					                   s->max_discard);
 | 
				
			||||||
        goto out;
 | 
					        goto out_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_debug_event(bs, BLKDBG_NONE);
 | 
					    bdrv_debug_event(bs, BLKDBG_NONE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = 0;
 | 
					    ret = 0;
 | 
				
			||||||
 | 
					out_rdlock:
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        qemu_mutex_destroy(&s->lock);
 | 
					        qemu_mutex_destroy(&s->lock);
 | 
				
			||||||
@ -746,13 +750,10 @@ blkdebug_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
 | 
				
			|||||||
    return bdrv_co_pdiscard(bs->file, offset, bytes);
 | 
					    return bdrv_co_pdiscard(bs->file, offset, bytes);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_fn blkdebug_co_block_status(BlockDriverState *bs,
 | 
					static int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
                                                 bool want_zero,
 | 
					blkdebug_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset,
 | 
				
			||||||
                                                 int64_t offset,
 | 
					                         int64_t bytes, int64_t *pnum, int64_t *map,
 | 
				
			||||||
                                                 int64_t bytes,
 | 
					                         BlockDriverState **file)
 | 
				
			||||||
                                                 int64_t *pnum,
 | 
					 | 
				
			||||||
                                                 int64_t *map,
 | 
					 | 
				
			||||||
                                                 BlockDriverState **file)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int err;
 | 
					    int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -973,7 +974,7 @@ blkdebug_co_getlength(BlockDriverState *bs)
 | 
				
			|||||||
    return bdrv_co_getlength(bs->file->bs);
 | 
					    return bdrv_co_getlength(bs->file->bs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void blkdebug_refresh_filename(BlockDriverState *bs)
 | 
					static void GRAPH_RDLOCK blkdebug_refresh_filename(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVBlkdebugState *s = bs->opaque;
 | 
					    BDRVBlkdebugState *s = bs->opaque;
 | 
				
			||||||
    const QDictEntry *e;
 | 
					    const QDictEntry *e;
 | 
				
			||||||
 | 
				
			|||||||
@ -130,7 +130,13 @@ static int coroutine_fn GRAPH_RDLOCK blkreplay_co_flush(BlockDriverState *bs)
 | 
				
			|||||||
static int blkreplay_snapshot_goto(BlockDriverState *bs,
 | 
					static int blkreplay_snapshot_goto(BlockDriverState *bs,
 | 
				
			||||||
                                   const char *snapshot_id)
 | 
					                                   const char *snapshot_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return bdrv_snapshot_goto(bs->file->bs, snapshot_id, NULL);
 | 
					    BlockDriverState *file_bs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					    file_bs = bs->file->bs;
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return bdrv_snapshot_goto(file_bs, snapshot_id, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BlockDriver bdrv_blkreplay = {
 | 
					static BlockDriver bdrv_blkreplay = {
 | 
				
			||||||
 | 
				
			|||||||
@ -33,8 +33,8 @@ typedef struct BlkverifyRequest {
 | 
				
			|||||||
    uint64_t bytes;
 | 
					    uint64_t bytes;
 | 
				
			||||||
    int flags;
 | 
					    int flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int (*request_fn)(BdrvChild *, int64_t, int64_t, QEMUIOVector *,
 | 
					    int GRAPH_RDLOCK_PTR (*request_fn)(
 | 
				
			||||||
                      BdrvRequestFlags);
 | 
					        BdrvChild *, int64_t, int64_t, QEMUIOVector *, BdrvRequestFlags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int ret;                    /* test image result */
 | 
					    int ret;                    /* test image result */
 | 
				
			||||||
    int raw_ret;                /* raw image result */
 | 
					    int raw_ret;                /* raw image result */
 | 
				
			||||||
@ -170,8 +170,11 @@ static void coroutine_fn blkverify_do_test_req(void *opaque)
 | 
				
			|||||||
    BlkverifyRequest *r = opaque;
 | 
					    BlkverifyRequest *r = opaque;
 | 
				
			||||||
    BDRVBlkverifyState *s = r->bs->opaque;
 | 
					    BDRVBlkverifyState *s = r->bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_co_rdlock();
 | 
				
			||||||
    r->ret = r->request_fn(s->test_file, r->offset, r->bytes, r->qiov,
 | 
					    r->ret = r->request_fn(s->test_file, r->offset, r->bytes, r->qiov,
 | 
				
			||||||
                           r->flags);
 | 
					                           r->flags);
 | 
				
			||||||
 | 
					    bdrv_graph_co_rdunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    r->done++;
 | 
					    r->done++;
 | 
				
			||||||
    qemu_coroutine_enter_if_inactive(r->co);
 | 
					    qemu_coroutine_enter_if_inactive(r->co);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -180,13 +183,16 @@ static void coroutine_fn blkverify_do_raw_req(void *opaque)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    BlkverifyRequest *r = opaque;
 | 
					    BlkverifyRequest *r = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_co_rdlock();
 | 
				
			||||||
    r->raw_ret = r->request_fn(r->bs->file, r->offset, r->bytes, r->raw_qiov,
 | 
					    r->raw_ret = r->request_fn(r->bs->file, r->offset, r->bytes, r->raw_qiov,
 | 
				
			||||||
                               r->flags);
 | 
					                               r->flags);
 | 
				
			||||||
 | 
					    bdrv_graph_co_rdunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    r->done++;
 | 
					    r->done++;
 | 
				
			||||||
    qemu_coroutine_enter_if_inactive(r->co);
 | 
					    qemu_coroutine_enter_if_inactive(r->co);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_fn
 | 
					static int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
blkverify_co_prwv(BlockDriverState *bs, BlkverifyRequest *r, uint64_t offset,
 | 
					blkverify_co_prwv(BlockDriverState *bs, BlkverifyRequest *r, uint64_t offset,
 | 
				
			||||||
                  uint64_t bytes, QEMUIOVector *qiov, QEMUIOVector *raw_qiov,
 | 
					                  uint64_t bytes, QEMUIOVector *qiov, QEMUIOVector *raw_qiov,
 | 
				
			||||||
                  int flags, bool is_write)
 | 
					                  int flags, bool is_write)
 | 
				
			||||||
@ -222,7 +228,7 @@ blkverify_co_prwv(BlockDriverState *bs, BlkverifyRequest *r, uint64_t offset,
 | 
				
			|||||||
    return r->ret;
 | 
					    return r->ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_fn
 | 
					static int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
blkverify_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
 | 
					blkverify_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
 | 
				
			||||||
                    QEMUIOVector *qiov, BdrvRequestFlags flags)
 | 
					                    QEMUIOVector *qiov, BdrvRequestFlags flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -251,7 +257,7 @@ blkverify_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_fn
 | 
					static int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
blkverify_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
 | 
					blkverify_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
 | 
				
			||||||
                     QEMUIOVector *qiov, BdrvRequestFlags flags)
 | 
					                     QEMUIOVector *qiov, BdrvRequestFlags flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -282,7 +288,7 @@ blkverify_recurse_can_replace(BlockDriverState *bs,
 | 
				
			|||||||
           bdrv_recurse_can_replace(s->test_file->bs, to_replace);
 | 
					           bdrv_recurse_can_replace(s->test_file->bs, to_replace);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void blkverify_refresh_filename(BlockDriverState *bs)
 | 
					static void GRAPH_RDLOCK blkverify_refresh_filename(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVBlkverifyState *s = bs->opaque;
 | 
					    BDRVBlkverifyState *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -931,10 +931,12 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
 | 
				
			|||||||
    ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
 | 
					    ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
    bdrv_ref(bs);
 | 
					    bdrv_ref(bs);
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(bs);
 | 
				
			||||||
    blk->root = bdrv_root_attach_child(bs, "root", &child_root,
 | 
					    blk->root = bdrv_root_attach_child(bs, "root", &child_root,
 | 
				
			||||||
                                       BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
 | 
					                                       BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
 | 
				
			||||||
                                       blk->perm, blk->shared_perm,
 | 
					                                       blk->perm, blk->shared_perm,
 | 
				
			||||||
                                       blk, errp);
 | 
					                                       blk, errp);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
    if (blk->root == NULL) {
 | 
					    if (blk->root == NULL) {
 | 
				
			||||||
        return -EPERM;
 | 
					        return -EPERM;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -2666,6 +2668,8 @@ int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size)
 | 
				
			|||||||
int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz)
 | 
					int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!blk_is_available(blk)) {
 | 
					    if (!blk_is_available(blk)) {
 | 
				
			||||||
        return -ENOMEDIUM;
 | 
					        return -ENOMEDIUM;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -2726,6 +2730,7 @@ int blk_commit_all(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    BlockBackend *blk = NULL;
 | 
					    BlockBackend *blk = NULL;
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while ((blk = blk_all_next(blk)) != NULL) {
 | 
					    while ((blk = blk_all_next(blk)) != NULL) {
 | 
				
			||||||
        AioContext *aio_context = blk_get_aio_context(blk);
 | 
					        AioContext *aio_context = blk_get_aio_context(blk);
 | 
				
			||||||
 | 
				
			|||||||
@ -313,7 +313,12 @@ static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
    BlockDriverInfo bdi;
 | 
					    BlockDriverInfo bdi;
 | 
				
			||||||
    bool target_does_cow = bdrv_backing_chain_next(target);
 | 
					    bool target_does_cow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    target_does_cow = bdrv_backing_chain_next(target);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * If there is no backing file on the target, we cannot rely on COW if our
 | 
					     * If there is no backing file on the target, we cannot rely on COW if our
 | 
				
			||||||
@ -355,6 +360,8 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
 | 
				
			|||||||
    BdrvDirtyBitmap *copy_bitmap;
 | 
					    BdrvDirtyBitmap *copy_bitmap;
 | 
				
			||||||
    bool is_fleecing;
 | 
					    bool is_fleecing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cluster_size = block_copy_calculate_cluster_size(target->bs, errp);
 | 
					    cluster_size = block_copy_calculate_cluster_size(target->bs, errp);
 | 
				
			||||||
    if (cluster_size < 0) {
 | 
					    if (cluster_size < 0) {
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
@ -392,7 +399,9 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
 | 
				
			|||||||
     * For more information see commit f8d59dfb40bb and test
 | 
					     * For more information see commit f8d59dfb40bb and test
 | 
				
			||||||
     * tests/qemu-iotests/222
 | 
					     * tests/qemu-iotests/222
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    is_fleecing = bdrv_chain_contains(target->bs, source->bs);
 | 
					    is_fleecing = bdrv_chain_contains(target->bs, source->bs);
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s = g_new(BlockCopyState, 1);
 | 
					    s = g_new(BlockCopyState, 1);
 | 
				
			||||||
    *s = (BlockCopyState) {
 | 
					    *s = (BlockCopyState) {
 | 
				
			||||||
 | 
				
			|||||||
@ -105,6 +105,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    struct bochs_header bochs;
 | 
					    struct bochs_header bochs;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* No write support yet */
 | 
					    /* No write support yet */
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    ret = bdrv_apply_auto_read_only(bs, NULL, errp);
 | 
					    ret = bdrv_apply_auto_read_only(bs, NULL, errp);
 | 
				
			||||||
@ -118,6 +120,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_pread(bs->file, 0, sizeof(bochs), &bochs, 0);
 | 
					    ret = bdrv_pread(bs->file, 0, sizeof(bochs), &bochs, 0);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
 | 
				
			|||||||
@ -67,6 +67,8 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    uint32_t offsets_size, max_compressed_block_size = 1, i;
 | 
					    uint32_t offsets_size, max_compressed_block_size = 1, i;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    ret = bdrv_apply_auto_read_only(bs, NULL, errp);
 | 
					    ret = bdrv_apply_auto_read_only(bs, NULL, errp);
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
@ -79,6 +81,8 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* read header */
 | 
					    /* read header */
 | 
				
			||||||
    ret = bdrv_pread(bs->file, 128, 4, &s->block_size, 0);
 | 
					    ret = bdrv_pread(bs->file, 128, 4, &s->block_size, 0);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
				
			|||||||
@ -48,8 +48,10 @@ static int commit_prepare(Job *job)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
 | 
					    CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
 | 
					    bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
 | 
				
			||||||
    s->chain_frozen = false;
 | 
					    s->chain_frozen = false;
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
 | 
					    /* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
 | 
				
			||||||
     * the normal backing chain can be restored. */
 | 
					     * the normal backing chain can be restored. */
 | 
				
			||||||
@ -66,9 +68,12 @@ static void commit_abort(Job *job)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
 | 
					    CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
 | 
				
			||||||
    BlockDriverState *top_bs = blk_bs(s->top);
 | 
					    BlockDriverState *top_bs = blk_bs(s->top);
 | 
				
			||||||
 | 
					    BlockDriverState *commit_top_backing_bs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->chain_frozen) {
 | 
					    if (s->chain_frozen) {
 | 
				
			||||||
 | 
					        bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
        bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
 | 
					        bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
 | 
				
			||||||
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Make sure commit_top_bs and top stay around until bdrv_replace_node() */
 | 
					    /* Make sure commit_top_bs and top stay around until bdrv_replace_node() */
 | 
				
			||||||
@ -90,8 +95,15 @@ static void commit_abort(Job *job)
 | 
				
			|||||||
     * XXX Can (or should) we somehow keep 'consistent read' blocked even
 | 
					     * XXX Can (or should) we somehow keep 'consistent read' blocked even
 | 
				
			||||||
     * after the failed/cancelled commit job is gone? If we already wrote
 | 
					     * after the failed/cancelled commit job is gone? If we already wrote
 | 
				
			||||||
     * something to base, the intermediate images aren't valid any more. */
 | 
					     * something to base, the intermediate images aren't valid any more. */
 | 
				
			||||||
    bdrv_replace_node(s->commit_top_bs, s->commit_top_bs->backing->bs,
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
                      &error_abort);
 | 
					    commit_top_backing_bs = s->commit_top_bs->backing->bs;
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_drained_begin(commit_top_backing_bs);
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(commit_top_backing_bs);
 | 
				
			||||||
 | 
					    bdrv_replace_node(s->commit_top_bs, commit_top_backing_bs, &error_abort);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					    bdrv_drained_end(commit_top_backing_bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_unref(s->commit_top_bs);
 | 
					    bdrv_unref(s->commit_top_bs);
 | 
				
			||||||
    bdrv_unref(top_bs);
 | 
					    bdrv_unref(top_bs);
 | 
				
			||||||
@ -210,7 +222,7 @@ bdrv_commit_top_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
 | 
				
			|||||||
    return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
 | 
					    return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void bdrv_commit_top_refresh_filename(BlockDriverState *bs)
 | 
					static GRAPH_RDLOCK void bdrv_commit_top_refresh_filename(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
 | 
					    pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
 | 
				
			||||||
            bs->backing->bs->filename);
 | 
					            bs->backing->bs->filename);
 | 
				
			||||||
@ -255,10 +267,13 @@ void commit_start(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert(top != bs);
 | 
					    assert(top != bs);
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    if (bdrv_skip_filters(top) == bdrv_skip_filters(base)) {
 | 
					    if (bdrv_skip_filters(top) == bdrv_skip_filters(base)) {
 | 
				
			||||||
        error_setg(errp, "Invalid files for merge: top and base are the same");
 | 
					        error_setg(errp, "Invalid files for merge: top and base are the same");
 | 
				
			||||||
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    base_size = bdrv_getlength(base);
 | 
					    base_size = bdrv_getlength(base);
 | 
				
			||||||
    if (base_size < 0) {
 | 
					    if (base_size < 0) {
 | 
				
			||||||
@ -324,6 +339,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
     * this is the responsibility of the interface (i.e. whoever calls
 | 
					     * this is the responsibility of the interface (i.e. whoever calls
 | 
				
			||||||
     * commit_start()).
 | 
					     * commit_start()).
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(top);
 | 
				
			||||||
    s->base_overlay = bdrv_find_overlay(top, base);
 | 
					    s->base_overlay = bdrv_find_overlay(top, base);
 | 
				
			||||||
    assert(s->base_overlay);
 | 
					    assert(s->base_overlay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -354,16 +370,20 @@ void commit_start(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
        ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
 | 
					        ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
 | 
				
			||||||
                                 iter_shared_perms, errp);
 | 
					                                 iter_shared_perms, errp);
 | 
				
			||||||
        if (ret < 0) {
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            bdrv_graph_wrunlock();
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
 | 
					    if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
 | 
				
			||||||
 | 
					        bdrv_graph_wrunlock();
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    s->chain_frozen = true;
 | 
					    s->chain_frozen = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
 | 
					    ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -396,7 +416,9 @@ void commit_start(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
    if (s->chain_frozen) {
 | 
					    if (s->chain_frozen) {
 | 
				
			||||||
 | 
					        bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
        bdrv_unfreeze_backing_chain(commit_top_bs, base);
 | 
					        bdrv_unfreeze_backing_chain(commit_top_bs, base);
 | 
				
			||||||
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (s->base) {
 | 
					    if (s->base) {
 | 
				
			||||||
        blk_unref(s->base);
 | 
					        blk_unref(s->base);
 | 
				
			||||||
@ -411,7 +433,11 @@ fail:
 | 
				
			|||||||
    /* commit_top_bs has to be replaced after deleting the block job,
 | 
					    /* commit_top_bs has to be replaced after deleting the block job,
 | 
				
			||||||
     * otherwise this would fail because of lack of permissions. */
 | 
					     * otherwise this would fail because of lack of permissions. */
 | 
				
			||||||
    if (commit_top_bs) {
 | 
					    if (commit_top_bs) {
 | 
				
			||||||
 | 
					        bdrv_drained_begin(top);
 | 
				
			||||||
 | 
					        bdrv_graph_wrlock(top);
 | 
				
			||||||
        bdrv_replace_node(commit_top_bs, top, &error_abort);
 | 
					        bdrv_replace_node(commit_top_bs, top, &error_abort);
 | 
				
			||||||
 | 
					        bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					        bdrv_drained_end(top);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -203,7 +203,7 @@ static int coroutine_fn GRAPH_RDLOCK cbw_co_flush(BlockDriverState *bs)
 | 
				
			|||||||
 * It's guaranteed that guest writes will not interact in the region until
 | 
					 * It's guaranteed that guest writes will not interact in the region until
 | 
				
			||||||
 * cbw_snapshot_read_unlock() called.
 | 
					 * cbw_snapshot_read_unlock() called.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static coroutine_fn BlockReq *
 | 
					static BlockReq * coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
cbw_snapshot_read_lock(BlockDriverState *bs, int64_t offset, int64_t bytes,
 | 
					cbw_snapshot_read_lock(BlockDriverState *bs, int64_t offset, int64_t bytes,
 | 
				
			||||||
                       int64_t *pnum, BdrvChild **file)
 | 
					                       int64_t *pnum, BdrvChild **file)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -335,7 +335,7 @@ cbw_co_pdiscard_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes)
 | 
				
			|||||||
    return bdrv_co_pdiscard(s->target, offset, bytes);
 | 
					    return bdrv_co_pdiscard(s->target, offset, bytes);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void cbw_refresh_filename(BlockDriverState *bs)
 | 
					static void GRAPH_RDLOCK cbw_refresh_filename(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
 | 
					    pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
 | 
				
			||||||
            bs->file->bs->filename);
 | 
					            bs->file->bs->filename);
 | 
				
			||||||
@ -433,6 +433,8 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ctx = bdrv_get_aio_context(bs);
 | 
					    ctx = bdrv_get_aio_context(bs);
 | 
				
			||||||
    aio_context_acquire(ctx);
 | 
					    aio_context_acquire(ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -35,8 +35,8 @@ typedef struct BDRVStateCOR {
 | 
				
			|||||||
} BDRVStateCOR;
 | 
					} BDRVStateCOR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int cor_open(BlockDriverState *bs, QDict *options, int flags,
 | 
					static int GRAPH_UNLOCKED
 | 
				
			||||||
                    Error **errp)
 | 
					cor_open(BlockDriverState *bs, QDict *options, int flags, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriverState *bottom_bs = NULL;
 | 
					    BlockDriverState *bottom_bs = NULL;
 | 
				
			||||||
    BDRVStateCOR *state = bs->opaque;
 | 
					    BDRVStateCOR *state = bs->opaque;
 | 
				
			||||||
@ -44,11 +44,15 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    const char *bottom_node = qdict_get_try_str(options, "bottom");
 | 
					    const char *bottom_node = qdict_get_try_str(options, "bottom");
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
 | 
					    ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bs->supported_read_flags = BDRV_REQ_PREFETCH;
 | 
					    bs->supported_read_flags = BDRV_REQ_PREFETCH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
 | 
					    bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
 | 
				
			||||||
@ -227,13 +231,17 @@ cor_co_lock_medium(BlockDriverState *bs, bool locked)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void cor_close(BlockDriverState *bs)
 | 
					static void GRAPH_UNLOCKED cor_close(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVStateCOR *s = bs->opaque;
 | 
					    BDRVStateCOR *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->chain_frozen) {
 | 
					    if (s->chain_frozen) {
 | 
				
			||||||
 | 
					        bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
        s->chain_frozen = false;
 | 
					        s->chain_frozen = false;
 | 
				
			||||||
        bdrv_unfreeze_backing_chain(bs, s->bottom_bs);
 | 
					        bdrv_unfreeze_backing_chain(bs, s->bottom_bs);
 | 
				
			||||||
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_unref(s->bottom_bs);
 | 
					    bdrv_unref(s->bottom_bs);
 | 
				
			||||||
@ -263,12 +271,15 @@ static BlockDriver bdrv_copy_on_read = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs)
 | 
					void no_coroutine_fn bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVStateCOR *s = cor_filter_bs->opaque;
 | 
					    BDRVStateCOR *s = cor_filter_bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* unfreeze, as otherwise bdrv_replace_node() will fail */
 | 
					    /* unfreeze, as otherwise bdrv_replace_node() will fail */
 | 
				
			||||||
    if (s->chain_frozen) {
 | 
					    if (s->chain_frozen) {
 | 
				
			||||||
 | 
					        GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
        s->chain_frozen = false;
 | 
					        s->chain_frozen = false;
 | 
				
			||||||
        bdrv_unfreeze_backing_chain(cor_filter_bs, s->bottom_bs);
 | 
					        bdrv_unfreeze_backing_chain(cor_filter_bs, s->bottom_bs);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -27,6 +27,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "block/block_int.h"
 | 
					#include "block/block_int.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs);
 | 
					void no_coroutine_fn GRAPH_UNLOCKED
 | 
				
			||||||
 | 
					bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* BLOCK_COPY_ON_READ_H */
 | 
					#endif /* BLOCK_COPY_ON_READ_H */
 | 
				
			||||||
 | 
				
			|||||||
@ -65,6 +65,9 @@ static int block_crypto_read_func(QCryptoBlock *block,
 | 
				
			|||||||
    BlockDriverState *bs = opaque;
 | 
					    BlockDriverState *bs = opaque;
 | 
				
			||||||
    ssize_t ret;
 | 
					    ssize_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_pread(bs->file, offset, buflen, buf, 0);
 | 
					    ret = bdrv_pread(bs->file, offset, buflen, buf, 0);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        error_setg_errno(errp, -ret, "Could not read encryption header");
 | 
					        error_setg_errno(errp, -ret, "Could not read encryption header");
 | 
				
			||||||
@ -83,6 +86,9 @@ static int block_crypto_write_func(QCryptoBlock *block,
 | 
				
			|||||||
    BlockDriverState *bs = opaque;
 | 
					    BlockDriverState *bs = opaque;
 | 
				
			||||||
    ssize_t ret;
 | 
					    ssize_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_pwrite(bs->file, offset, buflen, buf, 0);
 | 
					    ret = bdrv_pwrite(bs->file, offset, buflen, buf, 0);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        error_setg_errno(errp, -ret, "Could not write encryption header");
 | 
					        error_setg_errno(errp, -ret, "Could not write encryption header");
 | 
				
			||||||
@ -263,11 +269,15 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
 | 
				
			|||||||
    unsigned int cflags = 0;
 | 
					    unsigned int cflags = 0;
 | 
				
			||||||
    QDict *cryptoopts = NULL;
 | 
					    QDict *cryptoopts = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
 | 
					    ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bs->supported_write_flags = BDRV_REQ_FUA &
 | 
					    bs->supported_write_flags = BDRV_REQ_FUA &
 | 
				
			||||||
        bs->file->bs->supported_write_flags;
 | 
					        bs->file->bs->supported_write_flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										21
									
								
								block/dmg.c
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								block/dmg.c
									
									
									
									
									
								
							@ -70,7 +70,8 @@ static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
 | 
					read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint64_t buffer;
 | 
					    uint64_t buffer;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
@ -84,7 +85,8 @@ static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
 | 
					read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint32_t buffer;
 | 
					    uint32_t buffer;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
@ -321,8 +323,9 @@ fail:
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                                  uint64_t info_begin, uint64_t info_length)
 | 
					dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds,
 | 
				
			||||||
 | 
					                       uint64_t info_begin, uint64_t info_length)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVDMGState *s = bs->opaque;
 | 
					    BDRVDMGState *s = bs->opaque;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
@ -388,8 +391,9 @@ fail:
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int dmg_read_plist_xml(BlockDriverState *bs, DmgHeaderState *ds,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                              uint64_t info_begin, uint64_t info_length)
 | 
					dmg_read_plist_xml(BlockDriverState *bs, DmgHeaderState *ds,
 | 
				
			||||||
 | 
					                   uint64_t info_begin, uint64_t info_length)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVDMGState *s = bs->opaque;
 | 
					    BDRVDMGState *s = bs->opaque;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
@ -452,6 +456,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    int64_t offset;
 | 
					    int64_t offset;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    ret = bdrv_apply_auto_read_only(bs, NULL, errp);
 | 
					    ret = bdrv_apply_auto_read_only(bs, NULL, errp);
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
@ -463,6 +469,9 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * NB: if uncompress submodules are absent,
 | 
					     * NB: if uncompress submodules are absent,
 | 
				
			||||||
     * ie block_module_load return value == 0, the function pointers
 | 
					     * ie block_module_load return value == 0, the function pointers
 | 
				
			||||||
 | 
				
			|||||||
@ -36,6 +36,8 @@ static int compress_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) {
 | 
					    if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) {
 | 
				
			||||||
        error_setg(errp,
 | 
					        error_setg(errp,
 | 
				
			||||||
                   "Compression is not supported for underlying format: %s",
 | 
					                   "Compression is not supported for underlying format: %s",
 | 
				
			||||||
@ -97,7 +99,8 @@ compress_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void compress_refresh_limits(BlockDriverState *bs, Error **errp)
 | 
					static void GRAPH_RDLOCK
 | 
				
			||||||
 | 
					compress_refresh_limits(BlockDriverState *bs, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriverInfo bdi;
 | 
					    BlockDriverInfo bdi;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
				
			|||||||
@ -3685,6 +3685,8 @@ out:
 | 
				
			|||||||
void bdrv_cancel_in_flight(BlockDriverState *bs)
 | 
					void bdrv_cancel_in_flight(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!bs || !bs->drv) {
 | 
					    if (!bs || !bs->drv) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -479,7 +479,7 @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset,
 | 
				
			|||||||
    return bytes_handled;
 | 
					    return bytes_handled;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
 | 
					static void coroutine_fn GRAPH_RDLOCK mirror_iteration(MirrorBlockJob *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriverState *source = s->mirror_top_bs->backing->bs;
 | 
					    BlockDriverState *source = s->mirror_top_bs->backing->bs;
 | 
				
			||||||
    MirrorOp *pseudo_op;
 | 
					    MirrorOp *pseudo_op;
 | 
				
			||||||
@ -678,6 +678,7 @@ static int mirror_exit_common(Job *job)
 | 
				
			|||||||
    s->prepared = true;
 | 
					    s->prepared = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    aio_context_acquire(qemu_get_aio_context());
 | 
					    aio_context_acquire(qemu_get_aio_context());
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mirror_top_bs = s->mirror_top_bs;
 | 
					    mirror_top_bs = s->mirror_top_bs;
 | 
				
			||||||
    bs_opaque = mirror_top_bs->opaque;
 | 
					    bs_opaque = mirror_top_bs->opaque;
 | 
				
			||||||
@ -696,6 +697,8 @@ static int mirror_exit_common(Job *job)
 | 
				
			|||||||
    bdrv_ref(mirror_top_bs);
 | 
					    bdrv_ref(mirror_top_bs);
 | 
				
			||||||
    bdrv_ref(target_bs);
 | 
					    bdrv_ref(target_bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Remove target parent that still uses BLK_PERM_WRITE/RESIZE before
 | 
					     * Remove target parent that still uses BLK_PERM_WRITE/RESIZE before
 | 
				
			||||||
     * inserting target_bs at s->to_replace, where we might not be able to get
 | 
					     * inserting target_bs at s->to_replace, where we might not be able to get
 | 
				
			||||||
@ -709,12 +712,12 @@ static int mirror_exit_common(Job *job)
 | 
				
			|||||||
     * these permissions any more means that we can't allow any new requests on
 | 
					     * these permissions any more means that we can't allow any new requests on
 | 
				
			||||||
     * mirror_top_bs from now on, so keep it drained. */
 | 
					     * mirror_top_bs from now on, so keep it drained. */
 | 
				
			||||||
    bdrv_drained_begin(mirror_top_bs);
 | 
					    bdrv_drained_begin(mirror_top_bs);
 | 
				
			||||||
 | 
					    bdrv_drained_begin(target_bs);
 | 
				
			||||||
    bs_opaque->stop = true;
 | 
					    bs_opaque->stop = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
 | 
					    bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
 | 
				
			||||||
                             &error_abort);
 | 
					                             &error_abort);
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) {
 | 
					    if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) {
 | 
				
			||||||
        BlockDriverState *backing = s->is_none_mode ? src : s->base;
 | 
					        BlockDriverState *backing = s->is_none_mode ? src : s->base;
 | 
				
			||||||
@ -737,6 +740,7 @@ static int mirror_exit_common(Job *job)
 | 
				
			|||||||
            local_err = NULL;
 | 
					            local_err = NULL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->to_replace) {
 | 
					    if (s->to_replace) {
 | 
				
			||||||
        replace_aio_context = bdrv_get_aio_context(s->to_replace);
 | 
					        replace_aio_context = bdrv_get_aio_context(s->to_replace);
 | 
				
			||||||
@ -754,15 +758,13 @@ static int mirror_exit_common(Job *job)
 | 
				
			|||||||
        /* The mirror job has no requests in flight any more, but we need to
 | 
					        /* The mirror job has no requests in flight any more, but we need to
 | 
				
			||||||
         * drain potential other users of the BDS before changing the graph. */
 | 
					         * drain potential other users of the BDS before changing the graph. */
 | 
				
			||||||
        assert(s->in_drain);
 | 
					        assert(s->in_drain);
 | 
				
			||||||
        bdrv_drained_begin(target_bs);
 | 
					        bdrv_drained_begin(to_replace);
 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
         * Cannot use check_to_replace_node() here, because that would
 | 
					         * Cannot use check_to_replace_node() here, because that would
 | 
				
			||||||
         * check for an op blocker on @to_replace, and we have our own
 | 
					         * check for an op blocker on @to_replace, and we have our own
 | 
				
			||||||
         * there.
 | 
					         * there.
 | 
				
			||||||
         *
 | 
					 | 
				
			||||||
         * TODO Pull out the writer lock from bdrv_replace_node() to here
 | 
					 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        bdrv_graph_rdlock_main_loop();
 | 
					        bdrv_graph_wrlock(target_bs);
 | 
				
			||||||
        if (bdrv_recurse_can_replace(src, to_replace)) {
 | 
					        if (bdrv_recurse_can_replace(src, to_replace)) {
 | 
				
			||||||
            bdrv_replace_node(to_replace, target_bs, &local_err);
 | 
					            bdrv_replace_node(to_replace, target_bs, &local_err);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@ -771,8 +773,8 @@ static int mirror_exit_common(Job *job)
 | 
				
			|||||||
                       "would not lead to an abrupt change of visible data",
 | 
					                       "would not lead to an abrupt change of visible data",
 | 
				
			||||||
                       to_replace->node_name, target_bs->node_name);
 | 
					                       to_replace->node_name, target_bs->node_name);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        bdrv_graph_rdunlock_main_loop();
 | 
					        bdrv_graph_wrunlock();
 | 
				
			||||||
        bdrv_drained_end(target_bs);
 | 
					        bdrv_drained_end(to_replace);
 | 
				
			||||||
        if (local_err) {
 | 
					        if (local_err) {
 | 
				
			||||||
            error_report_err(local_err);
 | 
					            error_report_err(local_err);
 | 
				
			||||||
            ret = -EPERM;
 | 
					            ret = -EPERM;
 | 
				
			||||||
@ -787,7 +789,6 @@ static int mirror_exit_common(Job *job)
 | 
				
			|||||||
        aio_context_release(replace_aio_context);
 | 
					        aio_context_release(replace_aio_context);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    g_free(s->replaces);
 | 
					    g_free(s->replaces);
 | 
				
			||||||
    bdrv_unref(target_bs);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Remove the mirror filter driver from the graph. Before this, get rid of
 | 
					     * Remove the mirror filter driver from the graph. Before this, get rid of
 | 
				
			||||||
@ -795,7 +796,12 @@ static int mirror_exit_common(Job *job)
 | 
				
			|||||||
     * valid.
 | 
					     * valid.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    block_job_remove_all_bdrv(bjob);
 | 
					    block_job_remove_all_bdrv(bjob);
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(mirror_top_bs);
 | 
				
			||||||
    bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);
 | 
					    bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_drained_end(target_bs);
 | 
				
			||||||
 | 
					    bdrv_unref(target_bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bs_opaque->job = NULL;
 | 
					    bs_opaque->job = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -833,14 +839,18 @@ static void coroutine_fn mirror_throttle(MirrorBlockJob *s)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
 | 
					static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int64_t offset;
 | 
					    int64_t offset;
 | 
				
			||||||
    BlockDriverState *bs = s->mirror_top_bs->backing->bs;
 | 
					    BlockDriverState *bs;
 | 
				
			||||||
    BlockDriverState *target_bs = blk_bs(s->target);
 | 
					    BlockDriverState *target_bs = blk_bs(s->target);
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
    int64_t count;
 | 
					    int64_t count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_co_rdlock();
 | 
				
			||||||
 | 
					    bs = s->mirror_top_bs->backing->bs;
 | 
				
			||||||
 | 
					    bdrv_graph_co_rdunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->zero_target) {
 | 
					    if (s->zero_target) {
 | 
				
			||||||
        if (!bdrv_can_write_zeroes_with_unmap(target_bs)) {
 | 
					        if (!bdrv_can_write_zeroes_with_unmap(target_bs)) {
 | 
				
			||||||
            bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length);
 | 
					            bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length);
 | 
				
			||||||
@ -920,7 +930,7 @@ static int coroutine_fn mirror_flush(MirrorBlockJob *s)
 | 
				
			|||||||
static int coroutine_fn mirror_run(Job *job, Error **errp)
 | 
					static int coroutine_fn mirror_run(Job *job, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
 | 
					    MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
 | 
				
			||||||
    BlockDriverState *bs = s->mirror_top_bs->backing->bs;
 | 
					    BlockDriverState *bs;
 | 
				
			||||||
    MirrorBDSOpaque *mirror_top_opaque = s->mirror_top_bs->opaque;
 | 
					    MirrorBDSOpaque *mirror_top_opaque = s->mirror_top_bs->opaque;
 | 
				
			||||||
    BlockDriverState *target_bs = blk_bs(s->target);
 | 
					    BlockDriverState *target_bs = blk_bs(s->target);
 | 
				
			||||||
    bool need_drain = true;
 | 
					    bool need_drain = true;
 | 
				
			||||||
@ -932,6 +942,10 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
 | 
				
			|||||||
                                 checking for a NULL string */
 | 
					                                 checking for a NULL string */
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_co_rdlock();
 | 
				
			||||||
 | 
					    bs = bdrv_filter_bs(s->mirror_top_bs);
 | 
				
			||||||
 | 
					    bdrv_graph_co_rdunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (job_is_cancelled(&s->common.job)) {
 | 
					    if (job_is_cancelled(&s->common.job)) {
 | 
				
			||||||
        goto immediate_exit;
 | 
					        goto immediate_exit;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -992,13 +1006,13 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        s->target_cluster_size = BDRV_SECTOR_SIZE;
 | 
					        s->target_cluster_size = BDRV_SECTOR_SIZE;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    bdrv_graph_co_rdunlock();
 | 
					 | 
				
			||||||
    if (backing_filename[0] && !bdrv_backing_chain_next(target_bs) &&
 | 
					    if (backing_filename[0] && !bdrv_backing_chain_next(target_bs) &&
 | 
				
			||||||
        s->granularity < s->target_cluster_size) {
 | 
					        s->granularity < s->target_cluster_size) {
 | 
				
			||||||
        s->buf_size = MAX(s->buf_size, s->target_cluster_size);
 | 
					        s->buf_size = MAX(s->buf_size, s->target_cluster_size);
 | 
				
			||||||
        s->cow_bitmap = bitmap_new(length);
 | 
					        s->cow_bitmap = bitmap_new(length);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    s->max_iov = MIN(bs->bl.max_iov, target_bs->bl.max_iov);
 | 
					    s->max_iov = MIN(bs->bl.max_iov, target_bs->bl.max_iov);
 | 
				
			||||||
 | 
					    bdrv_graph_co_rdunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->buf = qemu_try_blockalign(bs, s->buf_size);
 | 
					    s->buf = qemu_try_blockalign(bs, s->buf_size);
 | 
				
			||||||
    if (s->buf == NULL) {
 | 
					    if (s->buf == NULL) {
 | 
				
			||||||
@ -1064,7 +1078,9 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
 | 
				
			|||||||
                mirror_wait_for_free_in_flight_slot(s);
 | 
					                mirror_wait_for_free_in_flight_slot(s);
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            } else if (cnt != 0) {
 | 
					            } else if (cnt != 0) {
 | 
				
			||||||
 | 
					                bdrv_graph_co_rdlock();
 | 
				
			||||||
                mirror_iteration(s);
 | 
					                mirror_iteration(s);
 | 
				
			||||||
 | 
					                bdrv_graph_co_rdunlock();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1634,7 +1650,7 @@ bdrv_mirror_top_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
 | 
				
			|||||||
                                    offset, bytes, NULL, 0);
 | 
					                                    offset, bytes, NULL, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs)
 | 
					static void GRAPH_RDLOCK bdrv_mirror_top_refresh_filename(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (bs->backing == NULL) {
 | 
					    if (bs->backing == NULL) {
 | 
				
			||||||
        /* we can be here after failed bdrv_attach_child in
 | 
					        /* we can be here after failed bdrv_attach_child in
 | 
				
			||||||
@ -1744,12 +1760,15 @@ static BlockJob *mirror_start_job(
 | 
				
			|||||||
        buf_size = DEFAULT_MIRROR_BUF_SIZE;
 | 
					        buf_size = DEFAULT_MIRROR_BUF_SIZE;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    if (bdrv_skip_filters(bs) == bdrv_skip_filters(target)) {
 | 
					    if (bdrv_skip_filters(bs) == bdrv_skip_filters(target)) {
 | 
				
			||||||
        error_setg(errp, "Can't mirror node into itself");
 | 
					        error_setg(errp, "Can't mirror node into itself");
 | 
				
			||||||
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    target_is_backing = bdrv_chain_contains(bs, target);
 | 
					    target_is_backing = bdrv_chain_contains(bs, target);
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* In the case of active commit, add dummy driver to provide consistent
 | 
					    /* In the case of active commit, add dummy driver to provide consistent
 | 
				
			||||||
     * reads on the top, while disabling it in the intermediate nodes, and make
 | 
					     * reads on the top, while disabling it in the intermediate nodes, and make
 | 
				
			||||||
@ -1832,14 +1851,19 @@ static BlockJob *mirror_start_job(
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        target_shared_perms |= BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
 | 
					        target_shared_perms |= BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
 | 
				
			||||||
    } else if (bdrv_chain_contains(bs, bdrv_skip_filters(target))) {
 | 
					    } else {
 | 
				
			||||||
        /*
 | 
					        bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
         * We may want to allow this in the future, but it would
 | 
					        if (bdrv_chain_contains(bs, bdrv_skip_filters(target))) {
 | 
				
			||||||
         * require taking some extra care.
 | 
					            /*
 | 
				
			||||||
         */
 | 
					             * We may want to allow this in the future, but it would
 | 
				
			||||||
        error_setg(errp, "Cannot mirror to a filter on top of a node in the "
 | 
					             * require taking some extra care.
 | 
				
			||||||
                   "source's backing chain");
 | 
					             */
 | 
				
			||||||
        goto fail;
 | 
					            error_setg(errp, "Cannot mirror to a filter on top of a node in "
 | 
				
			||||||
 | 
					                       "the source's backing chain");
 | 
				
			||||||
 | 
					            bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->target = blk_new(s->common.job.aio_context,
 | 
					    s->target = blk_new(s->common.job.aio_context,
 | 
				
			||||||
@ -1860,6 +1884,7 @@ static BlockJob *mirror_start_job(
 | 
				
			|||||||
    blk_set_allow_aio_context_change(s->target, true);
 | 
					    blk_set_allow_aio_context_change(s->target, true);
 | 
				
			||||||
    blk_set_disable_request_queuing(s->target, true);
 | 
					    blk_set_disable_request_queuing(s->target, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    s->replaces = g_strdup(replaces);
 | 
					    s->replaces = g_strdup(replaces);
 | 
				
			||||||
    s->on_source_error = on_source_error;
 | 
					    s->on_source_error = on_source_error;
 | 
				
			||||||
    s->on_target_error = on_target_error;
 | 
					    s->on_target_error = on_target_error;
 | 
				
			||||||
@ -1875,6 +1900,7 @@ static BlockJob *mirror_start_job(
 | 
				
			|||||||
    if (auto_complete) {
 | 
					    if (auto_complete) {
 | 
				
			||||||
        s->should_complete = true;
 | 
					        s->should_complete = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->dirty_bitmap = bdrv_create_dirty_bitmap(s->mirror_top_bs, granularity,
 | 
					    s->dirty_bitmap = bdrv_create_dirty_bitmap(s->mirror_top_bs, granularity,
 | 
				
			||||||
                                               NULL, errp);
 | 
					                                               NULL, errp);
 | 
				
			||||||
@ -1888,11 +1914,13 @@ static BlockJob *mirror_start_job(
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    bdrv_disable_dirty_bitmap(s->dirty_bitmap);
 | 
					    bdrv_disable_dirty_bitmap(s->dirty_bitmap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(bs);
 | 
				
			||||||
    ret = block_job_add_bdrv(&s->common, "source", bs, 0,
 | 
					    ret = block_job_add_bdrv(&s->common, "source", bs, 0,
 | 
				
			||||||
                             BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |
 | 
					                             BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |
 | 
				
			||||||
                             BLK_PERM_CONSISTENT_READ,
 | 
					                             BLK_PERM_CONSISTENT_READ,
 | 
				
			||||||
                             errp);
 | 
					                             errp);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        bdrv_graph_wrunlock();
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1937,14 +1965,17 @@ static BlockJob *mirror_start_job(
 | 
				
			|||||||
            ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
 | 
					            ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
 | 
				
			||||||
                                     iter_shared_perms, errp);
 | 
					                                     iter_shared_perms, errp);
 | 
				
			||||||
            if (ret < 0) {
 | 
					            if (ret < 0) {
 | 
				
			||||||
 | 
					                bdrv_graph_wrunlock();
 | 
				
			||||||
                goto fail;
 | 
					                goto fail;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
 | 
					        if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
 | 
				
			||||||
 | 
					            bdrv_graph_wrunlock();
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QTAILQ_INIT(&s->ops_in_flight);
 | 
					    QTAILQ_INIT(&s->ops_in_flight);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1969,11 +2000,14 @@ fail:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bs_opaque->stop = true;
 | 
					    bs_opaque->stop = true;
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					    bdrv_drained_begin(bs);
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(bs);
 | 
				
			||||||
 | 
					    assert(mirror_top_bs->backing->bs == bs);
 | 
				
			||||||
    bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
 | 
					    bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
 | 
				
			||||||
                             &error_abort);
 | 
					                             &error_abort);
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					    bdrv_replace_node(mirror_top_bs, bs, &error_abort);
 | 
				
			||||||
    bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					    bdrv_drained_end(bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_unref(mirror_top_bs);
 | 
					    bdrv_unref(mirror_top_bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2002,8 +2036,12 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
                   MirrorSyncMode_str(mode));
 | 
					                   MirrorSyncMode_str(mode));
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
 | 
					    is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
 | 
				
			||||||
    base = mode == MIRROR_SYNC_MODE_TOP ? bdrv_backing_chain_next(bs) : NULL;
 | 
					    base = mode == MIRROR_SYNC_MODE_TOP ? bdrv_backing_chain_next(bs) : NULL;
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mirror_start_job(job_id, bs, creation_flags, target, replaces,
 | 
					    mirror_start_job(job_id, bs, creation_flags, target, replaces,
 | 
				
			||||||
                     speed, granularity, buf_size, backing_mode, zero_target,
 | 
					                     speed, granularity, buf_size, backing_mode, zero_target,
 | 
				
			||||||
                     on_source_error, on_target_error, unmap, NULL, NULL,
 | 
					                     on_source_error, on_target_error, unmap, NULL, NULL,
 | 
				
			||||||
 | 
				
			|||||||
@ -206,6 +206,9 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
 | 
				
			|||||||
    BlockBackend *blk;
 | 
					    BlockBackend *blk;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!strcmp(device, "all")) {
 | 
					    if (!strcmp(device, "all")) {
 | 
				
			||||||
        ret = blk_commit_all();
 | 
					        ret = blk_commit_all();
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
				
			|||||||
@ -59,11 +59,10 @@ typedef struct ParallelsDirtyBitmapFeature {
 | 
				
			|||||||
} QEMU_PACKED ParallelsDirtyBitmapFeature;
 | 
					} QEMU_PACKED ParallelsDirtyBitmapFeature;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Given L1 table read bitmap data from the image and populate @bitmap */
 | 
					/* Given L1 table read bitmap data from the image and populate @bitmap */
 | 
				
			||||||
static int parallels_load_bitmap_data(BlockDriverState *bs,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                                      const uint64_t *l1_table,
 | 
					parallels_load_bitmap_data(BlockDriverState *bs, const uint64_t *l1_table,
 | 
				
			||||||
                                      uint32_t l1_size,
 | 
					                           uint32_t l1_size, BdrvDirtyBitmap *bitmap,
 | 
				
			||||||
                                      BdrvDirtyBitmap *bitmap,
 | 
					                           Error **errp)
 | 
				
			||||||
                                      Error **errp)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVParallelsState *s = bs->opaque;
 | 
					    BDRVParallelsState *s = bs->opaque;
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
@ -120,10 +119,9 @@ finish:
 | 
				
			|||||||
 * @data buffer (of @data_size size) is the Dirty bitmaps feature which
 | 
					 * @data buffer (of @data_size size) is the Dirty bitmaps feature which
 | 
				
			||||||
 * consists of ParallelsDirtyBitmapFeature followed by L1 table.
 | 
					 * consists of ParallelsDirtyBitmapFeature followed by L1 table.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static BdrvDirtyBitmap *parallels_load_bitmap(BlockDriverState *bs,
 | 
					static BdrvDirtyBitmap * GRAPH_RDLOCK
 | 
				
			||||||
                                              uint8_t *data,
 | 
					parallels_load_bitmap(BlockDriverState *bs, uint8_t *data, size_t data_size,
 | 
				
			||||||
                                              size_t data_size,
 | 
					                      Error **errp)
 | 
				
			||||||
                                              Error **errp)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
    ParallelsDirtyBitmapFeature bf;
 | 
					    ParallelsDirtyBitmapFeature bf;
 | 
				
			||||||
@ -183,8 +181,9 @@ static BdrvDirtyBitmap *parallels_load_bitmap(BlockDriverState *bs,
 | 
				
			|||||||
    return bitmap;
 | 
					    return bitmap;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int parallels_parse_format_extension(BlockDriverState *bs,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                                            uint8_t *ext_cluster, Error **errp)
 | 
					parallels_parse_format_extension(BlockDriverState *bs, uint8_t *ext_cluster,
 | 
				
			||||||
 | 
					                                 Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVParallelsState *s = bs->opaque;
 | 
					    BDRVParallelsState *s = bs->opaque;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
				
			|||||||
@ -200,7 +200,7 @@ static int mark_used(BlockDriverState *bs, unsigned long *bitmap,
 | 
				
			|||||||
 * bitmap anyway, as much as we can. This information will be used for
 | 
					 * bitmap anyway, as much as we can. This information will be used for
 | 
				
			||||||
 * error resolution.
 | 
					 * error resolution.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int parallels_fill_used_bitmap(BlockDriverState *bs)
 | 
					static int GRAPH_RDLOCK parallels_fill_used_bitmap(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVParallelsState *s = bs->opaque;
 | 
					    BDRVParallelsState *s = bs->opaque;
 | 
				
			||||||
    int64_t payload_bytes;
 | 
					    int64_t payload_bytes;
 | 
				
			||||||
@ -415,14 +415,10 @@ parallels_co_flush_to_os(BlockDriverState *bs)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
static int coroutine_fn parallels_co_block_status(BlockDriverState *bs,
 | 
					parallels_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset,
 | 
				
			||||||
                                                  bool want_zero,
 | 
					                          int64_t bytes, int64_t *pnum, int64_t *map,
 | 
				
			||||||
                                                  int64_t offset,
 | 
					                          BlockDriverState **file)
 | 
				
			||||||
                                                  int64_t bytes,
 | 
					 | 
				
			||||||
                                                  int64_t *pnum,
 | 
					 | 
				
			||||||
                                                  int64_t *map,
 | 
					 | 
				
			||||||
                                                  BlockDriverState **file)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVParallelsState *s = bs->opaque;
 | 
					    BDRVParallelsState *s = bs->opaque;
 | 
				
			||||||
    int count;
 | 
					    int count;
 | 
				
			||||||
@ -1189,7 +1185,7 @@ static int parallels_probe(const uint8_t *buf, int buf_size,
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int parallels_update_header(BlockDriverState *bs)
 | 
					static int GRAPH_RDLOCK parallels_update_header(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVParallelsState *s = bs->opaque;
 | 
					    BDRVParallelsState *s = bs->opaque;
 | 
				
			||||||
    unsigned size = MAX(bdrv_opt_mem_align(bs->file->bs),
 | 
					    unsigned size = MAX(bdrv_opt_mem_align(bs->file->bs),
 | 
				
			||||||
@ -1259,6 +1255,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    file_nb_sectors = bdrv_nb_sectors(bs->file->bs);
 | 
					    file_nb_sectors = bdrv_nb_sectors(bs->file->bs);
 | 
				
			||||||
    if (file_nb_sectors < 0) {
 | 
					    if (file_nb_sectors < 0) {
 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
@ -1363,11 +1361,9 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
        bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block));
 | 
					        bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Disable migration until bdrv_activate method is added */
 | 
					    /* Disable migration until bdrv_activate method is added */
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
    error_setg(&s->migration_blocker, "The Parallels format used by node '%s' "
 | 
					    error_setg(&s->migration_blocker, "The Parallels format used by node '%s' "
 | 
				
			||||||
               "does not support live migration",
 | 
					               "does not support live migration",
 | 
				
			||||||
               bdrv_get_device_or_node_name(bs));
 | 
					               bdrv_get_device_or_node_name(bs));
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
 | 
					    ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
@ -1432,6 +1428,8 @@ static void parallels_close(BlockDriverState *bs)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    BDRVParallelsState *s = bs->opaque;
 | 
					    BDRVParallelsState *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((bs->open_flags & BDRV_O_RDWR) && !(bs->open_flags & BDRV_O_INACTIVE)) {
 | 
					    if ((bs->open_flags & BDRV_O_RDWR) && !(bs->open_flags & BDRV_O_INACTIVE)) {
 | 
				
			||||||
        s->header->inuse = 0;
 | 
					        s->header->inuse = 0;
 | 
				
			||||||
        parallels_update_header(bs);
 | 
					        parallels_update_header(bs);
 | 
				
			||||||
 | 
				
			|||||||
@ -90,7 +90,8 @@ typedef struct BDRVParallelsState {
 | 
				
			|||||||
    Error *migration_blocker;
 | 
					    Error *migration_blocker;
 | 
				
			||||||
} BDRVParallelsState;
 | 
					} BDRVParallelsState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int parallels_read_format_extension(BlockDriverState *bs,
 | 
					int GRAPH_RDLOCK
 | 
				
			||||||
                                    int64_t ext_off, Error **errp);
 | 
					parallels_read_format_extension(BlockDriverState *bs, int64_t ext_off,
 | 
				
			||||||
 | 
					                                Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -143,6 +143,8 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    BDRVPreallocateState *s = bs->opaque;
 | 
					    BDRVPreallocateState *s = bs->opaque;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * s->data_end and friends should be initialized on permission update.
 | 
					     * s->data_end and friends should be initialized on permission update.
 | 
				
			||||||
     * For this to work, mark them invalid.
 | 
					     * For this to work, mark them invalid.
 | 
				
			||||||
@ -155,6 +157,8 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!preallocate_absorb_opts(&s->opts, options, bs->file->bs, errp)) {
 | 
					    if (!preallocate_absorb_opts(&s->opts, options, bs->file->bs, errp)) {
 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -169,7 +173,8 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int preallocate_truncate_to_real_size(BlockDriverState *bs, Error **errp)
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
 | 
					preallocate_truncate_to_real_size(BlockDriverState *bs, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVPreallocateState *s = bs->opaque;
 | 
					    BDRVPreallocateState *s = bs->opaque;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
@ -200,6 +205,9 @@ static void preallocate_close(BlockDriverState *bs)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    BDRVPreallocateState *s = bs->opaque;
 | 
					    BDRVPreallocateState *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qemu_bh_cancel(s->drop_resize_bh);
 | 
					    qemu_bh_cancel(s->drop_resize_bh);
 | 
				
			||||||
    qemu_bh_delete(s->drop_resize_bh);
 | 
					    qemu_bh_delete(s->drop_resize_bh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -223,6 +231,9 @@ static int preallocate_reopen_prepare(BDRVReopenState *reopen_state,
 | 
				
			|||||||
    PreallocateOpts *opts = g_new0(PreallocateOpts, 1);
 | 
					    PreallocateOpts *opts = g_new0(PreallocateOpts, 1);
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!preallocate_absorb_opts(opts, reopen_state->options,
 | 
					    if (!preallocate_absorb_opts(opts, reopen_state->options,
 | 
				
			||||||
                                 reopen_state->bs->file->bs, errp)) {
 | 
					                                 reopen_state->bs->file->bs, errp)) {
 | 
				
			||||||
        g_free(opts);
 | 
					        g_free(opts);
 | 
				
			||||||
@ -283,7 +294,7 @@ static bool can_write_resize(uint64_t perm)
 | 
				
			|||||||
    return (perm & BLK_PERM_WRITE) && (perm & BLK_PERM_RESIZE);
 | 
					    return (perm & BLK_PERM_WRITE) && (perm & BLK_PERM_RESIZE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool has_prealloc_perms(BlockDriverState *bs)
 | 
					static bool GRAPH_RDLOCK has_prealloc_perms(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVPreallocateState *s = bs->opaque;
 | 
					    BDRVPreallocateState *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -499,7 +510,8 @@ preallocate_co_getlength(BlockDriverState *bs)
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int preallocate_drop_resize(BlockDriverState *bs, Error **errp)
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
 | 
					preallocate_drop_resize(BlockDriverState *bs, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVPreallocateState *s = bs->opaque;
 | 
					    BDRVPreallocateState *s = bs->opaque;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
@ -525,15 +537,16 @@ static int preallocate_drop_resize(BlockDriverState *bs, Error **errp)
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    s->data_end = s->file_end = s->zero_start = -EINVAL;
 | 
					    s->data_end = s->file_end = s->zero_start = -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
    bdrv_child_refresh_perms(bs, bs->file, NULL);
 | 
					    bdrv_child_refresh_perms(bs, bs->file, NULL);
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void preallocate_drop_resize_bh(void *opaque)
 | 
					static void preallocate_drop_resize_bh(void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * In case of errors, we'll simply keep the exclusive lock on the image
 | 
					     * In case of errors, we'll simply keep the exclusive lock on the image
 | 
				
			||||||
     * indefinitely.
 | 
					     * indefinitely.
 | 
				
			||||||
@ -541,8 +554,8 @@ static void preallocate_drop_resize_bh(void *opaque)
 | 
				
			|||||||
    preallocate_drop_resize(opaque, NULL);
 | 
					    preallocate_drop_resize(opaque, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void preallocate_set_perm(BlockDriverState *bs,
 | 
					static void GRAPH_RDLOCK
 | 
				
			||||||
                                 uint64_t perm, uint64_t shared)
 | 
					preallocate_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVPreallocateState *s = bs->opaque;
 | 
					    BDRVPreallocateState *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										13
									
								
								block/qcow.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								block/qcow.c
									
									
									
									
									
								
							@ -124,9 +124,11 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
 | 
					    ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        goto fail;
 | 
					        goto fail_unlocked;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0);
 | 
					    ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
@ -301,11 +303,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Disable migration when qcow images are used */
 | 
					    /* Disable migration when qcow images are used */
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
    error_setg(&s->migration_blocker, "The qcow format used by node '%s' "
 | 
					    error_setg(&s->migration_blocker, "The qcow format used by node '%s' "
 | 
				
			||||||
               "does not support live migration",
 | 
					               "does not support live migration",
 | 
				
			||||||
               bdrv_get_device_or_node_name(bs));
 | 
					               bdrv_get_device_or_node_name(bs));
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
 | 
					    ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
@ -315,9 +315,12 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    qobject_unref(encryptopts);
 | 
					    qobject_unref(encryptopts);
 | 
				
			||||||
    qapi_free_QCryptoBlockOpenOptions(crypto_opts);
 | 
					    qapi_free_QCryptoBlockOpenOptions(crypto_opts);
 | 
				
			||||||
    qemu_co_mutex_init(&s->lock);
 | 
					    qemu_co_mutex_init(&s->lock);
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 fail:
 | 
					fail:
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					fail_unlocked:
 | 
				
			||||||
    g_free(s->l1_table);
 | 
					    g_free(s->l1_table);
 | 
				
			||||||
    qemu_vfree(s->l2_cache);
 | 
					    qemu_vfree(s->l2_cache);
 | 
				
			||||||
    g_free(s->cluster_cache);
 | 
					    g_free(s->cluster_cache);
 | 
				
			||||||
@ -1024,7 +1027,7 @@ fail:
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int qcow_make_empty(BlockDriverState *bs)
 | 
					static int GRAPH_RDLOCK qcow_make_empty(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcowState *s = bs->opaque;
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
    uint32_t l1_length = s->l1_size * sizeof(uint64_t);
 | 
					    uint32_t l1_length = s->l1_size * sizeof(uint64_t);
 | 
				
			||||||
 | 
				
			|||||||
@ -105,7 +105,7 @@ static inline bool can_write(BlockDriverState *bs)
 | 
				
			|||||||
    return !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE);
 | 
					    return !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int update_header_sync(BlockDriverState *bs)
 | 
					static int GRAPH_RDLOCK update_header_sync(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -221,8 +221,9 @@ clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                             uint64_t **bitmap_table)
 | 
					bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb,
 | 
				
			||||||
 | 
					                  uint64_t **bitmap_table)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
    BDRVQcow2State *s = bs->opaque;
 | 
					    BDRVQcow2State *s = bs->opaque;
 | 
				
			||||||
@ -551,8 +552,9 @@ static uint32_t bitmap_list_count(Qcow2BitmapList *bm_list)
 | 
				
			|||||||
 * Get bitmap list from qcow2 image. Actually reads bitmap directory,
 | 
					 * Get bitmap list from qcow2 image. Actually reads bitmap directory,
 | 
				
			||||||
 * checks it and convert to bitmap list.
 | 
					 * checks it and convert to bitmap list.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset,
 | 
					static Qcow2BitmapList * GRAPH_RDLOCK
 | 
				
			||||||
                                         uint64_t size, Error **errp)
 | 
					bitmap_list_load(BlockDriverState *bs, uint64_t offset, uint64_t size,
 | 
				
			||||||
 | 
					                 Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
    BDRVQcow2State *s = bs->opaque;
 | 
					    BDRVQcow2State *s = bs->opaque;
 | 
				
			||||||
@ -961,7 +963,7 @@ static void set_readonly_helper(gpointer bitmap, gpointer value)
 | 
				
			|||||||
 * If header_updated is not NULL then it is set appropriately regardless of
 | 
					 * If header_updated is not NULL then it is set appropriately regardless of
 | 
				
			||||||
 * the return value.
 | 
					 * the return value.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool coroutine_fn GRAPH_RDLOCK
 | 
					bool coroutine_fn
 | 
				
			||||||
qcow2_load_dirty_bitmaps(BlockDriverState *bs,
 | 
					qcow2_load_dirty_bitmaps(BlockDriverState *bs,
 | 
				
			||||||
                         bool *header_updated, Error **errp)
 | 
					                         bool *header_updated, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
				
			|||||||
@ -391,11 +391,10 @@ fail:
 | 
				
			|||||||
 * If the L2 entry is invalid return -errno and set @type to
 | 
					 * If the L2 entry is invalid return -errno and set @type to
 | 
				
			||||||
 * QCOW2_SUBCLUSTER_INVALID.
 | 
					 * QCOW2_SUBCLUSTER_INVALID.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int qcow2_get_subcluster_range_type(BlockDriverState *bs,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                                           uint64_t l2_entry,
 | 
					qcow2_get_subcluster_range_type(BlockDriverState *bs, uint64_t l2_entry,
 | 
				
			||||||
                                           uint64_t l2_bitmap,
 | 
					                                uint64_t l2_bitmap, unsigned sc_from,
 | 
				
			||||||
                                           unsigned sc_from,
 | 
					                                QCow2SubclusterType *type)
 | 
				
			||||||
                                           QCow2SubclusterType *type)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcow2State *s = bs->opaque;
 | 
					    BDRVQcow2State *s = bs->opaque;
 | 
				
			||||||
    uint32_t val;
 | 
					    uint32_t val;
 | 
				
			||||||
@ -442,9 +441,10 @@ static int qcow2_get_subcluster_range_type(BlockDriverState *bs,
 | 
				
			|||||||
 * On failure return -errno and update @l2_index to point to the
 | 
					 * On failure return -errno and update @l2_index to point to the
 | 
				
			||||||
 * invalid entry.
 | 
					 * invalid entry.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int count_contiguous_subclusters(BlockDriverState *bs, int nb_clusters,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                                        unsigned sc_index, uint64_t *l2_slice,
 | 
					count_contiguous_subclusters(BlockDriverState *bs, int nb_clusters,
 | 
				
			||||||
                                        unsigned *l2_index)
 | 
					                             unsigned sc_index, uint64_t *l2_slice,
 | 
				
			||||||
 | 
					                             unsigned *l2_index)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcow2State *s = bs->opaque;
 | 
					    BDRVQcow2State *s = bs->opaque;
 | 
				
			||||||
    int i, count = 0;
 | 
					    int i, count = 0;
 | 
				
			||||||
@ -1329,7 +1329,8 @@ calculate_l2_meta(BlockDriverState *bs, uint64_t host_cluster_offset,
 | 
				
			|||||||
 * requires a new allocation (that is, if the cluster is unallocated
 | 
					 * requires a new allocation (that is, if the cluster is unallocated
 | 
				
			||||||
 * or has refcount > 1 and therefore cannot be written in-place).
 | 
					 * or has refcount > 1 and therefore cannot be written in-place).
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static bool cluster_needs_new_alloc(BlockDriverState *bs, uint64_t l2_entry)
 | 
					static bool GRAPH_RDLOCK
 | 
				
			||||||
 | 
					cluster_needs_new_alloc(BlockDriverState *bs, uint64_t l2_entry)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch (qcow2_get_cluster_type(bs, l2_entry)) {
 | 
					    switch (qcow2_get_cluster_type(bs, l2_entry)) {
 | 
				
			||||||
    case QCOW2_CLUSTER_NORMAL:
 | 
					    case QCOW2_CLUSTER_NORMAL:
 | 
				
			||||||
@ -1360,9 +1361,9 @@ static bool cluster_needs_new_alloc(BlockDriverState *bs, uint64_t l2_entry)
 | 
				
			|||||||
 * allocated and can be overwritten in-place (this includes clusters
 | 
					 * allocated and can be overwritten in-place (this includes clusters
 | 
				
			||||||
 * of type QCOW2_CLUSTER_ZERO_ALLOC).
 | 
					 * of type QCOW2_CLUSTER_ZERO_ALLOC).
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int count_single_write_clusters(BlockDriverState *bs, int nb_clusters,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                                       uint64_t *l2_slice, int l2_index,
 | 
					count_single_write_clusters(BlockDriverState *bs, int nb_clusters,
 | 
				
			||||||
                                       bool new_alloc)
 | 
					                            uint64_t *l2_slice, int l2_index, bool new_alloc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcow2State *s = bs->opaque;
 | 
					    BDRVQcow2State *s = bs->opaque;
 | 
				
			||||||
    uint64_t l2_entry = get_l2_entry(s, l2_slice, l2_index);
 | 
					    uint64_t l2_entry = get_l2_entry(s, l2_slice, l2_index);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										132
									
								
								block/qcow2.c
									
									
									
									
									
								
							
							
						
						
									
										132
									
								
								block/qcow2.c
									
									
									
									
									
								
							@ -95,9 +95,10 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                                      uint8_t *buf, size_t buflen,
 | 
					qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset,
 | 
				
			||||||
                                      void *opaque, Error **errp)
 | 
					                           uint8_t *buf, size_t buflen,
 | 
				
			||||||
 | 
					                           void *opaque, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriverState *bs = opaque;
 | 
					    BlockDriverState *bs = opaque;
 | 
				
			||||||
    BDRVQcow2State *s = bs->opaque;
 | 
					    BDRVQcow2State *s = bs->opaque;
 | 
				
			||||||
@ -156,7 +157,7 @@ qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, void *opaque,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* The graph lock must be held when called in coroutine context */
 | 
					/* The graph lock must be held when called in coroutine context */
 | 
				
			||||||
static int coroutine_mixed_fn
 | 
					static int coroutine_mixed_fn GRAPH_RDLOCK
 | 
				
			||||||
qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset,
 | 
					qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset,
 | 
				
			||||||
                            const uint8_t *buf, size_t buflen,
 | 
					                            const uint8_t *buf, size_t buflen,
 | 
				
			||||||
                            void *opaque, Error **errp)
 | 
					                            void *opaque, Error **errp)
 | 
				
			||||||
@ -2029,6 +2030,8 @@ static void qcow2_reopen_commit(BDRVReopenState *state)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcow2State *s = state->bs->opaque;
 | 
					    BDRVQcow2State *s = state->bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qcow2_update_options_commit(state->bs, state->opaque);
 | 
					    qcow2_update_options_commit(state->bs, state->opaque);
 | 
				
			||||||
    if (!s->data_file) {
 | 
					    if (!s->data_file) {
 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
@ -2064,6 +2067,8 @@ static void qcow2_reopen_abort(BDRVReopenState *state)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcow2State *s = state->bs->opaque;
 | 
					    BDRVQcow2State *s = state->bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!s->data_file) {
 | 
					    if (!s->data_file) {
 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
         * If we don't have an external data file, s->data_file was cleared by
 | 
					         * If we don't have an external data file, s->data_file was cleared by
 | 
				
			||||||
@ -3155,8 +3160,9 @@ fail:
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int qcow2_change_backing_file(BlockDriverState *bs,
 | 
					static int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
    const char *backing_file, const char *backing_fmt)
 | 
					qcow2_co_change_backing_file(BlockDriverState *bs, const char *backing_file,
 | 
				
			||||||
 | 
					                             const char *backing_fmt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcow2State *s = bs->opaque;
 | 
					    BDRVQcow2State *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3816,8 +3822,11 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
 | 
				
			|||||||
            backing_format = BlockdevDriver_str(qcow2_opts->backing_fmt);
 | 
					            backing_format = BlockdevDriver_str(qcow2_opts->backing_fmt);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ret = bdrv_change_backing_file(blk_bs(blk), qcow2_opts->backing_file,
 | 
					        bdrv_graph_co_rdlock();
 | 
				
			||||||
                                       backing_format, false);
 | 
					        ret = bdrv_co_change_backing_file(blk_bs(blk), qcow2_opts->backing_file,
 | 
				
			||||||
 | 
					                                          backing_format, false);
 | 
				
			||||||
 | 
					        bdrv_graph_co_rdunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (ret < 0) {
 | 
					        if (ret < 0) {
 | 
				
			||||||
            error_setg_errno(errp, -ret, "Could not assign backing file '%s' "
 | 
					            error_setg_errno(errp, -ret, "Could not assign backing file '%s' "
 | 
				
			||||||
                             "with format '%s'", qcow2_opts->backing_file,
 | 
					                             "with format '%s'", qcow2_opts->backing_file,
 | 
				
			||||||
@ -5222,8 +5231,8 @@ qcow2_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs,
 | 
					static ImageInfoSpecific * GRAPH_RDLOCK
 | 
				
			||||||
                                                  Error **errp)
 | 
					qcow2_get_specific_info(BlockDriverState *bs, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcow2State *s = bs->opaque;
 | 
					    BDRVQcow2State *s = bs->opaque;
 | 
				
			||||||
    ImageInfoSpecific *spec_info;
 | 
					    ImageInfoSpecific *spec_info;
 | 
				
			||||||
@ -5302,7 +5311,8 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs,
 | 
				
			|||||||
    return spec_info;
 | 
					    return spec_info;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_mixed_fn qcow2_has_zero_init(BlockDriverState *bs)
 | 
					static int coroutine_mixed_fn GRAPH_RDLOCK
 | 
				
			||||||
 | 
					qcow2_has_zero_init(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcow2State *s = bs->opaque;
 | 
					    BDRVQcow2State *s = bs->opaque;
 | 
				
			||||||
    bool preallocated;
 | 
					    bool preallocated;
 | 
				
			||||||
@ -6114,64 +6124,64 @@ static const char *const qcow2_strong_runtime_opts[] = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BlockDriver bdrv_qcow2 = {
 | 
					BlockDriver bdrv_qcow2 = {
 | 
				
			||||||
    .format_name        = "qcow2",
 | 
					    .format_name                        = "qcow2",
 | 
				
			||||||
    .instance_size      = sizeof(BDRVQcow2State),
 | 
					    .instance_size                      = sizeof(BDRVQcow2State),
 | 
				
			||||||
    .bdrv_probe         = qcow2_probe,
 | 
					    .bdrv_probe                         = qcow2_probe,
 | 
				
			||||||
    .bdrv_open          = qcow2_open,
 | 
					    .bdrv_open                          = qcow2_open,
 | 
				
			||||||
    .bdrv_close         = qcow2_close,
 | 
					    .bdrv_close                         = qcow2_close,
 | 
				
			||||||
    .bdrv_reopen_prepare  = qcow2_reopen_prepare,
 | 
					    .bdrv_reopen_prepare                = qcow2_reopen_prepare,
 | 
				
			||||||
    .bdrv_reopen_commit   = qcow2_reopen_commit,
 | 
					    .bdrv_reopen_commit                 = qcow2_reopen_commit,
 | 
				
			||||||
    .bdrv_reopen_commit_post = qcow2_reopen_commit_post,
 | 
					    .bdrv_reopen_commit_post            = qcow2_reopen_commit_post,
 | 
				
			||||||
    .bdrv_reopen_abort    = qcow2_reopen_abort,
 | 
					    .bdrv_reopen_abort                  = qcow2_reopen_abort,
 | 
				
			||||||
    .bdrv_join_options    = qcow2_join_options,
 | 
					    .bdrv_join_options                  = qcow2_join_options,
 | 
				
			||||||
    .bdrv_child_perm      = bdrv_default_perms,
 | 
					    .bdrv_child_perm                    = bdrv_default_perms,
 | 
				
			||||||
    .bdrv_co_create_opts  = qcow2_co_create_opts,
 | 
					    .bdrv_co_create_opts                = qcow2_co_create_opts,
 | 
				
			||||||
    .bdrv_co_create       = qcow2_co_create,
 | 
					    .bdrv_co_create                     = qcow2_co_create,
 | 
				
			||||||
    .bdrv_has_zero_init   = qcow2_has_zero_init,
 | 
					    .bdrv_has_zero_init                 = qcow2_has_zero_init,
 | 
				
			||||||
    .bdrv_co_block_status = qcow2_co_block_status,
 | 
					    .bdrv_co_block_status               = qcow2_co_block_status,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_co_preadv_part    = qcow2_co_preadv_part,
 | 
					    .bdrv_co_preadv_part                = qcow2_co_preadv_part,
 | 
				
			||||||
    .bdrv_co_pwritev_part   = qcow2_co_pwritev_part,
 | 
					    .bdrv_co_pwritev_part               = qcow2_co_pwritev_part,
 | 
				
			||||||
    .bdrv_co_flush_to_os    = qcow2_co_flush_to_os,
 | 
					    .bdrv_co_flush_to_os                = qcow2_co_flush_to_os,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_co_pwrite_zeroes  = qcow2_co_pwrite_zeroes,
 | 
					    .bdrv_co_pwrite_zeroes              = qcow2_co_pwrite_zeroes,
 | 
				
			||||||
    .bdrv_co_pdiscard       = qcow2_co_pdiscard,
 | 
					    .bdrv_co_pdiscard                   = qcow2_co_pdiscard,
 | 
				
			||||||
    .bdrv_co_copy_range_from = qcow2_co_copy_range_from,
 | 
					    .bdrv_co_copy_range_from            = qcow2_co_copy_range_from,
 | 
				
			||||||
    .bdrv_co_copy_range_to  = qcow2_co_copy_range_to,
 | 
					    .bdrv_co_copy_range_to              = qcow2_co_copy_range_to,
 | 
				
			||||||
    .bdrv_co_truncate       = qcow2_co_truncate,
 | 
					    .bdrv_co_truncate                   = qcow2_co_truncate,
 | 
				
			||||||
    .bdrv_co_pwritev_compressed_part = qcow2_co_pwritev_compressed_part,
 | 
					    .bdrv_co_pwritev_compressed_part    = qcow2_co_pwritev_compressed_part,
 | 
				
			||||||
    .bdrv_make_empty        = qcow2_make_empty,
 | 
					    .bdrv_make_empty                    = qcow2_make_empty,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_snapshot_create   = qcow2_snapshot_create,
 | 
					    .bdrv_snapshot_create               = qcow2_snapshot_create,
 | 
				
			||||||
    .bdrv_snapshot_goto     = qcow2_snapshot_goto,
 | 
					    .bdrv_snapshot_goto                 = qcow2_snapshot_goto,
 | 
				
			||||||
    .bdrv_snapshot_delete   = qcow2_snapshot_delete,
 | 
					    .bdrv_snapshot_delete               = qcow2_snapshot_delete,
 | 
				
			||||||
    .bdrv_snapshot_list     = qcow2_snapshot_list,
 | 
					    .bdrv_snapshot_list                 = qcow2_snapshot_list,
 | 
				
			||||||
    .bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp,
 | 
					    .bdrv_snapshot_load_tmp             = qcow2_snapshot_load_tmp,
 | 
				
			||||||
    .bdrv_measure           = qcow2_measure,
 | 
					    .bdrv_measure                       = qcow2_measure,
 | 
				
			||||||
    .bdrv_co_get_info       = qcow2_co_get_info,
 | 
					    .bdrv_co_get_info                   = qcow2_co_get_info,
 | 
				
			||||||
    .bdrv_get_specific_info = qcow2_get_specific_info,
 | 
					    .bdrv_get_specific_info             = qcow2_get_specific_info,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_co_save_vmstate   = qcow2_co_save_vmstate,
 | 
					    .bdrv_co_save_vmstate               = qcow2_co_save_vmstate,
 | 
				
			||||||
    .bdrv_co_load_vmstate   = qcow2_co_load_vmstate,
 | 
					    .bdrv_co_load_vmstate               = qcow2_co_load_vmstate,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .is_format                  = true,
 | 
					    .is_format                          = true,
 | 
				
			||||||
    .supports_backing           = true,
 | 
					    .supports_backing                   = true,
 | 
				
			||||||
    .bdrv_change_backing_file   = qcow2_change_backing_file,
 | 
					    .bdrv_co_change_backing_file        = qcow2_co_change_backing_file,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_refresh_limits        = qcow2_refresh_limits,
 | 
					    .bdrv_refresh_limits                = qcow2_refresh_limits,
 | 
				
			||||||
    .bdrv_co_invalidate_cache   = qcow2_co_invalidate_cache,
 | 
					    .bdrv_co_invalidate_cache           = qcow2_co_invalidate_cache,
 | 
				
			||||||
    .bdrv_inactivate            = qcow2_inactivate,
 | 
					    .bdrv_inactivate                    = qcow2_inactivate,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .create_opts         = &qcow2_create_opts,
 | 
					    .create_opts                        = &qcow2_create_opts,
 | 
				
			||||||
    .amend_opts          = &qcow2_amend_opts,
 | 
					    .amend_opts                         = &qcow2_amend_opts,
 | 
				
			||||||
    .strong_runtime_opts = qcow2_strong_runtime_opts,
 | 
					    .strong_runtime_opts                = qcow2_strong_runtime_opts,
 | 
				
			||||||
    .mutable_opts        = mutable_opts,
 | 
					    .mutable_opts                       = mutable_opts,
 | 
				
			||||||
    .bdrv_co_check       = qcow2_co_check,
 | 
					    .bdrv_co_check                      = qcow2_co_check,
 | 
				
			||||||
    .bdrv_amend_options  = qcow2_amend_options,
 | 
					    .bdrv_amend_options                 = qcow2_amend_options,
 | 
				
			||||||
    .bdrv_co_amend       = qcow2_co_amend,
 | 
					    .bdrv_co_amend                      = qcow2_co_amend,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_detach_aio_context  = qcow2_detach_aio_context,
 | 
					    .bdrv_detach_aio_context            = qcow2_detach_aio_context,
 | 
				
			||||||
    .bdrv_attach_aio_context  = qcow2_attach_aio_context,
 | 
					    .bdrv_attach_aio_context            = qcow2_attach_aio_context,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_supports_persistent_dirty_bitmap =
 | 
					    .bdrv_supports_persistent_dirty_bitmap =
 | 
				
			||||||
            qcow2_supports_persistent_dirty_bitmap,
 | 
					            qcow2_supports_persistent_dirty_bitmap,
 | 
				
			||||||
 | 
				
			|||||||
@ -641,7 +641,7 @@ static inline void set_l2_bitmap(BDRVQcow2State *s, uint64_t *l2_slice,
 | 
				
			|||||||
    l2_slice[idx + 1] = cpu_to_be64(bitmap);
 | 
					    l2_slice[idx + 1] = cpu_to_be64(bitmap);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline bool has_data_file(BlockDriverState *bs)
 | 
					static inline bool GRAPH_RDLOCK has_data_file(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcow2State *s = bs->opaque;
 | 
					    BDRVQcow2State *s = bs->opaque;
 | 
				
			||||||
    return (s->data_file != bs->file);
 | 
					    return (s->data_file != bs->file);
 | 
				
			||||||
@ -709,8 +709,8 @@ static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s)
 | 
				
			|||||||
    return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
 | 
					    return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs,
 | 
					static inline QCow2ClusterType GRAPH_RDLOCK
 | 
				
			||||||
                                                      uint64_t l2_entry)
 | 
					qcow2_get_cluster_type(BlockDriverState *bs, uint64_t l2_entry)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcow2State *s = bs->opaque;
 | 
					    BDRVQcow2State *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -743,7 +743,7 @@ static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs,
 | 
				
			|||||||
 * (this checks the whole entry and bitmap, not only the bits related
 | 
					 * (this checks the whole entry and bitmap, not only the bits related
 | 
				
			||||||
 * to subcluster @sc_index).
 | 
					 * to subcluster @sc_index).
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static inline
 | 
					static inline GRAPH_RDLOCK
 | 
				
			||||||
QCow2SubclusterType qcow2_get_subcluster_type(BlockDriverState *bs,
 | 
					QCow2SubclusterType qcow2_get_subcluster_type(BlockDriverState *bs,
 | 
				
			||||||
                                              uint64_t l2_entry,
 | 
					                                              uint64_t l2_entry,
 | 
				
			||||||
                                              uint64_t l2_bitmap,
 | 
					                                              uint64_t l2_bitmap,
 | 
				
			||||||
@ -834,9 +834,9 @@ int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
 | 
				
			|||||||
                                     int refcount_order, bool generous_increase,
 | 
					                                     int refcount_order, bool generous_increase,
 | 
				
			||||||
                                     uint64_t *refblock_count);
 | 
					                                     uint64_t *refblock_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qcow2_mark_dirty(BlockDriverState *bs);
 | 
					int GRAPH_RDLOCK qcow2_mark_dirty(BlockDriverState *bs);
 | 
				
			||||||
int qcow2_mark_corrupt(BlockDriverState *bs);
 | 
					int GRAPH_RDLOCK qcow2_mark_corrupt(BlockDriverState *bs);
 | 
				
			||||||
int qcow2_update_header(BlockDriverState *bs);
 | 
					int GRAPH_RDLOCK qcow2_update_header(BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GRAPH_RDLOCK
 | 
					void GRAPH_RDLOCK
 | 
				
			||||||
qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
 | 
					qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
 | 
				
			||||||
@ -890,10 +890,11 @@ int GRAPH_RDLOCK qcow2_write_caches(BlockDriverState *bs);
 | 
				
			|||||||
int coroutine_fn qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
 | 
					int coroutine_fn qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
 | 
				
			||||||
                                       BdrvCheckMode fix);
 | 
					                                       BdrvCheckMode fix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void qcow2_process_discards(BlockDriverState *bs, int ret);
 | 
					void GRAPH_RDLOCK qcow2_process_discards(BlockDriverState *bs, int ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
 | 
					int GRAPH_RDLOCK
 | 
				
			||||||
                                 int64_t size);
 | 
					qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
 | 
				
			||||||
 | 
					                             int64_t size);
 | 
				
			||||||
int GRAPH_RDLOCK
 | 
					int GRAPH_RDLOCK
 | 
				
			||||||
qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
 | 
					qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
 | 
				
			||||||
                              int64_t size, bool data_file);
 | 
					                              int64_t size, bool data_file);
 | 
				
			||||||
@ -939,8 +940,9 @@ qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
 | 
				
			|||||||
int coroutine_fn GRAPH_RDLOCK
 | 
					int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset,
 | 
					qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset,
 | 
				
			||||||
                                      int compressed_size, uint64_t *host_offset);
 | 
					                                      int compressed_size, uint64_t *host_offset);
 | 
				
			||||||
void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
 | 
					void GRAPH_RDLOCK
 | 
				
			||||||
                                     uint64_t *coffset, int *csize);
 | 
					qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
 | 
				
			||||||
 | 
					                                uint64_t *coffset, int *csize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int coroutine_fn GRAPH_RDLOCK
 | 
					int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
 | 
					qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
 | 
				
			||||||
@ -972,11 +974,12 @@ int GRAPH_RDLOCK
 | 
				
			|||||||
qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id,
 | 
					qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id,
 | 
				
			||||||
                          const char *name, Error **errp);
 | 
					                          const char *name, Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
 | 
					int GRAPH_RDLOCK
 | 
				
			||||||
int qcow2_snapshot_load_tmp(BlockDriverState *bs,
 | 
					qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
 | 
				
			||||||
                            const char *snapshot_id,
 | 
					
 | 
				
			||||||
                            const char *name,
 | 
					int GRAPH_RDLOCK
 | 
				
			||||||
                            Error **errp);
 | 
					qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_id,
 | 
				
			||||||
 | 
					                        const char *name, Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void qcow2_free_snapshots(BlockDriverState *bs);
 | 
					void qcow2_free_snapshots(BlockDriverState *bs);
 | 
				
			||||||
int coroutine_fn GRAPH_RDLOCK
 | 
					int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
@ -992,8 +995,9 @@ qcow2_check_fix_snapshot_table(BlockDriverState *bs, BdrvCheckResult *result,
 | 
				
			|||||||
                               BdrvCheckMode fix);
 | 
					                               BdrvCheckMode fix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* qcow2-cache.c functions */
 | 
					/* qcow2-cache.c functions */
 | 
				
			||||||
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
 | 
					Qcow2Cache * GRAPH_RDLOCK
 | 
				
			||||||
                               unsigned table_size);
 | 
					qcow2_cache_create(BlockDriverState *bs, int num_tables, unsigned table_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qcow2_cache_destroy(Qcow2Cache *c);
 | 
					int qcow2_cache_destroy(Qcow2Cache *c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
 | 
					void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
 | 
				
			||||||
@ -1019,17 +1023,24 @@ void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset);
 | 
				
			|||||||
void qcow2_cache_discard(Qcow2Cache *c, void *table);
 | 
					void qcow2_cache_discard(Qcow2Cache *c, void *table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* qcow2-bitmap.c functions */
 | 
					/* qcow2-bitmap.c functions */
 | 
				
			||||||
int coroutine_fn
 | 
					int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
 | 
					qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
 | 
				
			||||||
                              void **refcount_table,
 | 
					                              void **refcount_table,
 | 
				
			||||||
                              int64_t *refcount_table_size);
 | 
					                              int64_t *refcount_table_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool coroutine_fn GRAPH_RDLOCK
 | 
					bool coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, Error **errp);
 | 
					qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated,
 | 
				
			||||||
bool qcow2_get_bitmap_info_list(BlockDriverState *bs,
 | 
					                         Error **errp);
 | 
				
			||||||
                                Qcow2BitmapInfoList **info_list, Error **errp);
 | 
					
 | 
				
			||||||
 | 
					bool GRAPH_RDLOCK
 | 
				
			||||||
 | 
					qcow2_get_bitmap_info_list(BlockDriverState *bs,
 | 
				
			||||||
 | 
					                           Qcow2BitmapInfoList **info_list, Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int GRAPH_RDLOCK qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
 | 
					int GRAPH_RDLOCK qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
 | 
				
			||||||
int GRAPH_RDLOCK qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
 | 
					int GRAPH_RDLOCK qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
 | 
				
			||||||
int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
 | 
					
 | 
				
			||||||
 | 
					int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
 | 
					qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool GRAPH_RDLOCK
 | 
					bool GRAPH_RDLOCK
 | 
				
			||||||
qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, bool release_stored,
 | 
					qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, bool release_stored,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										86
									
								
								block/qed.c
									
									
									
									
									
								
							
							
						
						
									
										86
									
								
								block/qed.c
									
									
									
									
									
								
							@ -612,7 +612,7 @@ static int bdrv_qed_reopen_prepare(BDRVReopenState *state,
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void bdrv_qed_close(BlockDriverState *bs)
 | 
					static void GRAPH_RDLOCK bdrv_qed_do_close(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQEDState *s = bs->opaque;
 | 
					    BDRVQEDState *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -631,6 +631,14 @@ static void bdrv_qed_close(BlockDriverState *bs)
 | 
				
			|||||||
    qemu_vfree(s->l1_table);
 | 
					    qemu_vfree(s->l1_table);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void GRAPH_UNLOCKED bdrv_qed_close(BlockDriverState *bs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_qed_do_close(bs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_fn GRAPH_UNLOCKED
 | 
					static int coroutine_fn GRAPH_UNLOCKED
 | 
				
			||||||
bdrv_qed_co_create(BlockdevCreateOptions *opts, Error **errp)
 | 
					bdrv_qed_co_create(BlockdevCreateOptions *opts, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -1138,7 +1146,7 @@ out:
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Check if the QED_F_NEED_CHECK bit should be set during allocating write
 | 
					 * Check if the QED_F_NEED_CHECK bit should be set during allocating write
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static bool qed_should_set_need_check(BDRVQEDState *s)
 | 
					static bool GRAPH_RDLOCK qed_should_set_need_check(BDRVQEDState *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /* The flush before L2 update path ensures consistency */
 | 
					    /* The flush before L2 update path ensures consistency */
 | 
				
			||||||
    if (s->bs->backing) {
 | 
					    if (s->bs->backing) {
 | 
				
			||||||
@ -1443,12 +1451,10 @@ bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
 | 
				
			|||||||
                          QED_AIOCB_WRITE | QED_AIOCB_ZERO);
 | 
					                          QED_AIOCB_WRITE | QED_AIOCB_ZERO);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs,
 | 
					static int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
                                             int64_t offset,
 | 
					bdrv_qed_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
 | 
				
			||||||
                                             bool exact,
 | 
					                     PreallocMode prealloc, BdrvRequestFlags flags,
 | 
				
			||||||
                                             PreallocMode prealloc,
 | 
					                     Error **errp)
 | 
				
			||||||
                                             BdrvRequestFlags flags,
 | 
					 | 
				
			||||||
                                             Error **errp)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQEDState *s = bs->opaque;
 | 
					    BDRVQEDState *s = bs->opaque;
 | 
				
			||||||
    uint64_t old_image_size;
 | 
					    uint64_t old_image_size;
 | 
				
			||||||
@ -1498,9 +1504,9 @@ bdrv_qed_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int bdrv_qed_change_backing_file(BlockDriverState *bs,
 | 
					static int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
                                        const char *backing_file,
 | 
					bdrv_qed_co_change_backing_file(BlockDriverState *bs, const char *backing_file,
 | 
				
			||||||
                                        const char *backing_fmt)
 | 
					                                const char *backing_fmt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQEDState *s = bs->opaque;
 | 
					    BDRVQEDState *s = bs->opaque;
 | 
				
			||||||
    QEDHeader new_header, le_header;
 | 
					    QEDHeader new_header, le_header;
 | 
				
			||||||
@ -1562,7 +1568,7 @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Write new header */
 | 
					    /* Write new header */
 | 
				
			||||||
    ret = bdrv_pwrite_sync(bs->file, 0, buffer_len, buffer, 0);
 | 
					    ret = bdrv_co_pwrite_sync(bs->file, 0, buffer_len, buffer, 0);
 | 
				
			||||||
    g_free(buffer);
 | 
					    g_free(buffer);
 | 
				
			||||||
    if (ret == 0) {
 | 
					    if (ret == 0) {
 | 
				
			||||||
        memcpy(&s->header, &new_header, sizeof(new_header));
 | 
					        memcpy(&s->header, &new_header, sizeof(new_header));
 | 
				
			||||||
@ -1576,7 +1582,7 @@ bdrv_qed_co_invalidate_cache(BlockDriverState *bs, Error **errp)
 | 
				
			|||||||
    BDRVQEDState *s = bs->opaque;
 | 
					    BDRVQEDState *s = bs->opaque;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_qed_close(bs);
 | 
					    bdrv_qed_do_close(bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_qed_init_state(bs);
 | 
					    bdrv_qed_init_state(bs);
 | 
				
			||||||
    qemu_co_mutex_lock(&s->table_lock);
 | 
					    qemu_co_mutex_lock(&s->table_lock);
 | 
				
			||||||
@ -1636,34 +1642,34 @@ static QemuOptsList qed_create_opts = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BlockDriver bdrv_qed = {
 | 
					static BlockDriver bdrv_qed = {
 | 
				
			||||||
    .format_name              = "qed",
 | 
					    .format_name                    = "qed",
 | 
				
			||||||
    .instance_size            = sizeof(BDRVQEDState),
 | 
					    .instance_size                  = sizeof(BDRVQEDState),
 | 
				
			||||||
    .create_opts              = &qed_create_opts,
 | 
					    .create_opts                    = &qed_create_opts,
 | 
				
			||||||
    .is_format                = true,
 | 
					    .is_format                      = true,
 | 
				
			||||||
    .supports_backing         = true,
 | 
					    .supports_backing               = true,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_probe               = bdrv_qed_probe,
 | 
					    .bdrv_probe                     = bdrv_qed_probe,
 | 
				
			||||||
    .bdrv_open                = bdrv_qed_open,
 | 
					    .bdrv_open                      = bdrv_qed_open,
 | 
				
			||||||
    .bdrv_close               = bdrv_qed_close,
 | 
					    .bdrv_close                     = bdrv_qed_close,
 | 
				
			||||||
    .bdrv_reopen_prepare      = bdrv_qed_reopen_prepare,
 | 
					    .bdrv_reopen_prepare            = bdrv_qed_reopen_prepare,
 | 
				
			||||||
    .bdrv_child_perm          = bdrv_default_perms,
 | 
					    .bdrv_child_perm                = bdrv_default_perms,
 | 
				
			||||||
    .bdrv_co_create           = bdrv_qed_co_create,
 | 
					    .bdrv_co_create                 = bdrv_qed_co_create,
 | 
				
			||||||
    .bdrv_co_create_opts      = bdrv_qed_co_create_opts,
 | 
					    .bdrv_co_create_opts            = bdrv_qed_co_create_opts,
 | 
				
			||||||
    .bdrv_has_zero_init       = bdrv_has_zero_init_1,
 | 
					    .bdrv_has_zero_init             = bdrv_has_zero_init_1,
 | 
				
			||||||
    .bdrv_co_block_status     = bdrv_qed_co_block_status,
 | 
					    .bdrv_co_block_status           = bdrv_qed_co_block_status,
 | 
				
			||||||
    .bdrv_co_readv            = bdrv_qed_co_readv,
 | 
					    .bdrv_co_readv                  = bdrv_qed_co_readv,
 | 
				
			||||||
    .bdrv_co_writev           = bdrv_qed_co_writev,
 | 
					    .bdrv_co_writev                 = bdrv_qed_co_writev,
 | 
				
			||||||
    .bdrv_co_pwrite_zeroes    = bdrv_qed_co_pwrite_zeroes,
 | 
					    .bdrv_co_pwrite_zeroes          = bdrv_qed_co_pwrite_zeroes,
 | 
				
			||||||
    .bdrv_co_truncate         = bdrv_qed_co_truncate,
 | 
					    .bdrv_co_truncate               = bdrv_qed_co_truncate,
 | 
				
			||||||
    .bdrv_co_getlength        = bdrv_qed_co_getlength,
 | 
					    .bdrv_co_getlength              = bdrv_qed_co_getlength,
 | 
				
			||||||
    .bdrv_co_get_info         = bdrv_qed_co_get_info,
 | 
					    .bdrv_co_get_info               = bdrv_qed_co_get_info,
 | 
				
			||||||
    .bdrv_refresh_limits      = bdrv_qed_refresh_limits,
 | 
					    .bdrv_refresh_limits            = bdrv_qed_refresh_limits,
 | 
				
			||||||
    .bdrv_change_backing_file = bdrv_qed_change_backing_file,
 | 
					    .bdrv_co_change_backing_file    = bdrv_qed_co_change_backing_file,
 | 
				
			||||||
    .bdrv_co_invalidate_cache = bdrv_qed_co_invalidate_cache,
 | 
					    .bdrv_co_invalidate_cache       = bdrv_qed_co_invalidate_cache,
 | 
				
			||||||
    .bdrv_co_check            = bdrv_qed_co_check,
 | 
					    .bdrv_co_check                  = bdrv_qed_co_check,
 | 
				
			||||||
    .bdrv_detach_aio_context  = bdrv_qed_detach_aio_context,
 | 
					    .bdrv_detach_aio_context        = bdrv_qed_detach_aio_context,
 | 
				
			||||||
    .bdrv_attach_aio_context  = bdrv_qed_attach_aio_context,
 | 
					    .bdrv_attach_aio_context        = bdrv_qed_attach_aio_context,
 | 
				
			||||||
    .bdrv_drain_begin         = bdrv_qed_drain_begin,
 | 
					    .bdrv_drain_begin               = bdrv_qed_drain_begin,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void bdrv_qed_init(void)
 | 
					static void bdrv_qed_init(void)
 | 
				
			||||||
 | 
				
			|||||||
@ -185,7 +185,7 @@ enum {
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Header functions
 | 
					 * Header functions
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int qed_write_header_sync(BDRVQEDState *s);
 | 
					int GRAPH_RDLOCK qed_write_header_sync(BDRVQEDState *s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * L2 cache functions
 | 
					 * L2 cache functions
 | 
				
			||||||
 | 
				
			|||||||
@ -95,9 +95,9 @@ end:
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int raw_apply_options(BlockDriverState *bs, BDRVRawState *s,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                             uint64_t offset, bool has_size, uint64_t size,
 | 
					raw_apply_options(BlockDriverState *bs, BDRVRawState *s, uint64_t offset,
 | 
				
			||||||
                             Error **errp)
 | 
					                  bool has_size, uint64_t size, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int64_t real_size = 0;
 | 
					    int64_t real_size = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -145,6 +145,9 @@ static int raw_reopen_prepare(BDRVReopenState *reopen_state,
 | 
				
			|||||||
    uint64_t offset, size;
 | 
					    uint64_t offset, size;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert(reopen_state != NULL);
 | 
					    assert(reopen_state != NULL);
 | 
				
			||||||
    assert(reopen_state->bs != NULL);
 | 
					    assert(reopen_state->bs != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -279,11 +282,10 @@ fail:
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
 | 
					static int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
                                            bool want_zero, int64_t offset,
 | 
					raw_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset,
 | 
				
			||||||
                                            int64_t bytes, int64_t *pnum,
 | 
					                    int64_t bytes, int64_t *pnum, int64_t *map,
 | 
				
			||||||
                                            int64_t *map,
 | 
					                    BlockDriverState **file)
 | 
				
			||||||
                                            BlockDriverState **file)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVRawState *s = bs->opaque;
 | 
					    BDRVRawState *s = bs->opaque;
 | 
				
			||||||
    *pnum = bytes;
 | 
					    *pnum = bytes;
 | 
				
			||||||
@ -397,7 +399,7 @@ raw_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 | 
				
			|||||||
    return bdrv_co_get_info(bs->file->bs, bdi);
 | 
					    return bdrv_co_get_info(bs->file->bs, bdi);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
 | 
					static void GRAPH_RDLOCK raw_refresh_limits(BlockDriverState *bs, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    bs->bl.has_variable_length = bs->file->bs->bl.has_variable_length;
 | 
					    bs->bl.has_variable_length = bs->file->bs->bl.has_variable_length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -452,7 +454,7 @@ raw_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
 | 
				
			|||||||
    return bdrv_co_ioctl(bs->file->bs, req, buf);
 | 
					    return bdrv_co_ioctl(bs->file->bs, req, buf);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int raw_has_zero_init(BlockDriverState *bs)
 | 
					static int GRAPH_RDLOCK raw_has_zero_init(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return bdrv_has_zero_init(bs->file->bs);
 | 
					    return bdrv_has_zero_init(bs->file->bs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -474,6 +476,8 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    BdrvChildRole file_role;
 | 
					    BdrvChildRole file_role;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = raw_read_options(options, &offset, &has_size, &size, errp);
 | 
					    ret = raw_read_options(options, &offset, &has_size, &size, errp);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
@ -491,6 +495,8 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
 | 
					    bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
 | 
				
			||||||
                    file_role, false, errp);
 | 
					                    file_role, false, errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
    if (!bs->file) {
 | 
					    if (!bs->file) {
 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -505,9 +511,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
                                   BDRV_REQ_ZERO_WRITE;
 | 
					                                   BDRV_REQ_ZERO_WRITE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bs->probed && !bdrv_is_read_only(bs)) {
 | 
					    if (bs->probed && !bdrv_is_read_only(bs)) {
 | 
				
			||||||
        bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
        bdrv_refresh_filename(bs->file->bs);
 | 
					        bdrv_refresh_filename(bs->file->bs);
 | 
				
			||||||
        bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
        fprintf(stderr,
 | 
					        fprintf(stderr,
 | 
				
			||||||
                "WARNING: Image format was not specified for '%s' and probing "
 | 
					                "WARNING: Image format was not specified for '%s' and probing "
 | 
				
			||||||
                "guessed raw.\n"
 | 
					                "guessed raw.\n"
 | 
				
			||||||
@ -543,7 +547,8 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
				
			|||||||
    return 1;
 | 
					    return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int raw_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
 | 
					raw_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVRawState *s = bs->opaque;
 | 
					    BDRVRawState *s = bs->opaque;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
@ -560,7 +565,8 @@ static int raw_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
 | 
					raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVRawState *s = bs->opaque;
 | 
					    BDRVRawState *s = bs->opaque;
 | 
				
			||||||
    if (s->offset || s->has_size) {
 | 
					    if (s->offset || s->has_size) {
 | 
				
			||||||
@ -610,7 +616,7 @@ static const char *const raw_strong_runtime_opts[] = {
 | 
				
			|||||||
    NULL
 | 
					    NULL
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void raw_cancel_in_flight(BlockDriverState *bs)
 | 
					static void GRAPH_RDLOCK raw_cancel_in_flight(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    bdrv_cancel_in_flight(bs->file->bs);
 | 
					    bdrv_cancel_in_flight(bs->file->bs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -311,7 +311,7 @@ static void GRAPH_UNLOCKED
 | 
				
			|||||||
secondary_do_checkpoint(BlockDriverState *bs, Error **errp)
 | 
					secondary_do_checkpoint(BlockDriverState *bs, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVReplicationState *s = bs->opaque;
 | 
					    BDRVReplicationState *s = bs->opaque;
 | 
				
			||||||
    BdrvChild *active_disk = bs->file;
 | 
					    BdrvChild *active_disk;
 | 
				
			||||||
    Error *local_err = NULL;
 | 
					    Error *local_err = NULL;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -328,6 +328,7 @@ secondary_do_checkpoint(BlockDriverState *bs, Error **errp)
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    active_disk = bs->file;
 | 
				
			||||||
    if (!active_disk->bs->drv) {
 | 
					    if (!active_disk->bs->drv) {
 | 
				
			||||||
        error_setg(errp, "Active disk %s is ejected",
 | 
					        error_setg(errp, "Active disk %s is ejected",
 | 
				
			||||||
                   active_disk->bs->node_name);
 | 
					                   active_disk->bs->node_name);
 | 
				
			||||||
@ -363,6 +364,9 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
 | 
				
			|||||||
    BdrvChild *hidden_disk, *secondary_disk;
 | 
					    BdrvChild *hidden_disk, *secondary_disk;
 | 
				
			||||||
    BlockReopenQueue *reopen_queue = NULL;
 | 
					    BlockReopenQueue *reopen_queue = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * s->hidden_disk and s->secondary_disk may not be set yet, as they will
 | 
					     * s->hidden_disk and s->secondary_disk may not be set yet, as they will
 | 
				
			||||||
     * only be set after the children are writable.
 | 
					     * only be set after the children are writable.
 | 
				
			||||||
@ -496,9 +500,11 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
 | 
				
			|||||||
    case REPLICATION_MODE_PRIMARY:
 | 
					    case REPLICATION_MODE_PRIMARY:
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case REPLICATION_MODE_SECONDARY:
 | 
					    case REPLICATION_MODE_SECONDARY:
 | 
				
			||||||
 | 
					        bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
        active_disk = bs->file;
 | 
					        active_disk = bs->file;
 | 
				
			||||||
        if (!active_disk || !active_disk->bs || !active_disk->bs->backing) {
 | 
					        if (!active_disk || !active_disk->bs || !active_disk->bs->backing) {
 | 
				
			||||||
            error_setg(errp, "Active disk doesn't have backing file");
 | 
					            error_setg(errp, "Active disk doesn't have backing file");
 | 
				
			||||||
 | 
					            bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
            aio_context_release(aio_context);
 | 
					            aio_context_release(aio_context);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -506,11 +512,11 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
 | 
				
			|||||||
        hidden_disk = active_disk->bs->backing;
 | 
					        hidden_disk = active_disk->bs->backing;
 | 
				
			||||||
        if (!hidden_disk->bs || !hidden_disk->bs->backing) {
 | 
					        if (!hidden_disk->bs || !hidden_disk->bs->backing) {
 | 
				
			||||||
            error_setg(errp, "Hidden disk doesn't have backing file");
 | 
					            error_setg(errp, "Hidden disk doesn't have backing file");
 | 
				
			||||||
 | 
					            bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
            aio_context_release(aio_context);
 | 
					            aio_context_release(aio_context);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
        secondary_disk = hidden_disk->bs->backing;
 | 
					        secondary_disk = hidden_disk->bs->backing;
 | 
				
			||||||
        if (!secondary_disk->bs || !bdrv_has_blk(secondary_disk->bs)) {
 | 
					        if (!secondary_disk->bs || !bdrv_has_blk(secondary_disk->bs)) {
 | 
				
			||||||
            error_setg(errp, "The secondary disk doesn't have block backend");
 | 
					            error_setg(errp, "The secondary disk doesn't have block backend");
 | 
				
			||||||
@ -750,11 +756,13 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
        s->stage = BLOCK_REPLICATION_FAILOVER;
 | 
					        s->stage = BLOCK_REPLICATION_FAILOVER;
 | 
				
			||||||
        s->commit_job = commit_active_start(
 | 
					        s->commit_job = commit_active_start(
 | 
				
			||||||
                            NULL, bs->file->bs, s->secondary_disk->bs,
 | 
					                            NULL, bs->file->bs, s->secondary_disk->bs,
 | 
				
			||||||
                            JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT,
 | 
					                            JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT,
 | 
				
			||||||
                            NULL, replication_done, bs, true, errp);
 | 
					                            NULL, replication_done, bs, true, errp);
 | 
				
			||||||
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        aio_context_release(aio_context);
 | 
					        aio_context_release(aio_context);
 | 
				
			||||||
 | 
				
			|||||||
@ -73,7 +73,7 @@ snapshot_access_co_pwritev_part(BlockDriverState *bs,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void snapshot_access_refresh_filename(BlockDriverState *bs)
 | 
					static void GRAPH_RDLOCK snapshot_access_refresh_filename(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
 | 
					    pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
 | 
				
			||||||
            bs->file->bs->filename);
 | 
					            bs->file->bs->filename);
 | 
				
			||||||
@ -85,6 +85,9 @@ static int snapshot_access_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
 | 
					    bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
 | 
				
			||||||
                    BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
 | 
					                    BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
 | 
				
			||||||
                    false, errp);
 | 
					                    false, errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!bs->file) {
 | 
					    if (!bs->file) {
 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -53,13 +53,20 @@ static int coroutine_fn stream_populate(BlockBackend *blk,
 | 
				
			|||||||
static int stream_prepare(Job *job)
 | 
					static int stream_prepare(Job *job)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
 | 
					    StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
 | 
				
			||||||
    BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
 | 
					    BlockDriverState *unfiltered_bs;
 | 
				
			||||||
    BlockDriverState *unfiltered_bs_cow = bdrv_cow_bs(unfiltered_bs);
 | 
					    BlockDriverState *unfiltered_bs_cow;
 | 
				
			||||||
    BlockDriverState *base;
 | 
					    BlockDriverState *base;
 | 
				
			||||||
    BlockDriverState *unfiltered_base;
 | 
					    BlockDriverState *unfiltered_base;
 | 
				
			||||||
    Error *local_err = NULL;
 | 
					    Error *local_err = NULL;
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					    unfiltered_bs = bdrv_skip_filters(s->target_bs);
 | 
				
			||||||
 | 
					    unfiltered_bs_cow = bdrv_cow_bs(unfiltered_bs);
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* We should drop filter at this point, as filter hold the backing chain */
 | 
					    /* We should drop filter at this point, as filter hold the backing chain */
 | 
				
			||||||
    bdrv_cor_filter_drop(s->cor_filter_bs);
 | 
					    bdrv_cor_filter_drop(s->cor_filter_bs);
 | 
				
			||||||
    s->cor_filter_bs = NULL;
 | 
					    s->cor_filter_bs = NULL;
 | 
				
			||||||
@ -78,10 +85,12 @@ static int stream_prepare(Job *job)
 | 
				
			|||||||
        bdrv_drained_begin(unfiltered_bs_cow);
 | 
					        bdrv_drained_begin(unfiltered_bs_cow);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    base = bdrv_filter_or_cow_bs(s->above_base);
 | 
					    base = bdrv_filter_or_cow_bs(s->above_base);
 | 
				
			||||||
    unfiltered_base = bdrv_skip_filters(base);
 | 
					    unfiltered_base = bdrv_skip_filters(base);
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bdrv_cow_child(unfiltered_bs)) {
 | 
					    if (unfiltered_bs_cow) {
 | 
				
			||||||
        const char *base_id = NULL, *base_fmt = NULL;
 | 
					        const char *base_id = NULL, *base_fmt = NULL;
 | 
				
			||||||
        if (unfiltered_base) {
 | 
					        if (unfiltered_base) {
 | 
				
			||||||
            base_id = s->backing_file_str ?: unfiltered_base->filename;
 | 
					            base_id = s->backing_file_str ?: unfiltered_base->filename;
 | 
				
			||||||
@ -90,7 +99,9 @@ static int stream_prepare(Job *job)
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bdrv_graph_wrlock(base);
 | 
				
			||||||
        bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err);
 | 
					        bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err);
 | 
				
			||||||
 | 
					        bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
         * This call will do I/O, so the graph can change again from here on.
 | 
					         * This call will do I/O, so the graph can change again from here on.
 | 
				
			||||||
@ -138,18 +149,19 @@ static void stream_clean(Job *job)
 | 
				
			|||||||
static int coroutine_fn stream_run(Job *job, Error **errp)
 | 
					static int coroutine_fn stream_run(Job *job, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
 | 
					    StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
 | 
				
			||||||
    BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
 | 
					    BlockDriverState *unfiltered_bs;
 | 
				
			||||||
    int64_t len;
 | 
					    int64_t len;
 | 
				
			||||||
    int64_t offset = 0;
 | 
					    int64_t offset = 0;
 | 
				
			||||||
    int error = 0;
 | 
					    int error = 0;
 | 
				
			||||||
    int64_t n = 0; /* bytes */
 | 
					    int64_t n = 0; /* bytes */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (unfiltered_bs == s->base_overlay) {
 | 
					 | 
				
			||||||
        /* Nothing to stream */
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    WITH_GRAPH_RDLOCK_GUARD() {
 | 
					    WITH_GRAPH_RDLOCK_GUARD() {
 | 
				
			||||||
 | 
					        unfiltered_bs = bdrv_skip_filters(s->target_bs);
 | 
				
			||||||
 | 
					        if (unfiltered_bs == s->base_overlay) {
 | 
				
			||||||
 | 
					            /* Nothing to stream */
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        len = bdrv_co_getlength(s->target_bs);
 | 
					        len = bdrv_co_getlength(s->target_bs);
 | 
				
			||||||
        if (len < 0) {
 | 
					        if (len < 0) {
 | 
				
			||||||
            return len;
 | 
					            return len;
 | 
				
			||||||
@ -256,6 +268,8 @@ void stream_start(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
    assert(!(base && bottom));
 | 
					    assert(!(base && bottom));
 | 
				
			||||||
    assert(!(backing_file_str && bottom));
 | 
					    assert(!(backing_file_str && bottom));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bottom) {
 | 
					    if (bottom) {
 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
         * New simple interface. The code is written in terms of old interface
 | 
					         * New simple interface. The code is written in terms of old interface
 | 
				
			||||||
@ -272,7 +286,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
        if (!base_overlay) {
 | 
					        if (!base_overlay) {
 | 
				
			||||||
            error_setg(errp, "'%s' is not in the backing chain of '%s'",
 | 
					            error_setg(errp, "'%s' is not in the backing chain of '%s'",
 | 
				
			||||||
                       base->node_name, bs->node_name);
 | 
					                       base->node_name, bs->node_name);
 | 
				
			||||||
            return;
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
@ -294,7 +308,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
    if (bs_read_only) {
 | 
					    if (bs_read_only) {
 | 
				
			||||||
        /* Hold the chain during reopen */
 | 
					        /* Hold the chain during reopen */
 | 
				
			||||||
        if (bdrv_freeze_backing_chain(bs, above_base, errp) < 0) {
 | 
					        if (bdrv_freeze_backing_chain(bs, above_base, errp) < 0) {
 | 
				
			||||||
            return;
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ret = bdrv_reopen_set_read_only(bs, false, errp);
 | 
					        ret = bdrv_reopen_set_read_only(bs, false, errp);
 | 
				
			||||||
@ -303,10 +317,12 @@ void stream_start(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
        bdrv_unfreeze_backing_chain(bs, above_base);
 | 
					        bdrv_unfreeze_backing_chain(bs, above_base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (ret < 0) {
 | 
					        if (ret < 0) {
 | 
				
			||||||
            return;
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    opts = qdict_new();
 | 
					    opts = qdict_new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qdict_put_str(opts, "driver", "copy-on-read");
 | 
					    qdict_put_str(opts, "driver", "copy-on-read");
 | 
				
			||||||
@ -350,8 +366,10 @@ void stream_start(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
     * already have our own plans. Also don't allow resize as the image size is
 | 
					     * already have our own plans. Also don't allow resize as the image size is
 | 
				
			||||||
     * queried only at the job start and then cached.
 | 
					     * queried only at the job start and then cached.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(bs);
 | 
				
			||||||
    if (block_job_add_bdrv(&s->common, "active node", bs, 0,
 | 
					    if (block_job_add_bdrv(&s->common, "active node", bs, 0,
 | 
				
			||||||
                           basic_flags | BLK_PERM_WRITE, errp)) {
 | 
					                           basic_flags | BLK_PERM_WRITE, errp)) {
 | 
				
			||||||
 | 
					        bdrv_graph_wrunlock();
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -371,9 +389,11 @@ void stream_start(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
        ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
 | 
					        ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
 | 
				
			||||||
                                 basic_flags, errp);
 | 
					                                 basic_flags, errp);
 | 
				
			||||||
        if (ret < 0) {
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            bdrv_graph_wrunlock();
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->base_overlay = base_overlay;
 | 
					    s->base_overlay = base_overlay;
 | 
				
			||||||
    s->above_base = above_base;
 | 
					    s->above_base = above_base;
 | 
				
			||||||
@ -397,4 +417,8 @@ fail:
 | 
				
			|||||||
    if (bs_read_only) {
 | 
					    if (bs_read_only) {
 | 
				
			||||||
        bdrv_reopen_set_read_only(bs, true, NULL);
 | 
					        bdrv_reopen_set_read_only(bs, true, NULL);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_rdlock:
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -84,6 +84,9 @@ static int throttle_open(BlockDriverState *bs, QDict *options,
 | 
				
			|||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bs->supported_write_flags = bs->file->bs->supported_write_flags |
 | 
					    bs->supported_write_flags = bs->file->bs->supported_write_flags |
 | 
				
			||||||
                                BDRV_REQ_WRITE_UNCHANGED;
 | 
					                                BDRV_REQ_WRITE_UNCHANGED;
 | 
				
			||||||
    bs->supported_zero_flags = bs->file->bs->supported_zero_flags |
 | 
					    bs->supported_zero_flags = bs->file->bs->supported_zero_flags |
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										15
									
								
								block/vdi.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								block/vdi.c
									
									
									
									
									
								
							@ -383,6 +383,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    logout("\n");
 | 
					    logout("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0);
 | 
					    ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0);
 | 
				
			||||||
@ -492,11 +494,9 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Disable migration when vdi images are used */
 | 
					    /* Disable migration when vdi images are used */
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
    error_setg(&s->migration_blocker, "The vdi format used by node '%s' "
 | 
					    error_setg(&s->migration_blocker, "The vdi format used by node '%s' "
 | 
				
			||||||
               "does not support live migration",
 | 
					               "does not support live migration",
 | 
				
			||||||
               bdrv_get_device_or_node_name(bs));
 | 
					               bdrv_get_device_or_node_name(bs));
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
 | 
					    ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
@ -520,11 +520,10 @@ static int vdi_reopen_prepare(BDRVReopenState *state,
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_fn vdi_co_block_status(BlockDriverState *bs,
 | 
					static int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
                                            bool want_zero,
 | 
					vdi_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset,
 | 
				
			||||||
                                            int64_t offset, int64_t bytes,
 | 
					                    int64_t bytes, int64_t *pnum, int64_t *map,
 | 
				
			||||||
                                            int64_t *pnum, int64_t *map,
 | 
					                    BlockDriverState **file)
 | 
				
			||||||
                                            BlockDriverState **file)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
 | 
					    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
 | 
				
			||||||
    size_t bmap_index = offset / s->block_size;
 | 
					    size_t bmap_index = offset / s->block_size;
 | 
				
			||||||
@ -990,7 +989,7 @@ static void vdi_close(BlockDriverState *bs)
 | 
				
			|||||||
    migrate_del_blocker(&s->migration_blocker);
 | 
					    migrate_del_blocker(&s->migration_blocker);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vdi_has_zero_init(BlockDriverState *bs)
 | 
					static int GRAPH_RDLOCK vdi_has_zero_init(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVVdiState *s = bs->opaque;
 | 
					    BDRVVdiState *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -55,8 +55,9 @@ static const MSGUID zero_guid = { 0 };
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Allow peeking at the hdr entry at the beginning of the current
 | 
					/* Allow peeking at the hdr entry at the beginning of the current
 | 
				
			||||||
 * read index, without advancing the read index */
 | 
					 * read index, without advancing the read index */
 | 
				
			||||||
static int vhdx_log_peek_hdr(BlockDriverState *bs, VHDXLogEntries *log,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                             VHDXLogEntryHeader *hdr)
 | 
					vhdx_log_peek_hdr(BlockDriverState *bs, VHDXLogEntries *log,
 | 
				
			||||||
 | 
					                  VHDXLogEntryHeader *hdr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
    uint64_t offset;
 | 
					    uint64_t offset;
 | 
				
			||||||
@ -107,7 +108,7 @@ static int vhdx_log_inc_idx(uint32_t idx, uint64_t length)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Reset the log to empty */
 | 
					/* Reset the log to empty */
 | 
				
			||||||
static void vhdx_log_reset(BlockDriverState *bs, BDRVVHDXState *s)
 | 
					static void GRAPH_RDLOCK vhdx_log_reset(BlockDriverState *bs, BDRVVHDXState *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    MSGUID guid = { 0 };
 | 
					    MSGUID guid = { 0 };
 | 
				
			||||||
    s->log.read = s->log.write = 0;
 | 
					    s->log.read = s->log.write = 0;
 | 
				
			||||||
@ -127,9 +128,10 @@ static void vhdx_log_reset(BlockDriverState *bs, BDRVVHDXState *s)
 | 
				
			|||||||
 * not modified.
 | 
					 * not modified.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * 0 is returned on success, -errno otherwise.  */
 | 
					 * 0 is returned on success, -errno otherwise.  */
 | 
				
			||||||
static int vhdx_log_read_sectors(BlockDriverState *bs, VHDXLogEntries *log,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                                 uint32_t *sectors_read, void *buffer,
 | 
					vhdx_log_read_sectors(BlockDriverState *bs, VHDXLogEntries *log,
 | 
				
			||||||
                                 uint32_t num_sectors, bool peek)
 | 
					                      uint32_t *sectors_read, void *buffer,
 | 
				
			||||||
 | 
					                      uint32_t num_sectors, bool peek)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
    uint64_t offset;
 | 
					    uint64_t offset;
 | 
				
			||||||
@ -333,9 +335,9 @@ static int vhdx_compute_desc_sectors(uint32_t desc_cnt)
 | 
				
			|||||||
 * will allocate all the space for buffer, which must be NULL when
 | 
					 * will allocate all the space for buffer, which must be NULL when
 | 
				
			||||||
 * passed into this function. Each descriptor will also be validated,
 | 
					 * passed into this function. Each descriptor will also be validated,
 | 
				
			||||||
 * and error returned if any are invalid. */
 | 
					 * and error returned if any are invalid. */
 | 
				
			||||||
static int vhdx_log_read_desc(BlockDriverState *bs, BDRVVHDXState *s,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                              VHDXLogEntries *log, VHDXLogDescEntries **buffer,
 | 
					vhdx_log_read_desc(BlockDriverState *bs, BDRVVHDXState *s, VHDXLogEntries *log,
 | 
				
			||||||
                              bool convert_endian)
 | 
					                   VHDXLogDescEntries **buffer, bool convert_endian)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
    uint32_t desc_sectors;
 | 
					    uint32_t desc_sectors;
 | 
				
			||||||
@ -412,8 +414,9 @@ exit:
 | 
				
			|||||||
 * For a zero descriptor, it may describe multiple sectors to fill with zeroes.
 | 
					 * For a zero descriptor, it may describe multiple sectors to fill with zeroes.
 | 
				
			||||||
 * In this case, it should be noted that zeroes are written to disk, and the
 | 
					 * In this case, it should be noted that zeroes are written to disk, and the
 | 
				
			||||||
 * image file is not extended as a sparse file.  */
 | 
					 * image file is not extended as a sparse file.  */
 | 
				
			||||||
static int vhdx_log_flush_desc(BlockDriverState *bs, VHDXLogDescriptor *desc,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                               VHDXLogDataSector *data)
 | 
					vhdx_log_flush_desc(BlockDriverState *bs, VHDXLogDescriptor *desc,
 | 
				
			||||||
 | 
					                    VHDXLogDataSector *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
    uint64_t seq, file_offset;
 | 
					    uint64_t seq, file_offset;
 | 
				
			||||||
@ -484,8 +487,8 @@ exit:
 | 
				
			|||||||
 * file, and then set the log to 'empty' status once complete.
 | 
					 * file, and then set the log to 'empty' status once complete.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The log entries should be validate prior to flushing */
 | 
					 * The log entries should be validate prior to flushing */
 | 
				
			||||||
static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                          VHDXLogSequence *logs)
 | 
					vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s, VHDXLogSequence *logs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
@ -584,9 +587,10 @@ exit:
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vhdx_validate_log_entry(BlockDriverState *bs, BDRVVHDXState *s,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                                   VHDXLogEntries *log, uint64_t seq,
 | 
					vhdx_validate_log_entry(BlockDriverState *bs, BDRVVHDXState *s,
 | 
				
			||||||
                                   bool *valid, VHDXLogEntryHeader *entry)
 | 
					                        VHDXLogEntries *log, uint64_t seq,
 | 
				
			||||||
 | 
					                        bool *valid, VHDXLogEntryHeader *entry)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
    VHDXLogEntryHeader hdr;
 | 
					    VHDXLogEntryHeader hdr;
 | 
				
			||||||
@ -663,8 +667,8 @@ free_and_exit:
 | 
				
			|||||||
/* Search through the log circular buffer, and find the valid, active
 | 
					/* Search through the log circular buffer, and find the valid, active
 | 
				
			||||||
 * log sequence, if any exists
 | 
					 * log sequence, if any exists
 | 
				
			||||||
 * */
 | 
					 * */
 | 
				
			||||||
static int vhdx_log_search(BlockDriverState *bs, BDRVVHDXState *s,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                           VHDXLogSequence *logs)
 | 
					vhdx_log_search(BlockDriverState *bs, BDRVVHDXState *s, VHDXLogSequence *logs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
    uint32_t tail;
 | 
					    uint32_t tail;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										37
									
								
								block/vhdx.c
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								block/vhdx.c
									
									
									
									
									
								
							@ -353,8 +353,9 @@ exit:
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *  - non-current header is updated with largest sequence number
 | 
					 *  - non-current header is updated with largest sequence number
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s,
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
                              bool generate_data_write_guid, MSGUID *log_guid)
 | 
					vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s,
 | 
				
			||||||
 | 
					                   bool generate_data_write_guid, MSGUID *log_guid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
    int hdr_idx = 0;
 | 
					    int hdr_idx = 0;
 | 
				
			||||||
@ -416,8 +417,8 @@ int vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* opens the specified header block from the VHDX file header section */
 | 
					/* opens the specified header block from the VHDX file header section */
 | 
				
			||||||
static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
 | 
					static void GRAPH_RDLOCK
 | 
				
			||||||
                              Error **errp)
 | 
					vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
    VHDXHeader *header1;
 | 
					    VHDXHeader *header1;
 | 
				
			||||||
@ -517,7 +518,8 @@ exit:
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vhdx_open_region_tables(BlockDriverState *bs, BDRVVHDXState *s)
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
 | 
					vhdx_open_region_tables(BlockDriverState *bs, BDRVVHDXState *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
    uint8_t *buffer;
 | 
					    uint8_t *buffer;
 | 
				
			||||||
@ -634,7 +636,8 @@ fail:
 | 
				
			|||||||
 * Also, if the File Parameters indicate this is a differencing file,
 | 
					 * Also, if the File Parameters indicate this is a differencing file,
 | 
				
			||||||
 * we must also look for the Parent Locator metadata item.
 | 
					 * we must also look for the Parent Locator metadata item.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
 | 
					vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
    uint8_t *buffer;
 | 
					    uint8_t *buffer;
 | 
				
			||||||
@ -885,7 +888,8 @@ static void vhdx_calc_bat_entries(BDRVVHDXState *s)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vhdx_check_bat_entries(BlockDriverState *bs, int *errcnt)
 | 
					static int coroutine_mixed_fn GRAPH_RDLOCK
 | 
				
			||||||
 | 
					vhdx_check_bat_entries(BlockDriverState *bs, int *errcnt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVVHDXState *s = bs->opaque;
 | 
					    BDRVVHDXState *s = bs->opaque;
 | 
				
			||||||
    int64_t image_file_size = bdrv_getlength(bs->file->bs);
 | 
					    int64_t image_file_size = bdrv_getlength(bs->file->bs);
 | 
				
			||||||
@ -1695,7 +1699,7 @@ exit:
 | 
				
			|||||||
 *  Fixed images: default state of the BAT is fully populated, with
 | 
					 *  Fixed images: default state of the BAT is fully populated, with
 | 
				
			||||||
 *                file offsets and state PAYLOAD_BLOCK_FULLY_PRESENT.
 | 
					 *                file offsets and state PAYLOAD_BLOCK_FULLY_PRESENT.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int coroutine_fn
 | 
					static int coroutine_fn GRAPH_UNLOCKED
 | 
				
			||||||
vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
 | 
					vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
 | 
				
			||||||
                uint64_t image_size, VHDXImageType type,
 | 
					                uint64_t image_size, VHDXImageType type,
 | 
				
			||||||
                bool use_zero_blocks, uint64_t file_offset,
 | 
					                bool use_zero_blocks, uint64_t file_offset,
 | 
				
			||||||
@ -1708,6 +1712,7 @@ vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
 | 
				
			|||||||
    uint64_t unused;
 | 
					    uint64_t unused;
 | 
				
			||||||
    int block_state;
 | 
					    int block_state;
 | 
				
			||||||
    VHDXSectorInfo sinfo;
 | 
					    VHDXSectorInfo sinfo;
 | 
				
			||||||
 | 
					    bool has_zero_init;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert(s->bat == NULL);
 | 
					    assert(s->bat == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1737,9 +1742,13 @@ vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
 | 
				
			|||||||
        goto exit;
 | 
					        goto exit;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_co_rdlock();
 | 
				
			||||||
 | 
					    has_zero_init = bdrv_has_zero_init(blk_bs(blk));
 | 
				
			||||||
 | 
					    bdrv_graph_co_rdunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (type == VHDX_TYPE_FIXED ||
 | 
					    if (type == VHDX_TYPE_FIXED ||
 | 
				
			||||||
                use_zero_blocks ||
 | 
					                use_zero_blocks ||
 | 
				
			||||||
                bdrv_has_zero_init(blk_bs(blk)) == 0) {
 | 
					                has_zero_init == 0) {
 | 
				
			||||||
        /* for a fixed file, the default BAT entry is not zero */
 | 
					        /* for a fixed file, the default BAT entry is not zero */
 | 
				
			||||||
        s->bat = g_try_malloc0(length);
 | 
					        s->bat = g_try_malloc0(length);
 | 
				
			||||||
        if (length && s->bat == NULL) {
 | 
					        if (length && s->bat == NULL) {
 | 
				
			||||||
@ -1782,7 +1791,7 @@ exit:
 | 
				
			|||||||
 * to create the BAT itself, we will also cause the BAT to be
 | 
					 * to create the BAT itself, we will also cause the BAT to be
 | 
				
			||||||
 * created.
 | 
					 * created.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int coroutine_fn
 | 
					static int coroutine_fn GRAPH_UNLOCKED
 | 
				
			||||||
vhdx_create_new_region_table(BlockBackend *blk, uint64_t image_size,
 | 
					vhdx_create_new_region_table(BlockBackend *blk, uint64_t image_size,
 | 
				
			||||||
                             uint32_t block_size, uint32_t sector_size,
 | 
					                             uint32_t block_size, uint32_t sector_size,
 | 
				
			||||||
                             uint32_t log_size, bool use_zero_blocks,
 | 
					                             uint32_t log_size, bool use_zero_blocks,
 | 
				
			||||||
@ -2158,9 +2167,9 @@ fail:
 | 
				
			|||||||
 * r/w and any log has already been replayed, so there is nothing (currently)
 | 
					 * r/w and any log has already been replayed, so there is nothing (currently)
 | 
				
			||||||
 * for us to do here
 | 
					 * for us to do here
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int coroutine_fn vhdx_co_check(BlockDriverState *bs,
 | 
					static int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
                                      BdrvCheckResult *result,
 | 
					vhdx_co_check(BlockDriverState *bs, BdrvCheckResult *result,
 | 
				
			||||||
                                      BdrvCheckMode fix)
 | 
					              BdrvCheckMode fix)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVVHDXState *s = bs->opaque;
 | 
					    BDRVVHDXState *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2173,7 +2182,7 @@ static int coroutine_fn vhdx_co_check(BlockDriverState *bs,
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vhdx_has_zero_init(BlockDriverState *bs)
 | 
					static int GRAPH_RDLOCK vhdx_has_zero_init(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVVHDXState *s = bs->opaque;
 | 
					    BDRVVHDXState *s = bs->opaque;
 | 
				
			||||||
    int state;
 | 
					    int state;
 | 
				
			||||||
 | 
				
			|||||||
@ -401,8 +401,9 @@ typedef struct BDRVVHDXState {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void vhdx_guid_generate(MSGUID *guid);
 | 
					void vhdx_guid_generate(MSGUID *guid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s, bool rw,
 | 
					int GRAPH_RDLOCK
 | 
				
			||||||
                        MSGUID *log_guid);
 | 
					vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s, bool rw,
 | 
				
			||||||
 | 
					                    MSGUID *log_guid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset);
 | 
					uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset);
 | 
				
			||||||
uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size,
 | 
					uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size,
 | 
				
			||||||
@ -448,6 +449,8 @@ void vhdx_metadata_header_le_import(VHDXMetadataTableHeader *hdr);
 | 
				
			|||||||
void vhdx_metadata_header_le_export(VHDXMetadataTableHeader *hdr);
 | 
					void vhdx_metadata_header_le_export(VHDXMetadataTableHeader *hdr);
 | 
				
			||||||
void vhdx_metadata_entry_le_import(VHDXMetadataTableEntry *e);
 | 
					void vhdx_metadata_entry_le_import(VHDXMetadataTableEntry *e);
 | 
				
			||||||
void vhdx_metadata_entry_le_export(VHDXMetadataTableEntry *e);
 | 
					void vhdx_metadata_entry_le_export(VHDXMetadataTableEntry *e);
 | 
				
			||||||
int vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s);
 | 
					
 | 
				
			||||||
 | 
					int GRAPH_RDLOCK
 | 
				
			||||||
 | 
					vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										23
									
								
								block/vmdk.c
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								block/vmdk.c
									
									
									
									
									
								
							@ -300,7 +300,8 @@ static void vmdk_free_last_extent(BlockDriverState *bs)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Return -ve errno, or 0 on success and write CID into *pcid. */
 | 
					/* Return -ve errno, or 0 on success and write CID into *pcid. */
 | 
				
			||||||
static int vmdk_read_cid(BlockDriverState *bs, int parent, uint32_t *pcid)
 | 
					static int GRAPH_RDLOCK
 | 
				
			||||||
 | 
					vmdk_read_cid(BlockDriverState *bs, int parent, uint32_t *pcid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *desc;
 | 
					    char *desc;
 | 
				
			||||||
    uint32_t cid;
 | 
					    uint32_t cid;
 | 
				
			||||||
@ -380,7 +381,7 @@ out:
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_fn vmdk_is_cid_valid(BlockDriverState *bs)
 | 
					static int coroutine_fn GRAPH_RDLOCK vmdk_is_cid_valid(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVVmdkState *s = bs->opaque;
 | 
					    BDRVVmdkState *s = bs->opaque;
 | 
				
			||||||
    uint32_t cur_pcid;
 | 
					    uint32_t cur_pcid;
 | 
				
			||||||
@ -415,6 +416,9 @@ static int vmdk_reopen_prepare(BDRVReopenState *state,
 | 
				
			|||||||
    BDRVVmdkReopenState *rs;
 | 
					    BDRVVmdkReopenState *rs;
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert(state != NULL);
 | 
					    assert(state != NULL);
 | 
				
			||||||
    assert(state->bs != NULL);
 | 
					    assert(state->bs != NULL);
 | 
				
			||||||
    assert(state->opaque == NULL);
 | 
					    assert(state->opaque == NULL);
 | 
				
			||||||
@ -451,6 +455,9 @@ static void vmdk_reopen_commit(BDRVReopenState *state)
 | 
				
			|||||||
    BDRVVmdkReopenState *rs = state->opaque;
 | 
					    BDRVVmdkReopenState *rs = state->opaque;
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < s->num_extents; i++) {
 | 
					    for (i = 0; i < s->num_extents; i++) {
 | 
				
			||||||
        if (rs->extents_using_bs_file[i]) {
 | 
					        if (rs->extents_using_bs_file[i]) {
 | 
				
			||||||
            s->extents[i].file = state->bs->file;
 | 
					            s->extents[i].file = state->bs->file;
 | 
				
			||||||
@ -465,7 +472,7 @@ static void vmdk_reopen_abort(BDRVReopenState *state)
 | 
				
			|||||||
    vmdk_reopen_clean(state);
 | 
					    vmdk_reopen_clean(state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vmdk_parent_open(BlockDriverState *bs)
 | 
					static int GRAPH_RDLOCK vmdk_parent_open(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *p_name;
 | 
					    char *p_name;
 | 
				
			||||||
    char *desc;
 | 
					    char *desc;
 | 
				
			||||||
@ -2547,7 +2554,10 @@ vmdk_co_do_create(int64_t size,
 | 
				
			|||||||
            ret = -EINVAL;
 | 
					            ret = -EINVAL;
 | 
				
			||||||
            goto exit;
 | 
					            goto exit;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bdrv_graph_co_rdlock();
 | 
				
			||||||
        ret = vmdk_read_cid(blk_bs(backing), 0, &parent_cid);
 | 
					        ret = vmdk_read_cid(blk_bs(backing), 0, &parent_cid);
 | 
				
			||||||
 | 
					        bdrv_graph_co_rdunlock();
 | 
				
			||||||
        blk_co_unref(backing);
 | 
					        blk_co_unref(backing);
 | 
				
			||||||
        if (ret) {
 | 
					        if (ret) {
 | 
				
			||||||
            error_setg(errp, "Failed to read parent CID");
 | 
					            error_setg(errp, "Failed to read parent CID");
 | 
				
			||||||
@ -2894,7 +2904,7 @@ vmdk_co_get_allocated_file_size(BlockDriverState *bs)
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vmdk_has_zero_init(BlockDriverState *bs)
 | 
					static int GRAPH_RDLOCK vmdk_has_zero_init(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
    BDRVVmdkState *s = bs->opaque;
 | 
					    BDRVVmdkState *s = bs->opaque;
 | 
				
			||||||
@ -3044,8 +3054,9 @@ vmdk_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void vmdk_gather_child_options(BlockDriverState *bs, QDict *target,
 | 
					static void GRAPH_RDLOCK
 | 
				
			||||||
                                      bool backing_overridden)
 | 
					vmdk_gather_child_options(BlockDriverState *bs, QDict *target,
 | 
				
			||||||
 | 
					                          bool backing_overridden)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /* No children but file and backing can be explicitly specified (TODO) */
 | 
					    /* No children but file and backing can be explicitly specified (TODO) */
 | 
				
			||||||
    qdict_put(target, "file",
 | 
					    qdict_put(target, "file",
 | 
				
			||||||
 | 
				
			|||||||
@ -238,6 +238,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort);
 | 
					    opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort);
 | 
				
			||||||
    if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 | 
					    if (!qemu_opts_absorb_qdict(opts, options, errp)) {
 | 
				
			||||||
        ret = -EINVAL;
 | 
					        ret = -EINVAL;
 | 
				
			||||||
@ -446,11 +448,9 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Disable migration when VHD images are used */
 | 
					    /* Disable migration when VHD images are used */
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
    error_setg(&s->migration_blocker, "The vpc format used by node '%s' "
 | 
					    error_setg(&s->migration_blocker, "The vpc format used by node '%s' "
 | 
				
			||||||
               "does not support live migration",
 | 
					               "does not support live migration",
 | 
				
			||||||
               bdrv_get_device_or_node_name(bs));
 | 
					               bdrv_get_device_or_node_name(bs));
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
 | 
					    ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
@ -1170,7 +1170,7 @@ fail:
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vpc_has_zero_init(BlockDriverState *bs)
 | 
					static int GRAPH_RDLOCK vpc_has_zero_init(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVVPCState *s = bs->opaque;
 | 
					    BDRVVPCState *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										72
									
								
								blockdev.c
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								blockdev.c
									
									
									
									
									
								
							@ -1610,7 +1610,12 @@ static void external_snapshot_abort(void *opaque)
 | 
				
			|||||||
                aio_context_acquire(aio_context);
 | 
					                aio_context_acquire(aio_context);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            bdrv_drained_begin(state->new_bs);
 | 
				
			||||||
 | 
					            bdrv_graph_wrlock(state->old_bs);
 | 
				
			||||||
            bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
 | 
					            bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
 | 
				
			||||||
 | 
					            bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					            bdrv_drained_end(state->new_bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
 | 
					            bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            aio_context_release(aio_context);
 | 
					            aio_context_release(aio_context);
 | 
				
			||||||
@ -1710,7 +1715,6 @@ static void drive_backup_action(DriveBackup *backup,
 | 
				
			|||||||
        bdrv_graph_rdunlock_main_loop();
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    flags = bs->open_flags | BDRV_O_RDWR;
 | 
					    flags = bs->open_flags | BDRV_O_RDWR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1735,6 +1739,7 @@ static void drive_backup_action(DriveBackup *backup,
 | 
				
			|||||||
        flags |= BDRV_O_NO_BACKING;
 | 
					        flags |= BDRV_O_NO_BACKING;
 | 
				
			||||||
        set_backing_hd = true;
 | 
					        set_backing_hd = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    size = bdrv_getlength(bs);
 | 
					    size = bdrv_getlength(bs);
 | 
				
			||||||
    if (size < 0) {
 | 
					    if (size < 0) {
 | 
				
			||||||
@ -1746,10 +1751,10 @@ static void drive_backup_action(DriveBackup *backup,
 | 
				
			|||||||
        assert(format);
 | 
					        assert(format);
 | 
				
			||||||
        if (source) {
 | 
					        if (source) {
 | 
				
			||||||
            /* Implicit filters should not appear in the filename */
 | 
					            /* Implicit filters should not appear in the filename */
 | 
				
			||||||
            BlockDriverState *explicit_backing =
 | 
					            BlockDriverState *explicit_backing;
 | 
				
			||||||
                bdrv_skip_implicit_filters(source);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            bdrv_graph_rdlock_main_loop();
 | 
					            bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					            explicit_backing = bdrv_skip_implicit_filters(source);
 | 
				
			||||||
            bdrv_refresh_filename(explicit_backing);
 | 
					            bdrv_refresh_filename(explicit_backing);
 | 
				
			||||||
            bdrv_graph_rdunlock_main_loop();
 | 
					            bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2450,11 +2455,12 @@ void qmp_block_stream(const char *job_id, const char *device,
 | 
				
			|||||||
    aio_context = bdrv_get_aio_context(bs);
 | 
					    aio_context = bdrv_get_aio_context(bs);
 | 
				
			||||||
    aio_context_acquire(aio_context);
 | 
					    aio_context_acquire(aio_context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    if (base) {
 | 
					    if (base) {
 | 
				
			||||||
        base_bs = bdrv_find_backing_image(bs, base);
 | 
					        base_bs = bdrv_find_backing_image(bs, base);
 | 
				
			||||||
        if (base_bs == NULL) {
 | 
					        if (base_bs == NULL) {
 | 
				
			||||||
            error_setg(errp, "Can't find '%s' in the backing chain", base);
 | 
					            error_setg(errp, "Can't find '%s' in the backing chain", base);
 | 
				
			||||||
            goto out;
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        assert(bdrv_get_aio_context(base_bs) == aio_context);
 | 
					        assert(bdrv_get_aio_context(base_bs) == aio_context);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -2462,38 +2468,36 @@ void qmp_block_stream(const char *job_id, const char *device,
 | 
				
			|||||||
    if (base_node) {
 | 
					    if (base_node) {
 | 
				
			||||||
        base_bs = bdrv_lookup_bs(NULL, base_node, errp);
 | 
					        base_bs = bdrv_lookup_bs(NULL, base_node, errp);
 | 
				
			||||||
        if (!base_bs) {
 | 
					        if (!base_bs) {
 | 
				
			||||||
            goto out;
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (bs == base_bs || !bdrv_chain_contains(bs, base_bs)) {
 | 
					        if (bs == base_bs || !bdrv_chain_contains(bs, base_bs)) {
 | 
				
			||||||
            error_setg(errp, "Node '%s' is not a backing image of '%s'",
 | 
					            error_setg(errp, "Node '%s' is not a backing image of '%s'",
 | 
				
			||||||
                       base_node, device);
 | 
					                       base_node, device);
 | 
				
			||||||
            goto out;
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        assert(bdrv_get_aio_context(base_bs) == aio_context);
 | 
					        assert(bdrv_get_aio_context(base_bs) == aio_context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
        bdrv_refresh_filename(base_bs);
 | 
					        bdrv_refresh_filename(base_bs);
 | 
				
			||||||
        bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bottom) {
 | 
					    if (bottom) {
 | 
				
			||||||
        bottom_bs = bdrv_lookup_bs(NULL, bottom, errp);
 | 
					        bottom_bs = bdrv_lookup_bs(NULL, bottom, errp);
 | 
				
			||||||
        if (!bottom_bs) {
 | 
					        if (!bottom_bs) {
 | 
				
			||||||
            goto out;
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (!bottom_bs->drv) {
 | 
					        if (!bottom_bs->drv) {
 | 
				
			||||||
            error_setg(errp, "Node '%s' is not open", bottom);
 | 
					            error_setg(errp, "Node '%s' is not open", bottom);
 | 
				
			||||||
            goto out;
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (bottom_bs->drv->is_filter) {
 | 
					        if (bottom_bs->drv->is_filter) {
 | 
				
			||||||
            error_setg(errp, "Node '%s' is a filter, use a non-filter node "
 | 
					            error_setg(errp, "Node '%s' is a filter, use a non-filter node "
 | 
				
			||||||
                       "as 'bottom'", bottom);
 | 
					                       "as 'bottom'", bottom);
 | 
				
			||||||
            goto out;
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (!bdrv_chain_contains(bs, bottom_bs)) {
 | 
					        if (!bdrv_chain_contains(bs, bottom_bs)) {
 | 
				
			||||||
            error_setg(errp, "Node '%s' is not in a chain starting from '%s'",
 | 
					            error_setg(errp, "Node '%s' is not in a chain starting from '%s'",
 | 
				
			||||||
                       bottom, device);
 | 
					                       bottom, device);
 | 
				
			||||||
            goto out;
 | 
					            goto out_rdlock;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        assert(bdrv_get_aio_context(bottom_bs) == aio_context);
 | 
					        assert(bdrv_get_aio_context(bottom_bs) == aio_context);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -2502,13 +2506,11 @@ void qmp_block_stream(const char *job_id, const char *device,
 | 
				
			|||||||
     * Check for op blockers in the whole chain between bs and base (or bottom)
 | 
					     * Check for op blockers in the whole chain between bs and base (or bottom)
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    iter_end = bottom ? bdrv_filter_or_cow_bs(bottom_bs) : base_bs;
 | 
					    iter_end = bottom ? bdrv_filter_or_cow_bs(bottom_bs) : base_bs;
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
    for (iter = bs; iter && iter != iter_end;
 | 
					    for (iter = bs; iter && iter != iter_end;
 | 
				
			||||||
         iter = bdrv_filter_or_cow_bs(iter))
 | 
					         iter = bdrv_filter_or_cow_bs(iter))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (bdrv_op_is_blocked(iter, BLOCK_OP_TYPE_STREAM, errp)) {
 | 
					        if (bdrv_op_is_blocked(iter, BLOCK_OP_TYPE_STREAM, errp)) {
 | 
				
			||||||
            bdrv_graph_rdunlock_main_loop();
 | 
					            goto out_rdlock;
 | 
				
			||||||
            goto out;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
@ -2540,6 +2542,11 @@ void qmp_block_stream(const char *job_id, const char *device,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
    aio_context_release(aio_context);
 | 
					    aio_context_release(aio_context);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_rdlock:
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					    aio_context_release(aio_context);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void qmp_block_commit(const char *job_id, const char *device,
 | 
					void qmp_block_commit(const char *job_id, const char *device,
 | 
				
			||||||
@ -3054,7 +3061,6 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
 | 
				
			|||||||
        bdrv_graph_rdunlock_main_loop();
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    aio_context = bdrv_get_aio_context(bs);
 | 
					    aio_context = bdrv_get_aio_context(bs);
 | 
				
			||||||
    aio_context_acquire(aio_context);
 | 
					    aio_context_acquire(aio_context);
 | 
				
			||||||
@ -3076,6 +3082,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
 | 
				
			|||||||
    if (arg->sync == MIRROR_SYNC_MODE_NONE) {
 | 
					    if (arg->sync == MIRROR_SYNC_MODE_NONE) {
 | 
				
			||||||
        target_backing_bs = bs;
 | 
					        target_backing_bs = bs;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    size = bdrv_getlength(bs);
 | 
					    size = bdrv_getlength(bs);
 | 
				
			||||||
    if (size < 0) {
 | 
					    if (size < 0) {
 | 
				
			||||||
@ -3108,16 +3115,18 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
 | 
				
			|||||||
        bdrv_img_create(arg->target, format,
 | 
					        bdrv_img_create(arg->target, format,
 | 
				
			||||||
                        NULL, NULL, NULL, size, flags, false, &local_err);
 | 
					                        NULL, NULL, NULL, size, flags, false, &local_err);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        /* Implicit filters should not appear in the filename */
 | 
					        BlockDriverState *explicit_backing;
 | 
				
			||||||
        BlockDriverState *explicit_backing =
 | 
					 | 
				
			||||||
            bdrv_skip_implicit_filters(target_backing_bs);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        switch (arg->mode) {
 | 
					        switch (arg->mode) {
 | 
				
			||||||
        case NEW_IMAGE_MODE_EXISTING:
 | 
					        case NEW_IMAGE_MODE_EXISTING:
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
 | 
					        case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
 | 
				
			||||||
            /* create new image with backing file */
 | 
					            /*
 | 
				
			||||||
 | 
					             * Create new image with backing file.
 | 
				
			||||||
 | 
					             * Implicit filters should not appear in the filename.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
            bdrv_graph_rdlock_main_loop();
 | 
					            bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					            explicit_backing = bdrv_skip_implicit_filters(target_backing_bs);
 | 
				
			||||||
            bdrv_refresh_filename(explicit_backing);
 | 
					            bdrv_refresh_filename(explicit_backing);
 | 
				
			||||||
            bdrv_graph_rdunlock_main_loop();
 | 
					            bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3156,9 +3165,11 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    zero_target = (arg->sync == MIRROR_SYNC_MODE_FULL &&
 | 
					    zero_target = (arg->sync == MIRROR_SYNC_MODE_FULL &&
 | 
				
			||||||
                   (arg->mode == NEW_IMAGE_MODE_EXISTING ||
 | 
					                   (arg->mode == NEW_IMAGE_MODE_EXISTING ||
 | 
				
			||||||
                    !bdrv_has_zero_init(target_bs)));
 | 
					                    !bdrv_has_zero_init(target_bs)));
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Honor bdrv_try_change_aio_context() context acquisition requirements. */
 | 
					    /* Honor bdrv_try_change_aio_context() context acquisition requirements. */
 | 
				
			||||||
@ -3435,38 +3446,38 @@ void qmp_change_backing_file(const char *device,
 | 
				
			|||||||
    aio_context = bdrv_get_aio_context(bs);
 | 
					    aio_context = bdrv_get_aio_context(bs);
 | 
				
			||||||
    aio_context_acquire(aio_context);
 | 
					    aio_context_acquire(aio_context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err);
 | 
					    image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err);
 | 
				
			||||||
    if (local_err) {
 | 
					    if (local_err) {
 | 
				
			||||||
        error_propagate(errp, local_err);
 | 
					        error_propagate(errp, local_err);
 | 
				
			||||||
        goto out;
 | 
					        goto out_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!image_bs) {
 | 
					    if (!image_bs) {
 | 
				
			||||||
        error_setg(errp, "image file not found");
 | 
					        error_setg(errp, "image file not found");
 | 
				
			||||||
        goto out;
 | 
					        goto out_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bdrv_find_base(image_bs) == image_bs) {
 | 
					    if (bdrv_find_base(image_bs) == image_bs) {
 | 
				
			||||||
        error_setg(errp, "not allowing backing file change on an image "
 | 
					        error_setg(errp, "not allowing backing file change on an image "
 | 
				
			||||||
                         "without a backing file");
 | 
					                         "without a backing file");
 | 
				
			||||||
        goto out;
 | 
					        goto out_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* even though we are not necessarily operating on bs, we need it to
 | 
					    /* even though we are not necessarily operating on bs, we need it to
 | 
				
			||||||
     * determine if block ops are currently prohibited on the chain */
 | 
					     * determine if block ops are currently prohibited on the chain */
 | 
				
			||||||
    bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
 | 
					    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
 | 
				
			||||||
        bdrv_graph_rdunlock_main_loop();
 | 
					        goto out_rdlock;
 | 
				
			||||||
        goto out;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* final sanity check */
 | 
					    /* final sanity check */
 | 
				
			||||||
    if (!bdrv_chain_contains(bs, image_bs)) {
 | 
					    if (!bdrv_chain_contains(bs, image_bs)) {
 | 
				
			||||||
        error_setg(errp, "'%s' and image file are not in the same chain",
 | 
					        error_setg(errp, "'%s' and image file are not in the same chain",
 | 
				
			||||||
                   device);
 | 
					                   device);
 | 
				
			||||||
        goto out;
 | 
					        goto out_rdlock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* if not r/w, reopen to make r/w */
 | 
					    /* if not r/w, reopen to make r/w */
 | 
				
			||||||
    ro = bdrv_is_read_only(image_bs);
 | 
					    ro = bdrv_is_read_only(image_bs);
 | 
				
			||||||
@ -3494,6 +3505,11 @@ void qmp_change_backing_file(const char *device,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
    aio_context_release(aio_context);
 | 
					    aio_context_release(aio_context);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_rdlock:
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					    aio_context_release(aio_context);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
 | 
					void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
 | 
				
			||||||
 | 
				
			|||||||
@ -513,7 +513,8 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
 | 
				
			|||||||
    BlockJob *job;
 | 
					    BlockJob *job;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
    GLOBAL_STATE_CODE();
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (job_id == NULL && !(flags & JOB_INTERNAL)) {
 | 
					    if (job_id == NULL && !(flags & JOB_INTERNAL)) {
 | 
				
			||||||
        job_id = bdrv_get_device_name(bs);
 | 
					        job_id = bdrv_get_device_name(bs);
 | 
				
			||||||
@ -522,6 +523,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
 | 
				
			|||||||
    job = job_create(job_id, &driver->job_driver, txn, bdrv_get_aio_context(bs),
 | 
					    job = job_create(job_id, &driver->job_driver, txn, bdrv_get_aio_context(bs),
 | 
				
			||||||
                     flags, cb, opaque, errp);
 | 
					                     flags, cb, opaque, errp);
 | 
				
			||||||
    if (job == NULL) {
 | 
					    if (job == NULL) {
 | 
				
			||||||
 | 
					        bdrv_graph_wrunlock();
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -561,9 +563,11 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
 | 
				
			|||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
    return job;
 | 
					    return job;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
    job_early_fail(&job->job);
 | 
					    job_early_fail(&job->job);
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -897,11 +897,10 @@ static bool ahci_write_fis_d2h(AHCIDevice *ad, bool d2h_fis_i)
 | 
				
			|||||||
    pr->tfdata = (ad->port.ifs[0].error << 8) |
 | 
					    pr->tfdata = (ad->port.ifs[0].error << 8) |
 | 
				
			||||||
        ad->port.ifs[0].status;
 | 
					        ad->port.ifs[0].status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* TFES IRQ is always raised if ERR_STAT is set, regardless of I bit. */
 | 
				
			||||||
    if (d2h_fis[2] & ERR_STAT) {
 | 
					    if (d2h_fis[2] & ERR_STAT) {
 | 
				
			||||||
        ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_TFES);
 | 
					        ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_TFES);
 | 
				
			||||||
    }
 | 
					    } else if (d2h_fis_i) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (d2h_fis_i) {
 | 
					 | 
				
			||||||
        ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_DHRS);
 | 
					        ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_DHRS);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -71,8 +71,10 @@ bdrv_co_create_file(const char *filename, QemuOpts *opts, Error **errp);
 | 
				
			|||||||
BlockDriverState *bdrv_new(void);
 | 
					BlockDriverState *bdrv_new(void);
 | 
				
			||||||
int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
 | 
					int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
 | 
				
			||||||
                Error **errp);
 | 
					                Error **errp);
 | 
				
			||||||
int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
 | 
					
 | 
				
			||||||
                      Error **errp);
 | 
					int GRAPH_WRLOCK
 | 
				
			||||||
 | 
					bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
 | 
					int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
 | 
				
			||||||
                          Error **errp);
 | 
					                          Error **errp);
 | 
				
			||||||
BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options,
 | 
					BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options,
 | 
				
			||||||
@ -101,9 +103,10 @@ bdrv_co_open_blockdev_ref(BlockdevRef *ref, Error **errp);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
 | 
					int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
 | 
				
			||||||
                        Error **errp);
 | 
					                        Error **errp);
 | 
				
			||||||
int bdrv_set_backing_hd_drained(BlockDriverState *bs,
 | 
					int GRAPH_WRLOCK
 | 
				
			||||||
                                BlockDriverState *backing_hd,
 | 
					bdrv_set_backing_hd_drained(BlockDriverState *bs, BlockDriverState *backing_hd,
 | 
				
			||||||
                                Error **errp);
 | 
					                            Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
 | 
					int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
 | 
				
			||||||
                           const char *bdref_key, Error **errp);
 | 
					                           const char *bdref_key, Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -139,19 +142,21 @@ bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int bdrv_commit(BlockDriverState *bs);
 | 
					int bdrv_commit(BlockDriverState *bs);
 | 
				
			||||||
int GRAPH_RDLOCK bdrv_make_empty(BdrvChild *c, Error **errp);
 | 
					int GRAPH_RDLOCK bdrv_make_empty(BdrvChild *c, Error **errp);
 | 
				
			||||||
int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
 | 
					
 | 
				
			||||||
                             const char *backing_fmt, bool warn);
 | 
					 | 
				
			||||||
void bdrv_register(BlockDriver *bdrv);
 | 
					void bdrv_register(BlockDriver *bdrv);
 | 
				
			||||||
int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
 | 
					int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
 | 
				
			||||||
                           const char *backing_file_str);
 | 
					                           const char *backing_file_str);
 | 
				
			||||||
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
 | 
					
 | 
				
			||||||
                                    BlockDriverState *bs);
 | 
					BlockDriverState * GRAPH_RDLOCK
 | 
				
			||||||
BlockDriverState *bdrv_find_base(BlockDriverState *bs);
 | 
					bdrv_find_overlay(BlockDriverState *active, BlockDriverState *bs);
 | 
				
			||||||
bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
 | 
					
 | 
				
			||||||
                                  Error **errp);
 | 
					BlockDriverState * GRAPH_RDLOCK bdrv_find_base(BlockDriverState *bs);
 | 
				
			||||||
int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
 | 
					
 | 
				
			||||||
                              Error **errp);
 | 
					int GRAPH_RDLOCK
 | 
				
			||||||
void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base);
 | 
					bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
 | 
				
			||||||
 | 
					                          Error **errp);
 | 
				
			||||||
 | 
					void GRAPH_RDLOCK
 | 
				
			||||||
 | 
					bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * The units of offset and total_work_size may be chosen arbitrarily by the
 | 
					 * The units of offset and total_work_size may be chosen arbitrarily by the
 | 
				
			||||||
@ -189,14 +194,16 @@ void bdrv_drain_all(void);
 | 
				
			|||||||
void bdrv_aio_cancel(BlockAIOCB *acb);
 | 
					void bdrv_aio_cancel(BlockAIOCB *acb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bdrv_has_zero_init_1(BlockDriverState *bs);
 | 
					int bdrv_has_zero_init_1(BlockDriverState *bs);
 | 
				
			||||||
int bdrv_has_zero_init(BlockDriverState *bs);
 | 
					int coroutine_mixed_fn GRAPH_RDLOCK bdrv_has_zero_init(BlockDriverState *bs);
 | 
				
			||||||
BlockDriverState *bdrv_find_node(const char *node_name);
 | 
					BlockDriverState *bdrv_find_node(const char *node_name);
 | 
				
			||||||
BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, Error **errp);
 | 
					BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, Error **errp);
 | 
				
			||||||
XDbgBlockGraph * GRAPH_RDLOCK bdrv_get_xdbg_block_graph(Error **errp);
 | 
					XDbgBlockGraph * GRAPH_RDLOCK bdrv_get_xdbg_block_graph(Error **errp);
 | 
				
			||||||
BlockDriverState *bdrv_lookup_bs(const char *device,
 | 
					BlockDriverState *bdrv_lookup_bs(const char *device,
 | 
				
			||||||
                                 const char *node_name,
 | 
					                                 const char *node_name,
 | 
				
			||||||
                                 Error **errp);
 | 
					                                 Error **errp);
 | 
				
			||||||
bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base);
 | 
					bool GRAPH_RDLOCK
 | 
				
			||||||
 | 
					bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BlockDriverState *bdrv_next_node(BlockDriverState *bs);
 | 
					BlockDriverState *bdrv_next_node(BlockDriverState *bs);
 | 
				
			||||||
BlockDriverState *bdrv_next_all_states(BlockDriverState *bs);
 | 
					BlockDriverState *bdrv_next_all_states(BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -281,7 +288,7 @@ bool bdrv_child_change_aio_context(BdrvChild *c, AioContext *ctx,
 | 
				
			|||||||
int bdrv_try_change_aio_context(BlockDriverState *bs, AioContext *ctx,
 | 
					int bdrv_try_change_aio_context(BlockDriverState *bs, AioContext *ctx,
 | 
				
			||||||
                                BdrvChild *ignore_child, Error **errp);
 | 
					                                BdrvChild *ignore_child, Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz);
 | 
					int GRAPH_RDLOCK bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz);
 | 
				
			||||||
int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
 | 
					int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GRAPH_WRLOCK
 | 
					void GRAPH_WRLOCK
 | 
				
			||||||
 | 
				
			|||||||
@ -183,7 +183,7 @@ bdrv_co_eject(BlockDriverState *bs, bool eject_flag);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const char *bdrv_get_format_name(BlockDriverState *bs);
 | 
					const char *bdrv_get_format_name(BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool bdrv_supports_compressed_writes(BlockDriverState *bs);
 | 
					bool GRAPH_RDLOCK bdrv_supports_compressed_writes(BlockDriverState *bs);
 | 
				
			||||||
const char *bdrv_get_node_name(const BlockDriverState *bs);
 | 
					const char *bdrv_get_node_name(const BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char * GRAPH_RDLOCK
 | 
					const char * GRAPH_RDLOCK
 | 
				
			||||||
@ -210,6 +210,14 @@ void bdrv_round_to_subclusters(BlockDriverState *bs,
 | 
				
			|||||||
void bdrv_get_backing_filename(BlockDriverState *bs,
 | 
					void bdrv_get_backing_filename(BlockDriverState *bs,
 | 
				
			||||||
                               char *filename, int filename_size);
 | 
					                               char *filename, int filename_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int coroutine_fn GRAPH_RDLOCK
 | 
				
			||||||
 | 
					bdrv_co_change_backing_file(BlockDriverState *bs, const char *backing_file,
 | 
				
			||||||
 | 
					                            const char *backing_fmt, bool warn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int co_wrapper_bdrv_rdlock
 | 
				
			||||||
 | 
					bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
 | 
				
			||||||
 | 
					                         const char *backing_fmt, bool warn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
 | 
					int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
 | 
				
			||||||
                      int64_t pos, int size);
 | 
					                      int64_t pos, int size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -310,7 +310,7 @@ struct BlockDriver {
 | 
				
			|||||||
     * One example usage is to avoid waiting for an nbd target node reconnect
 | 
					     * One example usage is to avoid waiting for an nbd target node reconnect
 | 
				
			||||||
     * timeout during job-cancel with force=true.
 | 
					     * timeout during job-cancel with force=true.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    void (*bdrv_cancel_in_flight)(BlockDriverState *bs);
 | 
					    void GRAPH_RDLOCK_PTR (*bdrv_cancel_in_flight)(BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int GRAPH_RDLOCK_PTR (*bdrv_inactivate)(BlockDriverState *bs);
 | 
					    int GRAPH_RDLOCK_PTR (*bdrv_inactivate)(BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -324,15 +324,16 @@ struct BlockDriver {
 | 
				
			|||||||
        BlockDriverState *bs, const char *snapshot_id, const char *name,
 | 
					        BlockDriverState *bs, const char *snapshot_id, const char *name,
 | 
				
			||||||
        Error **errp);
 | 
					        Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int (*bdrv_snapshot_list)(BlockDriverState *bs,
 | 
					    int GRAPH_RDLOCK_PTR (*bdrv_snapshot_list)(
 | 
				
			||||||
                              QEMUSnapshotInfo **psn_info);
 | 
					        BlockDriverState *bs, QEMUSnapshotInfo **psn_info);
 | 
				
			||||||
    int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,
 | 
					 | 
				
			||||||
                                  const char *snapshot_id,
 | 
					 | 
				
			||||||
                                  const char *name,
 | 
					 | 
				
			||||||
                                  Error **errp);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int (*bdrv_change_backing_file)(BlockDriverState *bs,
 | 
					    int GRAPH_RDLOCK_PTR (*bdrv_snapshot_load_tmp)(
 | 
				
			||||||
        const char *backing_file, const char *backing_fmt);
 | 
					        BlockDriverState *bs, const char *snapshot_id, const char *name,
 | 
				
			||||||
 | 
					        Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_change_backing_file)(
 | 
				
			||||||
 | 
					        BlockDriverState *bs, const char *backing_file,
 | 
				
			||||||
 | 
					        const char *backing_fmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* TODO Better pass a option string/QDict/QemuOpts to add any rule? */
 | 
					    /* TODO Better pass a option string/QDict/QemuOpts to add any rule? */
 | 
				
			||||||
    int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event,
 | 
					    int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event,
 | 
				
			||||||
@ -349,7 +350,7 @@ struct BlockDriver {
 | 
				
			|||||||
     * Returns 1 if newly created images are guaranteed to contain only
 | 
					     * Returns 1 if newly created images are guaranteed to contain only
 | 
				
			||||||
     * zeros, 0 otherwise.
 | 
					     * zeros, 0 otherwise.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    int (*bdrv_has_zero_init)(BlockDriverState *bs);
 | 
					    int GRAPH_RDLOCK_PTR (*bdrv_has_zero_init)(BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Remove fd handlers, timers, and other event loop callbacks so the event
 | 
					     * Remove fd handlers, timers, and other event loop callbacks so the event
 | 
				
			||||||
@ -386,7 +387,8 @@ struct BlockDriver {
 | 
				
			|||||||
     * On success, store them in @bsz and return zero.
 | 
					     * On success, store them in @bsz and return zero.
 | 
				
			||||||
     * On failure, return negative errno.
 | 
					     * On failure, return negative errno.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    int (*bdrv_probe_blocksizes)(BlockDriverState *bs, BlockSizes *bsz);
 | 
					    int GRAPH_RDLOCK_PTR (*bdrv_probe_blocksizes)(
 | 
				
			||||||
 | 
					        BlockDriverState *bs, BlockSizes *bsz);
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Try to get @bs's geometry (cyls, heads, sectors)
 | 
					     * Try to get @bs's geometry (cyls, heads, sectors)
 | 
				
			||||||
     * On success, store them in @geo and return 0.
 | 
					     * On success, store them in @geo and return 0.
 | 
				
			||||||
@ -394,7 +396,8 @@ struct BlockDriver {
 | 
				
			|||||||
     * Only drivers that want to override guest geometry implement this
 | 
					     * Only drivers that want to override guest geometry implement this
 | 
				
			||||||
     * callback; see hd_geometry_guess().
 | 
					     * callback; see hd_geometry_guess().
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo);
 | 
					    int GRAPH_RDLOCK_PTR (*bdrv_probe_geometry)(
 | 
				
			||||||
 | 
					        BlockDriverState *bs, HDGeometry *geo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void GRAPH_WRLOCK_PTR (*bdrv_add_child)(
 | 
					    void GRAPH_WRLOCK_PTR (*bdrv_add_child)(
 | 
				
			||||||
        BlockDriverState *parent, BlockDriverState *child, Error **errp);
 | 
					        BlockDriverState *parent, BlockDriverState *child, Error **errp);
 | 
				
			||||||
@ -1177,8 +1180,8 @@ struct BlockDriverState {
 | 
				
			|||||||
     * are connected with BdrvChildRole.
 | 
					     * are connected with BdrvChildRole.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    QLIST_HEAD(, BdrvChild GRAPH_RDLOCK_PTR) children;
 | 
					    QLIST_HEAD(, BdrvChild GRAPH_RDLOCK_PTR) children;
 | 
				
			||||||
    BdrvChild *backing;
 | 
					    BdrvChild * GRAPH_RDLOCK_PTR backing;
 | 
				
			||||||
    BdrvChild *file;
 | 
					    BdrvChild * GRAPH_RDLOCK_PTR file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QLIST_HEAD(, BdrvChild GRAPH_RDLOCK_PTR) parents;
 | 
					    QLIST_HEAD(, BdrvChild GRAPH_RDLOCK_PTR) parents;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -196,12 +196,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
 | 
				
			|||||||
                            BlockCompletionFunc *cb, void *opaque,
 | 
					                            BlockCompletionFunc *cb, void *opaque,
 | 
				
			||||||
                            JobTxn *txn, Error **errp);
 | 
					                            JobTxn *txn, Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
 | 
					BdrvChild * GRAPH_WRLOCK
 | 
				
			||||||
                                  const char *child_name,
 | 
					bdrv_root_attach_child(BlockDriverState *child_bs, const char *child_name,
 | 
				
			||||||
                                  const BdrvChildClass *child_class,
 | 
					                       const BdrvChildClass *child_class,
 | 
				
			||||||
                                  BdrvChildRole child_role,
 | 
					                       BdrvChildRole child_role,
 | 
				
			||||||
                                  uint64_t perm, uint64_t shared_perm,
 | 
					                       uint64_t perm, uint64_t shared_perm,
 | 
				
			||||||
                                  void *opaque, Error **errp);
 | 
					                       void *opaque, Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GRAPH_WRLOCK bdrv_root_unref_child(BdrvChild *child);
 | 
					void GRAPH_WRLOCK bdrv_root_unref_child(BdrvChild *child);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GRAPH_RDLOCK bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
 | 
					void GRAPH_RDLOCK bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
 | 
				
			||||||
@ -276,7 +277,8 @@ BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name,
 | 
				
			|||||||
                                           Error **errp);
 | 
					                                           Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BlockDriverState *bdrv_skip_implicit_filters(BlockDriverState *bs);
 | 
					BlockDriverState * GRAPH_RDLOCK
 | 
				
			||||||
 | 
					bdrv_skip_implicit_filters(BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * bdrv_add_aio_context_notifier:
 | 
					 * bdrv_add_aio_context_notifier:
 | 
				
			||||||
 | 
				
			|||||||
@ -130,26 +130,29 @@ bdrv_co_refresh_total_sectors(BlockDriverState *bs, int64_t hint);
 | 
				
			|||||||
int co_wrapper_mixed_bdrv_rdlock
 | 
					int co_wrapper_mixed_bdrv_rdlock
 | 
				
			||||||
bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint);
 | 
					bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BdrvChild *bdrv_cow_child(BlockDriverState *bs);
 | 
					BdrvChild * GRAPH_RDLOCK bdrv_cow_child(BlockDriverState *bs);
 | 
				
			||||||
BdrvChild *bdrv_filter_child(BlockDriverState *bs);
 | 
					BdrvChild * GRAPH_RDLOCK bdrv_filter_child(BlockDriverState *bs);
 | 
				
			||||||
BdrvChild *bdrv_filter_or_cow_child(BlockDriverState *bs);
 | 
					BdrvChild * GRAPH_RDLOCK bdrv_filter_or_cow_child(BlockDriverState *bs);
 | 
				
			||||||
BdrvChild * GRAPH_RDLOCK bdrv_primary_child(BlockDriverState *bs);
 | 
					BdrvChild * GRAPH_RDLOCK bdrv_primary_child(BlockDriverState *bs);
 | 
				
			||||||
BlockDriverState *bdrv_skip_filters(BlockDriverState *bs);
 | 
					BlockDriverState * GRAPH_RDLOCK bdrv_skip_filters(BlockDriverState *bs);
 | 
				
			||||||
BlockDriverState *bdrv_backing_chain_next(BlockDriverState *bs);
 | 
					BlockDriverState * GRAPH_RDLOCK bdrv_backing_chain_next(BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline BlockDriverState *bdrv_cow_bs(BlockDriverState *bs)
 | 
					static inline BlockDriverState * GRAPH_RDLOCK
 | 
				
			||||||
 | 
					bdrv_cow_bs(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    IO_CODE();
 | 
					    IO_CODE();
 | 
				
			||||||
    return child_bs(bdrv_cow_child(bs));
 | 
					    return child_bs(bdrv_cow_child(bs));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline BlockDriverState *bdrv_filter_bs(BlockDriverState *bs)
 | 
					static inline BlockDriverState * GRAPH_RDLOCK
 | 
				
			||||||
 | 
					bdrv_filter_bs(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    IO_CODE();
 | 
					    IO_CODE();
 | 
				
			||||||
    return child_bs(bdrv_filter_child(bs));
 | 
					    return child_bs(bdrv_filter_child(bs));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline BlockDriverState *bdrv_filter_or_cow_bs(BlockDriverState *bs)
 | 
					static inline BlockDriverState * GRAPH_RDLOCK
 | 
				
			||||||
 | 
					bdrv_filter_or_cow_bs(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    IO_CODE();
 | 
					    IO_CODE();
 | 
				
			||||||
    return child_bs(bdrv_filter_or_cow_child(bs));
 | 
					    return child_bs(bdrv_filter_or_cow_child(bs));
 | 
				
			||||||
 | 
				
			|||||||
@ -138,8 +138,9 @@ BlockJob *block_job_get_locked(const char *id);
 | 
				
			|||||||
 * @job. This means that all operations will be blocked on @bs while
 | 
					 * @job. This means that all operations will be blocked on @bs while
 | 
				
			||||||
 * @job exists.
 | 
					 * @job exists.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
 | 
					int GRAPH_WRLOCK
 | 
				
			||||||
                       uint64_t perm, uint64_t shared_perm, Error **errp);
 | 
					block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
 | 
				
			||||||
 | 
					                   uint64_t perm, uint64_t shared_perm, Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * block_job_remove_all_bdrv:
 | 
					 * block_job_remove_all_bdrv:
 | 
				
			||||||
 | 
				
			|||||||
@ -111,10 +111,11 @@ struct BlockJobDriver {
 | 
				
			|||||||
 * This function is not part of the public job interface; it should be
 | 
					 * This function is not part of the public job interface; it should be
 | 
				
			||||||
 * called from a wrapper that is specific to the job type.
 | 
					 * called from a wrapper that is specific to the job type.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void *block_job_create(const char *job_id, const BlockJobDriver *driver,
 | 
					void * GRAPH_UNLOCKED
 | 
				
			||||||
                       JobTxn *txn, BlockDriverState *bs, uint64_t perm,
 | 
					block_job_create(const char *job_id, const BlockJobDriver *driver,
 | 
				
			||||||
                       uint64_t shared_perm, int64_t speed, int flags,
 | 
					                 JobTxn *txn, BlockDriverState *bs, uint64_t perm,
 | 
				
			||||||
                       BlockCompletionFunc *cb, void *opaque, Error **errp);
 | 
					                 uint64_t shared_perm, int64_t speed, int flags,
 | 
				
			||||||
 | 
					                 BlockCompletionFunc *cb, void *opaque, Error **errp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * block_job_free:
 | 
					 * block_job_free:
 | 
				
			||||||
 | 
				
			|||||||
@ -607,6 +607,10 @@ static int init_dirty_bitmap_migration(DBMSaveState *s)
 | 
				
			|||||||
    BlockBackend *blk;
 | 
					    BlockBackend *blk;
 | 
				
			||||||
    GHashTable *alias_map = NULL;
 | 
					    GHashTable *alias_map = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Runs in the migration thread, but holds the iothread lock */
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (migrate_has_block_bitmap_mapping()) {
 | 
					    if (migrate_has_block_bitmap_mapping()) {
 | 
				
			||||||
        alias_map = construct_alias_map(migrate_block_bitmap_mapping(), true,
 | 
					        alias_map = construct_alias_map(migrate_block_bitmap_mapping(), true,
 | 
				
			||||||
                                        &error_abort);
 | 
					                                        &error_abort);
 | 
				
			||||||
 | 
				
			|||||||
@ -1689,6 +1689,7 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
 | 
				
			|||||||
    size_t i;
 | 
					    size_t i;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
    assert(exp_args->type == BLOCK_EXPORT_TYPE_NBD);
 | 
					    assert(exp_args->type == BLOCK_EXPORT_TYPE_NBD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!nbd_server_is_running()) {
 | 
					    if (!nbd_server_is_running()) {
 | 
				
			||||||
@ -1743,6 +1744,8 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE);
 | 
					    exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (bitmaps = arg->bitmaps; bitmaps; bitmaps = bitmaps->next) {
 | 
					    for (bitmaps = arg->bitmaps; bitmaps; bitmaps = bitmaps->next) {
 | 
				
			||||||
        exp->nr_export_bitmaps++;
 | 
					        exp->nr_export_bitmaps++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -1825,9 +1828,12 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    QTAILQ_INSERT_TAIL(&exports, exp, next);
 | 
					    QTAILQ_INSERT_TAIL(&exports, exp, next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
    g_free(exp->export_bitmaps);
 | 
					    g_free(exp->export_bitmaps);
 | 
				
			||||||
    g_free(exp->name);
 | 
					    g_free(exp->name);
 | 
				
			||||||
    g_free(exp->description);
 | 
					    g_free(exp->description);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										31
									
								
								qemu-img.c
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								qemu-img.c
									
									
									
									
									
								
							@ -1050,12 +1050,14 @@ static int img_commit(int argc, char **argv)
 | 
				
			|||||||
    qemu_progress_init(progress, 1.f);
 | 
					    qemu_progress_init(progress, 1.f);
 | 
				
			||||||
    qemu_progress_print(0.f, 100);
 | 
					    qemu_progress_print(0.f, 100);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    if (base) {
 | 
					    if (base) {
 | 
				
			||||||
        base_bs = bdrv_find_backing_image(bs, base);
 | 
					        base_bs = bdrv_find_backing_image(bs, base);
 | 
				
			||||||
        if (!base_bs) {
 | 
					        if (!base_bs) {
 | 
				
			||||||
            error_setg(&local_err,
 | 
					            error_setg(&local_err,
 | 
				
			||||||
                       "Did not find '%s' in the backing chain of '%s'",
 | 
					                       "Did not find '%s' in the backing chain of '%s'",
 | 
				
			||||||
                       base, filename);
 | 
					                       base, filename);
 | 
				
			||||||
 | 
					            bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
            goto done;
 | 
					            goto done;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@ -1065,9 +1067,11 @@ static int img_commit(int argc, char **argv)
 | 
				
			|||||||
        base_bs = bdrv_backing_chain_next(bs);
 | 
					        base_bs = bdrv_backing_chain_next(bs);
 | 
				
			||||||
        if (!base_bs) {
 | 
					        if (!base_bs) {
 | 
				
			||||||
            error_setg(&local_err, "Image does not have a backing file");
 | 
					            error_setg(&local_err, "Image does not have a backing file");
 | 
				
			||||||
 | 
					            bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
            goto done;
 | 
					            goto done;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cbi = (CommonBlockJobCBInfo){
 | 
					    cbi = (CommonBlockJobCBInfo){
 | 
				
			||||||
        .errp = &local_err,
 | 
					        .errp = &local_err,
 | 
				
			||||||
@ -1713,7 +1717,8 @@ static void convert_select_part(ImgConvertState *s, int64_t sector_num,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
 | 
					static int coroutine_mixed_fn GRAPH_RDLOCK
 | 
				
			||||||
 | 
					convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int64_t src_cur_offset;
 | 
					    int64_t src_cur_offset;
 | 
				
			||||||
    int ret, n, src_cur;
 | 
					    int ret, n, src_cur;
 | 
				
			||||||
@ -2099,7 +2104,9 @@ static int convert_do_copy(ImgConvertState *s)
 | 
				
			|||||||
    /* Check whether we have zero initialisation or can get it efficiently */
 | 
					    /* Check whether we have zero initialisation or can get it efficiently */
 | 
				
			||||||
    if (!s->has_zero_init && s->target_is_new && s->min_sparse &&
 | 
					    if (!s->has_zero_init && s->target_is_new && s->min_sparse &&
 | 
				
			||||||
        !s->target_has_backing) {
 | 
					        !s->target_has_backing) {
 | 
				
			||||||
 | 
					        bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
        s->has_zero_init = bdrv_has_zero_init(blk_bs(s->target));
 | 
					        s->has_zero_init = bdrv_has_zero_init(blk_bs(s->target));
 | 
				
			||||||
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Allocate buffer for copied data. For compressed images, only one cluster
 | 
					    /* Allocate buffer for copied data. For compressed images, only one cluster
 | 
				
			||||||
@ -2113,7 +2120,9 @@ static int convert_do_copy(ImgConvertState *s)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (sector_num < s->total_sectors) {
 | 
					    while (sector_num < s->total_sectors) {
 | 
				
			||||||
 | 
					        bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
        n = convert_iteration_sectors(s, sector_num);
 | 
					        n = convert_iteration_sectors(s, sector_num);
 | 
				
			||||||
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
        if (n < 0) {
 | 
					        if (n < 0) {
 | 
				
			||||||
            return n;
 | 
					            return n;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -2755,8 +2764,10 @@ static int img_convert(int argc, char **argv)
 | 
				
			|||||||
         * s.target_backing_sectors has to be negative, which it will
 | 
					         * s.target_backing_sectors has to be negative, which it will
 | 
				
			||||||
         * be automatically).  The backing file length is used only
 | 
					         * be automatically).  The backing file length is used only
 | 
				
			||||||
         * for optimizations, so such a case is not fatal. */
 | 
					         * for optimizations, so such a case is not fatal. */
 | 
				
			||||||
 | 
					        bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
        s.target_backing_sectors =
 | 
					        s.target_backing_sectors =
 | 
				
			||||||
            bdrv_nb_sectors(bdrv_backing_chain_next(out_bs));
 | 
					            bdrv_nb_sectors(bdrv_backing_chain_next(out_bs));
 | 
				
			||||||
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        s.target_backing_sectors = -1;
 | 
					        s.target_backing_sectors = -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -3143,6 +3154,9 @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
 | 
				
			|||||||
    int64_t map;
 | 
					    int64_t map;
 | 
				
			||||||
    char *filename = NULL;
 | 
					    char *filename = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GLOBAL_STATE_CODE();
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* As an optimization, we could cache the current range of unallocated
 | 
					    /* As an optimization, we could cache the current range of unallocated
 | 
				
			||||||
     * clusters in each file of the chain, and avoid querying the same
 | 
					     * clusters in each file of the chain, and avoid querying the same
 | 
				
			||||||
     * range repeatedly.
 | 
					     * range repeatedly.
 | 
				
			||||||
@ -3171,9 +3185,7 @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
 | 
				
			|||||||
    has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID);
 | 
					    has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (file && has_offset) {
 | 
					    if (file && has_offset) {
 | 
				
			||||||
        bdrv_graph_rdlock_main_loop();
 | 
					 | 
				
			||||||
        bdrv_refresh_filename(file);
 | 
					        bdrv_refresh_filename(file);
 | 
				
			||||||
        bdrv_graph_rdunlock_main_loop();
 | 
					 | 
				
			||||||
        filename = file->filename;
 | 
					        filename = file->filename;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3529,7 +3541,7 @@ static int img_rebase(int argc, char **argv)
 | 
				
			|||||||
    uint8_t *buf_old = NULL;
 | 
					    uint8_t *buf_old = NULL;
 | 
				
			||||||
    uint8_t *buf_new = NULL;
 | 
					    uint8_t *buf_new = NULL;
 | 
				
			||||||
    BlockDriverState *bs = NULL, *prefix_chain_bs = NULL;
 | 
					    BlockDriverState *bs = NULL, *prefix_chain_bs = NULL;
 | 
				
			||||||
    BlockDriverState *unfiltered_bs;
 | 
					    BlockDriverState *unfiltered_bs, *unfiltered_bs_cow;
 | 
				
			||||||
    BlockDriverInfo bdi = {0};
 | 
					    BlockDriverInfo bdi = {0};
 | 
				
			||||||
    char *filename;
 | 
					    char *filename;
 | 
				
			||||||
    const char *fmt, *cache, *src_cache, *out_basefmt, *out_baseimg;
 | 
					    const char *fmt, *cache, *src_cache, *out_basefmt, *out_baseimg;
 | 
				
			||||||
@ -3661,7 +3673,10 @@ static int img_rebase(int argc, char **argv)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    bs = blk_bs(blk);
 | 
					    bs = blk_bs(blk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    unfiltered_bs = bdrv_skip_filters(bs);
 | 
					    unfiltered_bs = bdrv_skip_filters(bs);
 | 
				
			||||||
 | 
					    unfiltered_bs_cow = bdrv_cow_bs(unfiltered_bs);
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (compress && !block_driver_can_compress(unfiltered_bs->drv)) {
 | 
					    if (compress && !block_driver_can_compress(unfiltered_bs->drv)) {
 | 
				
			||||||
        error_report("Compression not supported for this file format");
 | 
					        error_report("Compression not supported for this file format");
 | 
				
			||||||
@ -3696,7 +3711,11 @@ static int img_rebase(int argc, char **argv)
 | 
				
			|||||||
    /* For safe rebasing we need to compare old and new backing file */
 | 
					    /* For safe rebasing we need to compare old and new backing file */
 | 
				
			||||||
    if (!unsafe) {
 | 
					    if (!unsafe) {
 | 
				
			||||||
        QDict *options = NULL;
 | 
					        QDict *options = NULL;
 | 
				
			||||||
        BlockDriverState *base_bs = bdrv_cow_bs(unfiltered_bs);
 | 
					        BlockDriverState *base_bs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
 | 
					        base_bs = bdrv_cow_bs(unfiltered_bs);
 | 
				
			||||||
 | 
					        bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (base_bs) {
 | 
					        if (base_bs) {
 | 
				
			||||||
            blk_old_backing = blk_new(qemu_get_aio_context(),
 | 
					            blk_old_backing = blk_new(qemu_get_aio_context(),
 | 
				
			||||||
@ -3862,7 +3881,7 @@ static int img_rebase(int argc, char **argv)
 | 
				
			|||||||
                 * If cluster wasn't changed since prefix_chain, we don't need
 | 
					                 * If cluster wasn't changed since prefix_chain, we don't need
 | 
				
			||||||
                 * to take action
 | 
					                 * to take action
 | 
				
			||||||
                 */
 | 
					                 */
 | 
				
			||||||
                ret = bdrv_is_allocated_above(bdrv_cow_bs(unfiltered_bs),
 | 
					                ret = bdrv_is_allocated_above(unfiltered_bs_cow,
 | 
				
			||||||
                                              prefix_chain_bs, false,
 | 
					                                              prefix_chain_bs, false,
 | 
				
			||||||
                                              offset, n, &n);
 | 
					                                              offset, n, &n);
 | 
				
			||||||
                if (ret < 0) {
 | 
					                if (ret < 0) {
 | 
				
			||||||
 | 
				
			|||||||
@ -96,9 +96,9 @@ static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs,
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int bdrv_test_change_backing_file(BlockDriverState *bs,
 | 
					static int bdrv_test_co_change_backing_file(BlockDriverState *bs,
 | 
				
			||||||
                                         const char *backing_file,
 | 
					                                            const char *backing_file,
 | 
				
			||||||
                                         const char *backing_fmt)
 | 
					                                            const char *backing_fmt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -116,7 +116,7 @@ static BlockDriver bdrv_test = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    .bdrv_child_perm        = bdrv_default_perms,
 | 
					    .bdrv_child_perm        = bdrv_default_perms,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .bdrv_change_backing_file = bdrv_test_change_backing_file,
 | 
					    .bdrv_co_change_backing_file = bdrv_test_co_change_backing_file,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void aio_ret_cb(void *opaque, int ret)
 | 
					static void aio_ret_cb(void *opaque, int ret)
 | 
				
			||||||
@ -218,8 +218,14 @@ static void do_drain_end_unlocked(enum drain_type drain_type, BlockDriverState *
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_drv_cb_common(BlockBackend *blk, enum drain_type drain_type,
 | 
					/*
 | 
				
			||||||
                               bool recursive)
 | 
					 * Locking the block graph would be a bit cumbersome here because this function
 | 
				
			||||||
 | 
					 * is called both in coroutine and non-coroutine context. We know this is a test
 | 
				
			||||||
 | 
					 * and nothing else is running, so don't bother with TSA.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void coroutine_mixed_fn TSA_NO_TSA
 | 
				
			||||||
 | 
					test_drv_cb_common(BlockBackend *blk, enum drain_type drain_type,
 | 
				
			||||||
 | 
					                   bool recursive)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriverState *bs = blk_bs(blk);
 | 
					    BlockDriverState *bs = blk_bs(blk);
 | 
				
			||||||
    BlockDriverState *backing = bs->backing->bs;
 | 
					    BlockDriverState *backing = bs->backing->bs;
 | 
				
			||||||
@ -307,8 +313,14 @@ static void test_drv_cb_co_drain(void)
 | 
				
			|||||||
    blk_unref(blk);
 | 
					    blk_unref(blk);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_quiesce_common(BlockBackend *blk, enum drain_type drain_type,
 | 
					/*
 | 
				
			||||||
                                bool recursive)
 | 
					 * Locking the block graph would be a bit cumbersome here because this function
 | 
				
			||||||
 | 
					 * is called both in coroutine and non-coroutine context. We know this is a test
 | 
				
			||||||
 | 
					 * and nothing else is running, so don't bother with TSA.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void coroutine_mixed_fn TSA_NO_TSA
 | 
				
			||||||
 | 
					test_quiesce_common(BlockBackend *blk, enum drain_type drain_type,
 | 
				
			||||||
 | 
					                    bool recursive)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriverState *bs = blk_bs(blk);
 | 
					    BlockDriverState *bs = blk_bs(blk);
 | 
				
			||||||
    BlockDriverState *backing = bs->backing->bs;
 | 
					    BlockDriverState *backing = bs->backing->bs;
 | 
				
			||||||
@ -794,7 +806,10 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
 | 
				
			|||||||
                            0, 0, NULL, NULL, &error_abort);
 | 
					                            0, 0, NULL, NULL, &error_abort);
 | 
				
			||||||
    tjob->bs = src;
 | 
					    tjob->bs = src;
 | 
				
			||||||
    job = &tjob->common;
 | 
					    job = &tjob->common;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(target);
 | 
				
			||||||
    block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort);
 | 
					    block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (result) {
 | 
					    switch (result) {
 | 
				
			||||||
    case TEST_JOB_SUCCESS:
 | 
					    case TEST_JOB_SUCCESS:
 | 
				
			||||||
@ -1865,6 +1880,8 @@ static void bdrv_replace_test_drain_end(BlockDriverState *bs)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    BDRVReplaceTestState *s = bs->opaque;
 | 
					    BDRVReplaceTestState *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GRAPH_RDLOCK_GUARD_MAINLOOP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!s->setup_completed) {
 | 
					    if (!s->setup_completed) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -1997,7 +2014,13 @@ static void do_test_replace_child_mid_drain(int old_drain_count,
 | 
				
			|||||||
    parent_s->was_undrained = false;
 | 
					    parent_s->was_undrained = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_assert(parent_bs->quiesce_counter == old_drain_count);
 | 
					    g_assert(parent_bs->quiesce_counter == old_drain_count);
 | 
				
			||||||
 | 
					    bdrv_drained_begin(old_child_bs);
 | 
				
			||||||
 | 
					    bdrv_drained_begin(new_child_bs);
 | 
				
			||||||
 | 
					    bdrv_graph_wrlock(NULL);
 | 
				
			||||||
    bdrv_replace_node(old_child_bs, new_child_bs, &error_abort);
 | 
					    bdrv_replace_node(old_child_bs, new_child_bs, &error_abort);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					    bdrv_drained_end(new_child_bs);
 | 
				
			||||||
 | 
					    bdrv_drained_end(old_child_bs);
 | 
				
			||||||
    g_assert(parent_bs->quiesce_counter == new_drain_count);
 | 
					    g_assert(parent_bs->quiesce_counter == new_drain_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!old_drain_count && !new_drain_count) {
 | 
					    if (!old_drain_count && !new_drain_count) {
 | 
				
			||||||
 | 
				
			|||||||
@ -206,15 +206,18 @@ static void test_should_update_child(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    bdrv_set_backing_hd(target, bs, &error_abort);
 | 
					    bdrv_set_backing_hd(target, bs, &error_abort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_assert(target->backing->bs == bs);
 | 
					 | 
				
			||||||
    bdrv_graph_wrlock(NULL);
 | 
					    bdrv_graph_wrlock(NULL);
 | 
				
			||||||
 | 
					    g_assert(target->backing->bs == bs);
 | 
				
			||||||
    bdrv_attach_child(filter, target, "target", &child_of_bds,
 | 
					    bdrv_attach_child(filter, target, "target", &child_of_bds,
 | 
				
			||||||
                      BDRV_CHILD_DATA, &error_abort);
 | 
					                      BDRV_CHILD_DATA, &error_abort);
 | 
				
			||||||
    bdrv_graph_wrunlock();
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
    aio_context_acquire(qemu_get_aio_context());
 | 
					    aio_context_acquire(qemu_get_aio_context());
 | 
				
			||||||
    bdrv_append(filter, bs, &error_abort);
 | 
					    bdrv_append(filter, bs, &error_abort);
 | 
				
			||||||
    aio_context_release(qemu_get_aio_context());
 | 
					    aio_context_release(qemu_get_aio_context());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_graph_rdlock_main_loop();
 | 
				
			||||||
    g_assert(target->backing->bs == bs);
 | 
					    g_assert(target->backing->bs == bs);
 | 
				
			||||||
 | 
					    bdrv_graph_rdunlock_main_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_unref(filter);
 | 
					    bdrv_unref(filter);
 | 
				
			||||||
    bdrv_unref(bs);
 | 
					    bdrv_unref(bs);
 | 
				
			||||||
@ -234,11 +237,16 @@ static void test_parallel_exclusive_write(void)
 | 
				
			|||||||
    BlockDriverState *fl1 = pass_through_node("fl1");
 | 
					    BlockDriverState *fl1 = pass_through_node("fl1");
 | 
				
			||||||
    BlockDriverState *fl2 = pass_through_node("fl2");
 | 
					    BlockDriverState *fl2 = pass_through_node("fl2");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_drained_begin(fl1);
 | 
				
			||||||
 | 
					    bdrv_drained_begin(fl2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * bdrv_attach_child() eats child bs reference, so we need two @base
 | 
					     * bdrv_attach_child() eats child bs reference, so we need two @base
 | 
				
			||||||
     * references for two filters:
 | 
					     * references for two filters. We also need an additional @fl1 reference so
 | 
				
			||||||
 | 
					     * that it still exists when we want to undrain it.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    bdrv_ref(base);
 | 
					    bdrv_ref(base);
 | 
				
			||||||
 | 
					    bdrv_ref(fl1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_graph_wrlock(NULL);
 | 
					    bdrv_graph_wrlock(NULL);
 | 
				
			||||||
    bdrv_attach_child(top, fl1, "backing", &child_of_bds,
 | 
					    bdrv_attach_child(top, fl1, "backing", &child_of_bds,
 | 
				
			||||||
@ -250,10 +258,14 @@ static void test_parallel_exclusive_write(void)
 | 
				
			|||||||
    bdrv_attach_child(fl2, base, "backing", &child_of_bds,
 | 
					    bdrv_attach_child(fl2, base, "backing", &child_of_bds,
 | 
				
			||||||
                      BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
 | 
					                      BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
 | 
				
			||||||
                      &error_abort);
 | 
					                      &error_abort);
 | 
				
			||||||
    bdrv_graph_wrunlock();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bdrv_replace_node(fl1, fl2, &error_abort);
 | 
					    bdrv_replace_node(fl1, fl2, &error_abort);
 | 
				
			||||||
 | 
					    bdrv_graph_wrunlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_drained_end(fl2);
 | 
				
			||||||
 | 
					    bdrv_drained_end(fl1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bdrv_unref(fl1);
 | 
				
			||||||
    bdrv_unref(fl2);
 | 
					    bdrv_unref(fl2);
 | 
				
			||||||
    bdrv_unref(top);
 | 
					    bdrv_unref(top);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user