Compare commits

...

6 Commits

Author SHA1 Message Date
João Silva
3856675bfe block: Add a thread-pool version of fstat
The fstat call can take a long time to finish when running over
NFS. Add a version of it that runs in the thread pool.

Adapt one of its users, raw_co_get_allocated_file size to use the new
version. That function is called via QMP under the qemu_global_mutex
so it has a large chance of blocking VCPU threads in case it takes too
long to finish.

Reviewed-by: Claudio Fontana <cfontana@suse.de>
Signed-off-by: João Silva <jsilva@suse.de>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-05-24 13:29:59 -03:00
Fabiano Rosas
42c3cecd30 block: Allow bdrv_get_allocated_file_size to run in bdrv context
We're about to move calls to 'fstat' into the thread-pool to avoid
blocking VCPU threads should the system call take too long.

To achieve that we first need to make sure none of its callers is
holding the aio_context lock, otherwise yielding before scheduling the
aiocb handler would result in a deadlock when the qemu_global_mutex is
released and another thread tries to acquire the aio_context.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-05-24 11:18:19 -03:00
75aa05d919 Convert query-named-block-nodes to coroutine
The query-named-block-nodes QMP command can perform time-consuming I/O
(say waiting for an 'fstat' call over NFS). Let's put this QMP handler
in a coroutine so we can move the I/O into the thread-pool in the
subsequent patches.

Signed-off-by: Lin Ma <lma@suse.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-05-24 11:15:34 -03:00
30ed6ada68 Convert query-block to coroutine
The query-block QMP command can perform time-consuming I/O (say
waiting for an 'fstat' call over NFS). Let's put this QMP handler in a
coroutine so we can move the I/O into the thread-pool in the
subsequent patches.

Since qmp_query_block() now expects to be in coroutine context, its
callers need to be converted as well. Convert hmp_nbd_server_start()
and hmp_info_block().

Signed-off-by: Lin Ma <lma@suse.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-05-24 11:14:26 -03:00
Fabiano Rosas
e5e26a1e4b block: Mark bdrv_co_get_allocated_file_size() as mixed
Some callers of this function are about to be converted to use
coroutines, so allow it to be executed both inside and outside a
coroutine.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-05-23 15:14:10 -03:00
Fabiano Rosas
31487818c2 block: Remove bdrv_query_block_node_info
The last call site of this function has been removed by commit
c04d0ab026 ("qemu-img: Let info print block graph").

Reviewed-by: Claudio Fontana <cfontana@suse.de>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-05-23 15:14:10 -03:00
12 changed files with 76 additions and 47 deletions

View File

