xref: /qemu/block/blkreplay.c (revision 1f051dcb)
163785678SPavel Dovgalyuk /*
263785678SPavel Dovgalyuk  * Block protocol for record/replay
363785678SPavel Dovgalyuk  *
463785678SPavel Dovgalyuk  * Copyright (c) 2010-2016 Institute for System Programming
563785678SPavel Dovgalyuk  *                         of the Russian Academy of Sciences.
663785678SPavel Dovgalyuk  *
763785678SPavel Dovgalyuk  * This work is licensed under the terms of the GNU GPL, version 2 or later.
863785678SPavel Dovgalyuk  * See the COPYING file in the top-level directory.
963785678SPavel Dovgalyuk  *
1063785678SPavel Dovgalyuk  */
1163785678SPavel Dovgalyuk 
1263785678SPavel Dovgalyuk #include "qemu/osdep.h"
130b8fa32fSMarkus Armbruster #include "qemu/module.h"
14e2c1c34fSMarkus Armbruster #include "block/block-io.h"
1563785678SPavel Dovgalyuk #include "block/block_int.h"
1663785678SPavel Dovgalyuk #include "sysemu/replay.h"
1763785678SPavel Dovgalyuk #include "qapi/error.h"
1863785678SPavel Dovgalyuk 
1963785678SPavel Dovgalyuk typedef struct Request {
2063785678SPavel Dovgalyuk     Coroutine *co;
2163785678SPavel Dovgalyuk     QEMUBH *bh;
2263785678SPavel Dovgalyuk } Request;
2363785678SPavel Dovgalyuk 
blkreplay_open(BlockDriverState * bs,QDict * options,int flags,Error ** errp)2463785678SPavel Dovgalyuk static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
2563785678SPavel Dovgalyuk                           Error **errp)
2663785678SPavel Dovgalyuk {
2763785678SPavel Dovgalyuk     int ret;
2863785678SPavel Dovgalyuk 
2963785678SPavel Dovgalyuk     /* Open the image file */
3083930780SVladimir Sementsov-Ogievskiy     ret = bdrv_open_file_child(NULL, options, "image", bs, errp);
3183930780SVladimir Sementsov-Ogievskiy     if (ret < 0) {
3263785678SPavel Dovgalyuk         goto fail;
3363785678SPavel Dovgalyuk     }
3463785678SPavel Dovgalyuk 
35228345bfSMax Reitz     bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
36228345bfSMax Reitz     bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED;
37228345bfSMax Reitz 
3863785678SPavel Dovgalyuk     ret = 0;
3963785678SPavel Dovgalyuk fail:
4063785678SPavel Dovgalyuk     return ret;
4163785678SPavel Dovgalyuk }
4263785678SPavel Dovgalyuk 
438ab8140aSKevin Wolf static int64_t coroutine_fn GRAPH_RDLOCK
blkreplay_co_getlength(BlockDriverState * bs)448ab8140aSKevin Wolf blkreplay_co_getlength(BlockDriverState *bs)
4563785678SPavel Dovgalyuk {
46c86422c5SEmanuele Giuseppe Esposito     return bdrv_co_getlength(bs->file->bs);
4763785678SPavel Dovgalyuk }
4863785678SPavel Dovgalyuk 
4963785678SPavel Dovgalyuk /* This bh is used for synchronization of return from coroutines.
5063785678SPavel Dovgalyuk    It continues yielded coroutine which then finishes its execution.
5163785678SPavel Dovgalyuk    BH is called adjusted to some replay checkpoint, therefore
5263785678SPavel Dovgalyuk    record and replay will always finish coroutines deterministically.
5363785678SPavel Dovgalyuk */
blkreplay_bh_cb(void * opaque)5463785678SPavel Dovgalyuk static void blkreplay_bh_cb(void *opaque)
5563785678SPavel Dovgalyuk {
5663785678SPavel Dovgalyuk     Request *req = opaque;
571919631eSPaolo Bonzini     aio_co_wake(req->co);
5863785678SPavel Dovgalyuk     qemu_bh_delete(req->bh);
5963785678SPavel Dovgalyuk     g_free(req);
6063785678SPavel Dovgalyuk }
6163785678SPavel Dovgalyuk 
block_request_create(uint64_t reqid,BlockDriverState * bs,Coroutine * co)6263785678SPavel Dovgalyuk static void block_request_create(uint64_t reqid, BlockDriverState *bs,
6363785678SPavel Dovgalyuk                                  Coroutine *co)
6463785678SPavel Dovgalyuk {
6563785678SPavel Dovgalyuk     Request *req = g_new(Request, 1);
6663785678SPavel Dovgalyuk     *req = (Request) {
6763785678SPavel Dovgalyuk         .co = co,
6863785678SPavel Dovgalyuk         .bh = aio_bh_new(bdrv_get_aio_context(bs), blkreplay_bh_cb, req),
6963785678SPavel Dovgalyuk     };
7063785678SPavel Dovgalyuk     replay_block_event(req->bh, reqid);
7163785678SPavel Dovgalyuk }
7263785678SPavel Dovgalyuk 
73b9b10c35SKevin Wolf static int coroutine_fn GRAPH_RDLOCK
blkreplay_co_preadv(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags)74b9b10c35SKevin Wolf blkreplay_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
75b9b10c35SKevin Wolf                     QEMUIOVector *qiov, BdrvRequestFlags flags)
7663785678SPavel Dovgalyuk {
776d0ceb80SPavel Dovgalyuk     uint64_t reqid = blkreplay_next_id();
78a03ef88fSKevin Wolf     int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
7963785678SPavel Dovgalyuk     block_request_create(reqid, bs, qemu_coroutine_self());
8063785678SPavel Dovgalyuk     qemu_coroutine_yield();
8163785678SPavel Dovgalyuk 
8263785678SPavel Dovgalyuk     return ret;
8363785678SPavel Dovgalyuk }
8463785678SPavel Dovgalyuk 
85b9b10c35SKevin Wolf static int coroutine_fn GRAPH_RDLOCK
blkreplay_co_pwritev(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags)86b9b10c35SKevin Wolf blkreplay_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
87b9b10c35SKevin Wolf                      QEMUIOVector *qiov, BdrvRequestFlags flags)
8863785678SPavel Dovgalyuk {
896d0ceb80SPavel Dovgalyuk     uint64_t reqid = blkreplay_next_id();
90a03ef88fSKevin Wolf     int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
9163785678SPavel Dovgalyuk     block_request_create(reqid, bs, qemu_coroutine_self());
9263785678SPavel Dovgalyuk     qemu_coroutine_yield();
9363785678SPavel Dovgalyuk 
9463785678SPavel Dovgalyuk     return ret;
9563785678SPavel Dovgalyuk }
9663785678SPavel Dovgalyuk 
97abaf8b75SKevin Wolf static int coroutine_fn GRAPH_RDLOCK
blkreplay_co_pwrite_zeroes(BlockDriverState * bs,int64_t offset,int64_t bytes,BdrvRequestFlags flags)98abaf8b75SKevin Wolf blkreplay_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
99abaf8b75SKevin Wolf                            BdrvRequestFlags flags)
10063785678SPavel Dovgalyuk {
1016d0ceb80SPavel Dovgalyuk     uint64_t reqid = blkreplay_next_id();
102f5a5ca79SManos Pitsidianakis     int ret = bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
10363785678SPavel Dovgalyuk     block_request_create(reqid, bs, qemu_coroutine_self());
10463785678SPavel Dovgalyuk     qemu_coroutine_yield();
10563785678SPavel Dovgalyuk 
10663785678SPavel Dovgalyuk     return ret;
10763785678SPavel Dovgalyuk }
10863785678SPavel Dovgalyuk 
1099a5a1c62SEmanuele Giuseppe Esposito static int coroutine_fn GRAPH_RDLOCK
blkreplay_co_pdiscard(BlockDriverState * bs,int64_t offset,int64_t bytes)1109a5a1c62SEmanuele Giuseppe Esposito blkreplay_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
11163785678SPavel Dovgalyuk {
1126d0ceb80SPavel Dovgalyuk     uint64_t reqid = blkreplay_next_id();
1130b9fd3f4SFam Zheng     int ret = bdrv_co_pdiscard(bs->file, offset, bytes);
11463785678SPavel Dovgalyuk     block_request_create(reqid, bs, qemu_coroutine_self());
11563785678SPavel Dovgalyuk     qemu_coroutine_yield();
11663785678SPavel Dovgalyuk 
11763785678SPavel Dovgalyuk     return ret;
11863785678SPavel Dovgalyuk }
11963785678SPavel Dovgalyuk 
blkreplay_co_flush(BlockDriverState * bs)12088095349SEmanuele Giuseppe Esposito static int coroutine_fn GRAPH_RDLOCK blkreplay_co_flush(BlockDriverState *bs)
12163785678SPavel Dovgalyuk {
1226d0ceb80SPavel Dovgalyuk     uint64_t reqid = blkreplay_next_id();
12363785678SPavel Dovgalyuk     int ret = bdrv_co_flush(bs->file->bs);
12463785678SPavel Dovgalyuk     block_request_create(reqid, bs, qemu_coroutine_self());
12563785678SPavel Dovgalyuk     qemu_coroutine_yield();
12663785678SPavel Dovgalyuk 
12763785678SPavel Dovgalyuk     return ret;
12863785678SPavel Dovgalyuk }
12963785678SPavel Dovgalyuk 
blkreplay_snapshot_goto(BlockDriverState * bs,const char * snapshot_id)1303c6c4348SPavel Dovgalyuk static int blkreplay_snapshot_goto(BlockDriverState *bs,
1313c6c4348SPavel Dovgalyuk                                    const char *snapshot_id)
1323c6c4348SPavel Dovgalyuk {
1331f051dcbSKevin Wolf     BlockDriverState *file_bs;
1341f051dcbSKevin Wolf 
1351f051dcbSKevin Wolf     bdrv_graph_rdlock_main_loop();
1361f051dcbSKevin Wolf     file_bs = bs->file->bs;
1371f051dcbSKevin Wolf     bdrv_graph_rdunlock_main_loop();
1381f051dcbSKevin Wolf 
1391f051dcbSKevin Wolf     return bdrv_snapshot_goto(file_bs, snapshot_id, NULL);
1403c6c4348SPavel Dovgalyuk }
1413c6c4348SPavel Dovgalyuk 
14263785678SPavel Dovgalyuk static BlockDriver bdrv_blkreplay = {
14363785678SPavel Dovgalyuk     .format_name            = "blkreplay",
14463785678SPavel Dovgalyuk     .instance_size          = 0,
1456540fd15SMax Reitz     .is_filter              = true,
14663785678SPavel Dovgalyuk 
1478140e786SFabiano Rosas     .bdrv_open              = blkreplay_open,
14869dca43dSMax Reitz     .bdrv_child_perm        = bdrv_default_perms,
149c86422c5SEmanuele Giuseppe Esposito     .bdrv_co_getlength      = blkreplay_co_getlength,
15063785678SPavel Dovgalyuk 
151e858a970SKevin Wolf     .bdrv_co_preadv         = blkreplay_co_preadv,
152e858a970SKevin Wolf     .bdrv_co_pwritev        = blkreplay_co_pwritev,
15363785678SPavel Dovgalyuk 
1549c21a422SEric Blake     .bdrv_co_pwrite_zeroes  = blkreplay_co_pwrite_zeroes,
155aba76e2fSEric Blake     .bdrv_co_pdiscard       = blkreplay_co_pdiscard,
15663785678SPavel Dovgalyuk     .bdrv_co_flush          = blkreplay_co_flush,
1573c6c4348SPavel Dovgalyuk 
1583c6c4348SPavel Dovgalyuk     .bdrv_snapshot_goto     = blkreplay_snapshot_goto,
15963785678SPavel Dovgalyuk };
16063785678SPavel Dovgalyuk 
bdrv_blkreplay_init(void)16163785678SPavel Dovgalyuk static void bdrv_blkreplay_init(void)
16263785678SPavel Dovgalyuk {
16363785678SPavel Dovgalyuk     bdrv_register(&bdrv_blkreplay);
16463785678SPavel Dovgalyuk }
16563785678SPavel Dovgalyuk 
16663785678SPavel Dovgalyuk block_init(bdrv_blkreplay_init);
167