Skip to content

Commit

Permalink
Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging
Browse files Browse the repository at this point in the history
Block layer patches

- Graph locking part 4 (node management)
- qemu-img map: report compressed data blocks
- block-backend: process I/O in the current AioContext

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmUEbPkRHGt3b2xmQHJl
# ZGhhdC5jb20ACgkQfwmycsiPL9bIaQ//QAwYKudsfXZXaeWxqDm88tKHzN5oTt5P
# Fkb4MyHDqN0OboGwLbpHRFPDt5BPw3MhLzIyhsmWBD5Twyv+7+nTf7OzSp/ciNlg
# hISy/eZwEbqNZUktiYD8vCeuDJuCHSPlDKGe1as7mqSfVg1KwScYK2Yf8HWoTNz6
# Ku/Dm9opEX5obaOfeyLWXIzoWj5w2PcK4mn6hOTOSew6Ia44usV+QQe+yNAhMrJf
# sozoezaec6OUFXzoOlgz+nuEFcvxihST9ZBc/34msOSBGxDJuIHxBoAzsSTLZdmY
# LlsnzfjfFwd1qTb+m5h/HL2oEC9fje79XFWn8AAINkenXY8qZMfzXo+286DlQN/M
# YN6iq5pLmzOfbPLM6xq0EG/FBCm50mBmOgfyuLBuOhc3CTj/EzsGI7MAdeX32+cO
# 4pu2hGnzvqmWuJi+bVo40d1xpUnhEztzDK0d/NTvQMqNdQ4ieiLqCw1pgDvW4w6f
# 32xElO7wiut3SnylZoghXk2BACuK8SHeCgV2+iI9TRl8t0uBVsrYX/0mD4hNAtE0
# igNPQTfeZogqrFYhxrHftmL4pMfzvHXEaU1HbvJMTHnMdj+8bjtWfPpinmeLviP6
# fy1x90VJ7bSOgSgZSEGJTwCyOV+0M8bY5c+4uyRIRkye5QZtftYt5kJCvb0+4aTB
# ADq6DjKxX/A=
# =EgzU
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 15 Sep 2023 10:40:57 EDT
# 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: (28 commits)
  block-coroutine-wrapper: use qemu_get_current_aio_context()
  block-backend: process zoned requests in the current AioContext
  block-backend: process I/O in the current AioContext
  test-bdrv-drain: avoid race with BH in IOThread drain test
  block: remove AIOCBInfo->get_aio_context()
  qemu-img: map: report compressed data blocks
  block: add BDRV_BLOCK_COMPRESSED flag for bdrv_block_status()
  block: Mark bdrv_add/del_child() and caller GRAPH_WRLOCK
  block: Mark bdrv_unref_child() GRAPH_WRLOCK
  block: Mark bdrv_root_unref_child() GRAPH_WRLOCK
  block: Take graph rdlock in bdrv_change_aio_context()
  block: Take graph rdlock in bdrv_drop_intermediate()
  block: Mark bdrv_parent_cb_change_media() GRAPH_RDLOCK
  block: Mark bdrv_child_perm() GRAPH_RDLOCK
  block: Mark bdrv_get_cumulative_perm() and callers GRAPH_RDLOCK
  block: Mark bdrv_parent_perms_conflict() and callers GRAPH_RDLOCK
  block: Mark bdrv_attach_child() GRAPH_WRLOCK
  block: Call transaction callbacks with lock held
  block: Mark bdrv_attach_child_common() GRAPH_WRLOCK
  block: Mark bdrv_replace_child_tran() GRAPH_WRLOCK
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
  • Loading branch information
stefanhaRH committed Sep 18, 2023
2 parents 8450c26 + 5d96864 commit 1738b8c
Show file tree
Hide file tree
Showing 50 changed files with 1,376 additions and 1,036 deletions.
348 changes: 251 additions & 97 deletions block.c

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions block/blklogwrites.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,9 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
ret = 0;
fail_log:
if (ret < 0) {
bdrv_graph_wrlock(NULL);
bdrv_unref_child(bs, s->log_file);
bdrv_graph_wrunlock();
s->log_file = NULL;
}
fail:
Expand All @@ -263,8 +265,10 @@ static void blk_log_writes_close(BlockDriverState *bs)
{
BDRVBlkLogWritesState *s = bs->opaque;

bdrv_graph_wrlock(NULL);
bdrv_unref_child(bs, s->log_file);
s->log_file = NULL;
bdrv_graph_wrunlock();
}