@@ -227,6 +227,9 @@ typedef struct RawPosixAIOData {
struct {
unsigned long op;
} zone_mgmt;
struct {
struct stat *st;
} fstat;
};
} RawPosixAIOData;
@@ -2644,6 +2647,34 @@ static void raw_close(BlockDriverState *bs)
}
}
static int handle_aiocb_fstat(void *opaque)
{
RawPosixAIOData *aiocb = opaque;
if (fstat(aiocb->aio_fildes, aiocb->fstat.st) < 0) {
return -errno;
}
return 0;
}
static int coroutine_fn raw_co_fstat(BlockDriverState *bs, struct stat *st)
{
BDRVRawState *s = bs->opaque;
RawPosixAIOData acb;
acb = (RawPosixAIOData) {
.bs = bs,
.aio_fildes = s->fd,
.aio_type = QEMU_AIO_FSTAT,
.fstat = {
.st = st,
},
};
return raw_thread_pool_submit(handle_aiocb_fstat, &acb);
}
/**
* Truncates the given regular file @fd to @offset and, when growing, fills the
* new space according to @prealloc.
@@ -2883,11 +2914,14 @@ static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
static int64_t coroutine_fn raw_co_get_allocated_file_size(BlockDriverState *bs)
{
struct stat st;
BDRVRawState *s = bs->opaque;
int ret;
if (fstat(s->fd, &st) < 0) {
return -errno;
ret = raw_co_fstat(bs, &st);
if (ret) {
return ret;
}
return (int64_t)st.st_blocks * 512;
}

View File

@@ -388,7 +388,7 @@ void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, err);
}
void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
void coroutine_fn hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
{
const char *uri = qdict_get_str(qdict, "uri");
bool writable = qdict_get_try_bool(qdict, "writable", false);
@@ -738,7 +738,7 @@ static void print_block_info(Monitor *mon, BlockInfo *info,
}
}
void hmp_info_block(Monitor *mon, const QDict *qdict)
void coroutine_fn hmp_info_block(Monitor *mon, const QDict *qdict)
{
BlockInfoList *block_list, *info;
BlockDeviceInfoList *blockdev_list, *blockdev;

View File

@@ -222,6 +222,26 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs,
return 0;
}
static int64_t bdrv_get_actual_size(BlockDriverState *bs)
{
int64_t size;
AioContext *old_ctx = NULL;
if (qemu_in_coroutine()) {
aio_context_release(bdrv_get_aio_context(bs));
old_ctx = bdrv_co_enter(bs);
}
size = bdrv_get_allocated_file_size(bs);
if (qemu_in_coroutine() && old_ctx) {
bdrv_co_leave(bs, old_ctx);
aio_context_acquire(bdrv_get_aio_context(bs));
}
return size;
}
/**
* Helper function for other query info functions. Store information about @bs
* in @info, setting @errp on error.
@@ -250,7 +270,7 @@ static void bdrv_do_query_node_info(BlockDriverState *bs,
info->filename = g_strdup(bs->filename);
info->format = g_strdup(bdrv_get_format_name(bs));
info->virtual_size = size;
info->actual_size = bdrv_get_allocated_file_size(bs);
info->actual_size = bdrv_get_actual_size(bs);
info->has_actual_size = info->actual_size >= 0;
if (bs->encrypted) {
info->encrypted = true;
@@ -309,33 +329,6 @@ out:
aio_context_release(bdrv_get_aio_context(bs));
}
/**
* bdrv_query_block_node_info:
* @bs: block node to examine
* @p_info: location to store node information
* @errp: location to store error information
*
* Store image information about @bs in @p_info.
*
* @p_info will be set only on success. On error, store error in @errp.
*/
void bdrv_query_block_node_info(BlockDriverState *bs,
BlockNodeInfo **p_info,
Error **errp)
{
BlockNodeInfo *info;
ERRP_GUARD();
info = g_new0(BlockNodeInfo, 1);
bdrv_do_query_node_info(bs, info, errp);
if (*errp) {
qapi_free_BlockNodeInfo(info);
return;
}
*p_info = info;
}
/**
* bdrv_query_image_info:
* @bs: block node to examine
@@ -694,7 +687,7 @@ bdrv_query_bds_stats(BlockDriverState *bs, bool blk_level)
return s;
}
BlockInfoList *qmp_query_block(Error **errp)
BlockInfoList *coroutine_fn qmp_query_block(Error **errp)
{
BlockInfoList *head = NULL, **p_next = &head;
BlockBackend *blk;

View File

@@ -2804,9 +2804,9 @@ void qmp_drive_backup(DriveBackup *backup, Error **errp)
blockdev_do_action(&action, errp);
}
BlockDeviceInfoList *qmp_query_named_block_nodes(bool has_flat,
bool flat,
Error **errp)
BlockDeviceInfoList *coroutine_fn qmp_query_named_block_nodes(bool has_flat,
bool flat,
Error **errp)
{
bool return_flat = has_flat && flat;

View File

@@ -65,6 +65,7 @@ ERST
.help = "show info of one block device or all block devices "
"(-n: show named nodes; -v: show details)",
.cmd = hmp_info_block,
.coroutine = true,
},
SRST

View File

@@ -1432,6 +1432,7 @@ ERST
.params = "nbd_server_start [-a] [-w] host:port",
.help = "serve block devices on the given host and port",
.cmd = hmp_nbd_server_start,
.coroutine = true,
.flags = "p",
},
SRST

View File

@@ -35,7 +35,7 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict);
void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
void coroutine_fn hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
@@ -48,7 +48,7 @@ void hmp_eject(Monitor *mon, const QDict *qdict);
void hmp_qemu_io(Monitor *mon, const QDict *qdict);
void hmp_info_block(Monitor *mon, const QDict *qdict);
void coroutine_fn hmp_info_block(Monitor *mon, const QDict *qdict);
void hmp_info_blockstats(Monitor *mon, const QDict *qdict);
void hmp_info_block_jobs(Monitor *mon, const QDict *qdict);
void hmp_info_snapshots(Monitor *mon, const QDict *qdict);

View File

@@ -87,7 +87,7 @@ int64_t co_wrapper_mixed_bdrv_rdlock bdrv_getlength(BlockDriverState *bs);
int64_t coroutine_fn GRAPH_RDLOCK
bdrv_co_get_allocated_file_size(BlockDriverState *bs);
int64_t co_wrapper_bdrv_rdlock
int64_t co_wrapper_mixed_bdrv_rdlock
bdrv_get_allocated_file_size(BlockDriverState *bs);
BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts,

View File

@@ -36,9 +36,6 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
int bdrv_query_snapshot_info_list(BlockDriverState *bs,
SnapshotInfoList **p_list,
Error **errp);
void bdrv_query_block_node_info(BlockDriverState *bs,
BlockNodeInfo **p_info,
Error **errp);
void bdrv_query_image_info(BlockDriverState *bs,
ImageInfo **p_info,
bool flat,

View File

@@ -31,6 +31,7 @@
#define QEMU_AIO_ZONE_REPORT 0x0100
#define QEMU_AIO_ZONE_MGMT 0x0200
#define QEMU_AIO_ZONE_APPEND 0x0400
#define QEMU_AIO_FSTAT 0x0800
#define QEMU_AIO_TYPE_MASK \
(QEMU_AIO_READ | \
QEMU_AIO_WRITE | \
@@ -42,7 +43,8 @@
QEMU_AIO_TRUNCATE | \
QEMU_AIO_ZONE_REPORT | \
QEMU_AIO_ZONE_MGMT | \
QEMU_AIO_ZONE_APPEND)
QEMU_AIO_ZONE_APPEND | \
QEMU_AIO_FSTAT)
/* AIO flags */
#define QEMU_AIO_MISALIGNED 0x1000

View File

@@ -838,7 +838,7 @@
# }
##
{ 'command': 'query-block', 'returns': ['BlockInfo'],
'allow-preconfig': true }
'allow-preconfig': true, 'coroutine': true }
##
# @BlockDeviceTimedStats:
@@ -1972,7 +1972,8 @@
{ 'command': 'query-named-block-nodes',
'returns': [ 'BlockDeviceInfo' ],
'data': { '*flat': 'bool' },
'allow-preconfig': true }
'allow-preconfig': true,
'coroutine': true}
##
# @XDbgBlockGraphNodeType:

View File

@@ -74,7 +74,7 @@
'*tls-creds': 'str',
'*tls-authz': 'str',
'*max-connections': 'uint32' },
'allow-preconfig': true }
'allow-preconfig': true, 'coroutine': true }
##
# @BlockExportOptionsNbdBase: