@samitouri / QOSamiQemu / commits / 7f8466e2ce

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>

Kevin Wolf committed Apr 27, 2026 at 19:05 UTC 7f8466e2ce620e3c6a6e2f32d616367174d4dbe9
1 file changed +115
qemu-io-cmds.c
+115
@@ -2218,6 +2218,120 @@ static int discard_f(BlockBackend *blk, int argc, char **argv)
2218 return 0;
2219 }
2220
2221 +static void aio_discard_help(void)
2222 +{
2223 + printf(
2224 +"\n"
2225 +" asynchronously discards a range of bytes from the given offset\n"
2226 +"\n"
2227 +" Example:\n"
2228 +" 'aio_discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
2229 +"\n"
2230 +" Discards a segment of the currently open file.\n"
2231 +" -C, -- report statistics in a machine parsable format\n"
2232 +" -q, -- quiet mode, do not show I/O statistics\n"
2233 +" The discard is performed asynchronously and the aio_flush command must be\n"
2234 +" used to ensure all outstanding aio requests have been completed.\n"
2235 +" Note that due to its asynchronous nature, this command will be\n"
2236 +" considered successful once the request is submitted, independently\n"
2237 +" of potential I/O errors.\n"
2238 +"\n");
2239 +}
2240 +
2241 +static int aio_discard_f(BlockBackend *blk, int argc, char **argv);
2242 +
2243 +static const cmdinfo_t aio_discard_cmd = {
2244 + .name = "aio_discard",
2245 + .cfunc = aio_discard_f,
2246 + .perm = BLK_PERM_WRITE,
2247 + .argmin = 2,
2248 + .argmax = -1,
2249 + .args = "[-Cq] off len",
2250 + .oneline = "asynchronously discards a number of bytes",
2251 + .help = aio_discard_help,
2252 +};
2253 +
2254 +static void aio_discard_done(void *opaque, int ret)
2255 +{
2256 + struct aio_ctx *ctx = opaque;
2257 + struct timespec t2;
2258 +
2259 + clock_gettime(CLOCK_MONOTONIC, &t2);
2260 +
2261 + if (ret < 0) {
2262 + printf("aio_discard failed: %s\n", strerror(-ret));
2263 + block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct);
2264 + goto out;
2265 + }
2266 +
2267 + block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
2268 +
2269 + if (ctx->qflag) {
2270 + goto out;
2271 + }
2272 +
2273 + /* Finally, report back -- -C gives a parsable format */
2274 + t2 = tsub(t2, ctx->t1);
2275 + print_report("discarded ", &t2, ctx->offset, ctx->qiov.size,
2276 + ctx->qiov.size, 1, ctx->Cflag);
2277 +out:
2278 + g_free(ctx);
2279 +}
2280 +
2281 +static int aio_discard_f(BlockBackend *blk, int argc, char **argv)
2282 +{
2283 + int c, ret;
2284 + int64_t count;
2285 + struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
2286 +
2287 + ctx->blk = blk;
2288 +
2289 + while ((c = getopt(argc, argv, "Cq")) != -1) {
2290 + switch (c) {
2291 + case 'C':
2292 + ctx->Cflag = true;
2293 + break;
2294 + case 'q':
2295 + ctx->qflag = true;
2296 + break;
2297 + default:
2298 + g_free(ctx);
2299 + qemuio_command_usage(&aio_discard_cmd);
2300 + return -EINVAL;
2301 + }
2302 + }
2303 +
2304 + if (optind != argc - 2) {
2305 + g_free(ctx);
2306 + qemuio_command_usage(&aio_discard_cmd);
2307 + return -EINVAL;
2308 + }
2309 +
2310 + ctx->offset = cvtnum(argv[optind]);
2311 + if (ctx->offset < 0) {
2312 + ret = ctx->offset;
2313 + print_cvtnum_err(ret, argv[optind]);
2314 + g_free(ctx);
2315 + return ret;
2316 + }
2317 + optind++;
2318 +
2319 + count = cvtnum(argv[optind]);
2320 + if (count < 0) {
2321 + print_cvtnum_err(count, argv[optind]);
2322 + g_free(ctx);
2323 + return count;
2324 + }
2325 +
2326 + clock_gettime(CLOCK_MONOTONIC, &ctx->t1);
2327 + ctx->qiov.size = count;
2328 + block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
2329 + BLOCK_ACCT_UNMAP);
2330 + blk_aio_pdiscard(blk, ctx->offset, count, aio_discard_done, ctx);
2331 +
2332 + return 0;
2333 +}
2334 +
2335 static int alloc_f(BlockBackend *blk, int argc, char **argv)
2336 {
2337 BlockDriverState *bs = blk_bs(blk);
@@ -2800,6 +2914,7 @@ static void __attribute((constructor)) init_qemuio_commands(void)
2914 qemuio_add_command(&length_cmd);
2915 qemuio_add_command(&info_cmd);
2916 qemuio_add_command(&discard_cmd);
2917 + qemuio_add_command(&aio_discard_cmd);
2918 qemuio_add_command(&alloc_cmd);
2919 qemuio_add_command(&map_cmd);
2920 qemuio_add_command(&reopen_cmd);