static int64_t coroutine_fn GRAPH_RDLOCK
Expand Down
2 changes: 2 additions & 0 deletions block/blkverify.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,10 @@ static void blkverify_close(BlockDriverState *bs)
{
BDRVBlkverifyState *s = bs->opaque;

bdrv_graph_wrlock(NULL);
bdrv_unref_child(bs, s->test_file);
s->test_file = NULL;
bdrv_graph_wrunlock();
}

static int64_t coroutine_fn GRAPH_RDLOCK
Expand Down
64 changes: 32 additions & 32 deletions block/block-backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@

#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */

static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb);

typedef struct BlockBackendAioNotifier {
void (*attached_aio_context)(AioContext *new_context, void *opaque);
void (*detach_aio_context)(void *opaque);
Expand Down Expand Up @@ -103,7 +101,6 @@ typedef struct BlockBackendAIOCB {
} BlockBackendAIOCB;

static const AIOCBInfo block_backend_aiocb_info = {
.get_aio_context = blk_aiocb_get_aio_context,
.aiocb_size = sizeof(BlockBackendAIOCB),
};

Expand All @@ -121,6 +118,10 @@ static QTAILQ_HEAD(, BlockBackend) block_backends =
static QTAILQ_HEAD(, BlockBackend) monitor_block_backends =
QTAILQ_HEAD_INITIALIZER(monitor_block_backends);

static int coroutine_mixed_fn GRAPH_RDLOCK
blk_set_perm_locked(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
Error **errp);

static void blk_root_inherit_options(BdrvChildRole role, bool parent_is_format,
int *child_flags, QDict *child_options,
int parent_flags, QDict *parent_options)
Expand Down Expand Up @@ -186,7 +187,7 @@ static void blk_vm_state_changed(void *opaque, bool running, RunState state)
*
* If an error is returned, the VM cannot be allowed to be resumed.
*/
static void blk_root_activate(BdrvChild *child, Error **errp)
static void GRAPH_RDLOCK blk_root_activate(BdrvChild *child, Error **errp)
{
BlockBackend *blk = child->opaque;
Error *local_err = NULL;
Expand All @@ -207,7 +208,7 @@ static void blk_root_activate(BdrvChild *child, Error **errp)
*/
saved_shared_perm = blk->shared_perm;

blk_set_perm(blk, blk->perm, BLK_PERM_ALL, &local_err);
blk_set_perm_locked(blk, blk->perm, BLK_PERM_ALL, &local_err);
if (local_err) {
error_propagate(errp, local_err);
blk->disable_perm = true;
Expand All @@ -226,7 +227,7 @@ static void blk_root_activate(BdrvChild *child, Error **errp)
return;
}

blk_set_perm(blk, blk->perm, blk->shared_perm, &local_err);
blk_set_perm_locked(blk, blk->perm, blk->shared_perm, &local_err);
if (local_err) {
error_propagate(errp, local_err);
blk->disable_perm = true;
Expand Down Expand Up @@ -259,7 +260,7 @@ static bool blk_can_inactivate(BlockBackend *blk)
return blk->force_allow_inactivate;
}

static int blk_root_inactivate(BdrvChild *child)
static int GRAPH_RDLOCK blk_root_inactivate(BdrvChild *child)
{
BlockBackend *blk = child->opaque;

Expand Down Expand Up @@ -911,7 +912,10 @@ void blk_remove_bs(BlockBackend *blk)
blk_drain(blk);
root = blk->root;
blk->root = NULL;

bdrv_graph_wrlock(NULL);
bdrv_root_unref_child(root);
bdrv_graph_wrunlock();
}

/*
Expand Down Expand Up @@ -953,8 +957,9 @@ int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp)
/*
* Sets the permission bitmasks that the user of the BlockBackend needs.
*/
int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
Error **errp)
static int coroutine_mixed_fn GRAPH_RDLOCK
blk_set_perm_locked(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
Error **errp)
{
int ret;
GLOBAL_STATE_CODE();
Expand All @@ -972,6 +977,15 @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
return 0;
}

int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
Error **errp)
{
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();

return blk_set_perm_locked(blk, perm, shared_perm, errp);
}

void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm)
{
GLOBAL_STATE_CODE();
Expand Down Expand Up @@ -1533,7 +1547,7 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk,
acb->blk = blk;
acb->ret = ret;

replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(),
error_callback_bh, acb);
return &acb->common;
}
Expand All @@ -1545,16 +1559,8 @@ typedef struct BlkAioEmAIOCB {
bool has_returned;
} BlkAioEmAIOCB;

static AioContext *blk_aio_em_aiocb_get_aio_context(BlockAIOCB *acb_)
{
BlkAioEmAIOCB *acb = container_of(acb_, BlkAioEmAIOCB, common);

return blk_get_aio_context(acb->rwco.blk);
}

static const AIOCBInfo blk_aio_em_aiocb_info = {
.aiocb_size = sizeof(BlkAioEmAIOCB),
.get_aio_context = blk_aio_em_aiocb_get_aio_context,
};

static void blk_aio_complete(BlkAioEmAIOCB *acb)
Expand Down Expand Up @@ -1595,11 +1601,11 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset,
acb->has_returned = false;

co = qemu_coroutine_create(co_entry, acb);
aio_co_enter(blk_get_aio_context(blk), co);
aio_co_enter(qemu_get_current_aio_context(), co);

acb->has_returned = true;
if (acb->rwco.ret != NOT_DONE) {
replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(),
blk_aio_complete_bh, acb);
}

Expand Down Expand Up @@ -1901,11 +1907,11 @@ BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset,
acb->has_returned = false;

co = qemu_coroutine_create(blk_aio_zone_report_entry, acb);
aio_co_enter(blk_get_aio_context(blk), co);
aio_co_enter(qemu_get_current_aio_context(), co);

acb->has_returned = true;
if (acb->rwco.ret != NOT_DONE) {
replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(),
blk_aio_complete_bh, acb);
}

Expand Down Expand Up @@ -1942,11 +1948,11 @@ BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
acb->has_returned = false;

co = qemu_coroutine_create(blk_aio_zone_mgmt_entry, acb);
aio_co_enter(blk_get_aio_context(blk), co);
aio_co_enter(qemu_get_current_aio_context(), co);

acb->has_returned = true;
if (acb->rwco.ret != NOT_DONE) {
replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(),
blk_aio_complete_bh, acb);
}

Expand Down Expand Up @@ -1982,10 +1988,10 @@ BlockAIOCB *blk_aio_zone_append(BlockBackend *blk, int64_t *offset,
acb->has_returned = false;

co = qemu_coroutine_create(blk_aio_zone_append_entry, acb);
aio_co_enter(blk_get_aio_context(blk), co);
aio_co_enter(qemu_get_current_aio_context(), co);
acb->has_returned = true;
if (acb->rwco.ret != NOT_DONE) {
replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(),
blk_aio_complete_bh, acb);
}

Expand Down Expand Up @@ -2434,12 +2440,6 @@ AioContext *blk_get_aio_context(BlockBackend *blk)
return blk->ctx;
}

static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
{
BlockBackendAIOCB *blk_acb = DO_UPCAST(BlockBackendAIOCB, common, acb);
return blk_get_aio_context(blk_acb->blk);
}

int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
Error **errp)
{
Expand Down
10 changes: 5 additions & 5 deletions block/copy-before-write.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,11 +341,11 @@ static void cbw_refresh_filename(BlockDriverState *bs)
bs->file->bs->filename);
}

