mirror of
https://github.com/qemu/qemu.git
synced 2026-07-08 17:46:10 +00:00
qemu-io: Add 'aio_discard' command
Testing interactions between multiple requests that include discard requests require that qemu-io can do the discard asynchronously, like it already does for reads and writes. To this effect, add an 'aio_discard' command. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Message-ID: <20260427170520.101242-3-kwolf@redhat.com> Reviewed-by: Denis V. Lunev <den@openvz.org> Tested-by: Denis V. Lunev <den@openvz.org> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
115
qemu-io-cmds.c
115
qemu-io-cmds.c
@@ -2218,6 +2218,120 @@ static int discard_f(BlockBackend *blk, int argc, char **argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void aio_discard_help(void)
|
||||||
|
{
|
||||||
|
printf(
|
||||||
|
"\n"
|
||||||
|
" asynchronously discards a range of bytes from the given offset\n"
|
||||||
|
"\n"
|
||||||
|
" Example:\n"
|
||||||
|
" 'aio_discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
|
||||||
|
"\n"
|
||||||
|
" Discards a segment of the currently open file.\n"
|
||||||
|
" -C, -- report statistics in a machine parsable format\n"
|
||||||
|
" -q, -- quiet mode, do not show I/O statistics\n"
|
||||||
|
" The discard is performed asynchronously and the aio_flush command must be\n"
|
||||||
|
" used to ensure all outstanding aio requests have been completed.\n"
|
||||||
|
" Note that due to its asynchronous nature, this command will be\n"
|
||||||
|
" considered successful once the request is submitted, independently\n"
|
||||||
|
" of potential I/O errors.\n"
|
||||||
|
"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aio_discard_f(BlockBackend *blk, int argc, char **argv);
|
||||||
|
|
||||||
|
static const cmdinfo_t aio_discard_cmd = {
|
||||||
|
.name = "aio_discard",
|
||||||
|
.cfunc = aio_discard_f,
|
||||||
|
.perm = BLK_PERM_WRITE,
|
||||||
|
.argmin = 2,
|
||||||
|
.argmax = -1,
|
||||||
|
.args = "[-Cq] off len",
|
||||||
|
.oneline = "asynchronously discards a number of bytes",
|
||||||
|
.help = aio_discard_help,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void aio_discard_done(void *opaque, int ret)
|
||||||
|
{
|
||||||
|
struct aio_ctx *ctx = opaque;
|
||||||
|
struct timespec t2;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &t2);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
printf("aio_discard failed: %s\n", strerror(-ret));
|
||||||
|
block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
|
||||||
|
|
||||||
|
if (ctx->qflag) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finally, report back -- -C gives a parsable format */
|
||||||
|
t2 = tsub(t2, ctx->t1);
|
||||||
|
print_report("discarded ", &t2, ctx->offset, ctx->qiov.size,
|
||||||
|
ctx->qiov.size, 1, ctx->Cflag);
|
||||||
|
out:
|
||||||
|
g_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aio_discard_f(BlockBackend *blk, int argc, char **argv)
|
||||||
|
{
|
||||||
|
int c, ret;
|
||||||
|
int64_t count;
|
||||||
|
struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
|
||||||
|
|
||||||
|
ctx->blk = blk;
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "Cq")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'C':
|
||||||
|
ctx->Cflag = true;
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
ctx->qflag = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_free(ctx);
|
||||||
|
qemuio_command_usage(&aio_discard_cmd);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind != argc - 2) {
|
||||||
|
g_free(ctx);
|
||||||
|
qemuio_command_usage(&aio_discard_cmd);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->offset = cvtnum(argv[optind]);
|
||||||
|
if (ctx->offset < 0) {
|
||||||
|
ret = ctx->offset;
|
||||||
|
print_cvtnum_err(ret, argv[optind]);
|
||||||
|
g_free(ctx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
optind++;
|
||||||
|
|
||||||
|
count = cvtnum(argv[optind]);
|
||||||
|
if (count < 0) {
|
||||||
|
print_cvtnum_err(count, argv[optind]);
|
||||||
|
g_free(ctx);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ctx->t1);
|
||||||
|
ctx->qiov.size = count;
|
||||||
|
block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
|
||||||
|
BLOCK_ACCT_UNMAP);
|
||||||
|
blk_aio_pdiscard(blk, ctx->offset, count, aio_discard_done, ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int alloc_f(BlockBackend *blk, int argc, char **argv)
|
static int alloc_f(BlockBackend *blk, int argc, char **argv)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs = blk_bs(blk);
|
BlockDriverState *bs = blk_bs(blk);
|
||||||
@@ -2800,6 +2914,7 @@ static void __attribute((constructor)) init_qemuio_commands(void)
|
|||||||
qemuio_add_command(&length_cmd);
|
qemuio_add_command(&length_cmd);
|
||||||
qemuio_add_command(&info_cmd);
|
qemuio_add_command(&info_cmd);
|
||||||
qemuio_add_command(&discard_cmd);
|
qemuio_add_command(&discard_cmd);
|
||||||
|
qemuio_add_command(&aio_discard_cmd);
|
||||||
qemuio_add_command(&alloc_cmd);
|
qemuio_add_command(&alloc_cmd);
|
||||||
qemuio_add_command(&map_cmd);
|
qemuio_add_command(&map_cmd);
|
||||||
qemuio_add_command(&reopen_cmd);
|
qemuio_add_command(&reopen_cmd);
|
||||||
|
|||||||
Reference in New Issue
Block a user