block: add bdrv_add_before_write_notifier()

The bdrv_add_before_write_notifier() function installs a callback that
is invoked before a write request is processed.  This will be used to
implement copy-on-write point-in-time snapshots where we need to copy
out old data before overwriting it.

Note that BdrvTrackedRequest is moved to block_int.h since it is passed
to .notify() functions.

Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2013-06-24 17:13:10 +02:00 committed by Kevin Wolf
parent 5dae8e5fb8
commit d616b22474
2 changed files with 34 additions and 12 deletions

23
block.c
View File

@ -305,6 +305,7 @@ BlockDriverState *bdrv_new(const char *device_name)
}
bdrv_iostatus_disable(bs);
notifier_list_init(&bs->close_notifiers);
notifier_with_return_list_init(&bs->before_write_notifiers);
return bs;
}
@ -1840,16 +1841,6 @@ int bdrv_commit_all(void)
return 0;
}
struct BdrvTrackedRequest {
BlockDriverState *bs;
int64_t sector_num;
int nb_sectors;
bool is_write;
QLIST_ENTRY(BdrvTrackedRequest) list;
Coroutine *co; /* owner, used for deadlock detection */
CoQueue wait_queue; /* coroutines blocked on this request */
};
/**
* Remove an active request from the tracked requests list
*
@ -2620,7 +2611,11 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
tracked_request_begin(&req, bs, sector_num, nb_sectors, true);
if (flags & BDRV_REQ_ZERO_WRITE) {
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, &req);
if (ret < 0) {
/* Do nothing, write notifier decided to fail this request */
} else if (flags & BDRV_REQ_ZERO_WRITE) {
ret = bdrv_co_do_write_zeroes(bs, sector_num, nb_sectors);
} else {
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
@ -4581,3 +4576,9 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs)
/* Currently BlockDriverState always uses the main loop AioContext */
return qemu_get_aio_context();
}
void bdrv_add_before_write_notifier(BlockDriverState *bs,
NotifierWithReturn *notifier)
{
notifier_with_return_list_add(&bs->before_write_notifiers, notifier);
}

View File

@ -59,7 +59,16 @@
#define BLOCK_OPT_LAZY_REFCOUNTS "lazy_refcounts"
#define BLOCK_OPT_ADAPTER_TYPE "adapter_type"
typedef struct BdrvTrackedRequest BdrvTrackedRequest;
typedef struct BdrvTrackedRequest {
BlockDriverState *bs;
int64_t sector_num;
int nb_sectors;
bool is_write;
QLIST_ENTRY(BdrvTrackedRequest) list;
Coroutine *co; /* owner, used for deadlock detection */
CoQueue wait_queue; /* coroutines blocked on this request */
} BdrvTrackedRequest;
typedef struct BlockIOLimit {
int64_t bps[3];
@ -248,6 +257,9 @@ struct BlockDriverState {
NotifierList close_notifiers;
/* Callback before write request is processed */
NotifierWithReturnList before_write_notifiers;
/* number of in-flight copy-on-read requests */
unsigned int copy_on_read_in_flight;
@ -298,6 +310,15 @@ int get_tmp_filename(char *filename, int size);
void bdrv_set_io_limits(BlockDriverState *bs,
BlockIOLimit *io_limits);
/**
* bdrv_add_before_write_notifier:
*
* Register a callback that is invoked before write requests are processed but
* after any throttling or waiting for overlapping requests.
*/
void bdrv_add_before_write_notifier(BlockDriverState *bs,
NotifierWithReturn *notifier);
/**
* bdrv_get_aio_context:
*