static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c,
BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
static void GRAPH_RDLOCK
cbw_child_perm(BlockDriverState *bs, BdrvChild *c, BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
{
if (!(role & BDRV_CHILD_FILTERED)) {
/*
Expand Down
6 changes: 4 additions & 2 deletions block/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,7 @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
return spec_info;
}

static int
static int GRAPH_RDLOCK
block_crypto_amend_prepare(BlockDriverState *bs, Error **errp)
{
BlockCrypto *crypto = bs->opaque;
Expand All @@ -793,7 +793,7 @@ block_crypto_amend_prepare(BlockDriverState *bs, Error **errp)
return ret;
}

static void
static void GRAPH_RDLOCK
block_crypto_amend_cleanup(BlockDriverState *bs)
{
BlockCrypto *crypto = bs->opaque;
Expand Down Expand Up @@ -841,6 +841,8 @@ block_crypto_amend_options_luks(BlockDriverState *bs,
QCryptoBlockAmendOptions *amend_options = NULL;
int ret = -EINVAL;

assume_graph_lock(); /* FIXME */

assert(crypto);
assert(crypto->block);

Expand Down
26 changes: 19 additions & 7 deletions block/graph-lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,17 +163,29 @@ void bdrv_graph_wrlock(BlockDriverState *bs)
void bdrv_graph_wrunlock(void)
{
GLOBAL_STATE_CODE();
QEMU_LOCK_GUARD(&aio_context_list_lock);
assert(qatomic_read(&has_writer));

WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) {
/*
* No need for memory barriers, this works in pair with
* the slow path of rdlock() and both take the lock.
*/
qatomic_store_release(&has_writer, 0);

/* Wake up all coroutines that are waiting to read the graph */
qemu_co_enter_all(&reader_queue, &aio_context_list_lock);
}

/*
* No need for memory barriers, this works in pair with
* the slow path of rdlock() and both take the lock.
* Run any BHs that were scheduled during the wrlock section and that
* callers might expect to have finished (in particular, this is important
* for bdrv_schedule_unref()).
*
* Do this only after restarting coroutines so that nested event loops in
* BHs don't deadlock if their condition relies on the coroutine making
* progress.
*/
qatomic_store_release(&has_writer, 0);

/* Wake up all coroutine that are waiting to read the graph */
qemu_co_enter_all(&reader_queue, &aio_context_list_lock);
aio_bh_poll(qemu_get_aio_context());
}

void coroutine_fn bdrv_graph_co_rdlock(void)
Expand Down
23 changes: 8 additions & 15 deletions block/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -2950,25 +2950,18 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
/**************************************************************/
/* async I/Os */

/**
* Synchronously cancels an acb. Must be called with the BQL held and the acb
* must be processed with the BQL held too (IOThreads are not allowed).
*
* Use bdrv_aio_cancel_async() instead when possible.
*/
void bdrv_aio_cancel(BlockAIOCB *acb)
{
IO_CODE();
GLOBAL_STATE_CODE();
qemu_aio_ref(acb);
bdrv_aio_cancel_async(acb);
while (acb->refcnt > 1) {
if (acb->aiocb_info->get_aio_context) {
aio_poll(acb->aiocb_info->get_aio_context(acb), true);
} else if (acb->bs) {
/* qemu_aio_ref and qemu_aio_unref are not thread-safe, so
* assert that we're not using an I/O thread. Thread-safe
* code should use bdrv_aio_cancel_async exclusively.
*/
assert(bdrv_get_aio_context(acb->bs) == qemu_get_aio_context());
aio_poll(bdrv_get_aio_context(acb->bs), true);
} else {
abort();
}
}
AIO_WAIT_WHILE_UNLOCKED(NULL, acb->refcnt > 1);
qemu_aio_unref(acb);
}

Expand Down
8 changes: 8 additions & 0 deletions block/mirror.c
Original file line number Diff line number Diff line change
Expand Up @@ -702,8 +702,12 @@ static int mirror_exit_common(Job *job)
* mirror_top_bs from now on, so keep it drained. */
bdrv_drained_begin(mirror_top_bs);
bs_opaque->stop = true;

bdrv_graph_rdlock_main_loop();
bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
&error_abort);
bdrv_graph_rdunlock_main_loop();

if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) {
BlockDriverState *backing = s->is_none_mode ? src : s->base;
BlockDriverState *unfiltered_target = bdrv_skip_filters(target_bs);
Expand Down Expand Up @@ -1670,6 +1674,8 @@ static BlockJob *mirror_start_job(
uint64_t target_perms, target_shared_perms;
int ret;

GLOBAL_STATE_CODE();

if (granularity == 0) {
granularity = bdrv_get_default_bitmap_granularity(target);
}
Expand Down Expand Up @@ -1906,8 +1912,10 @@ static BlockJob *mirror_start_job(
}

bs_opaque->stop = true;
bdrv_graph_rdlock_main_loop();
bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
&error_abort);
bdrv_graph_rdunlock_main_loop();
bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);

bdrv_unref(mirror_top_bs);
Expand Down

0 comments on commit 1738b8c

Please sign in to comment.