}
bdrv_iostatus_disable(bs);
notifier_list_init(&bs->close_notifiers);
+ notifier_with_return_list_init(&bs->before_write_notifiers);
return bs;
}
{
BlockDriver *drv;
- drv = bdrv_find_protocol(filename);
+ drv = bdrv_find_protocol(filename, true);
if (drv == NULL) {
return -ENOENT;
}
return drv;
}
-BlockDriver *bdrv_find_protocol(const char *filename)
+BlockDriver *bdrv_find_protocol(const char *filename,
+ bool allow_protocol_prefix)
{
BlockDriver *drv1;
char protocol[128];
return drv1;
}
- if (!path_has_protocol(filename)) {
+ if (!path_has_protocol(filename) || !allow_protocol_prefix) {
return bdrv_find_format("file");
}
+
p = strchr(filename, ':');
assert(p != NULL);
len = p - filename;
BlockDriverState *bs;
BlockDriver *drv;
const char *drvname;
+ bool allow_protocol_prefix = false;
int ret;
/* NULL means an empty set of options */
filename = qdict_get_try_str(options, "filename");
} else if (filename && !qdict_haskey(options, "filename")) {
qdict_put(options, "filename", qstring_from_str(filename));
+ allow_protocol_prefix = true;
} else {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't specify 'file' and "
"'filename' options at the same time");
drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR));
qdict_del(options, "driver");
} else if (filename) {
- drv = bdrv_find_protocol(filename);
+ drv = bdrv_find_protocol(filename, allow_protocol_prefix);
+ if (!drv) {
+ qerror_report(ERROR_CLASS_GENERIC_ERROR, "Unknown protocol");
+ }
} else {
qerror_report(ERROR_CLASS_GENERIC_ERROR,
"Must specify either driver or file");
extract_subqdict(options, &file_options, "file.");
ret = bdrv_file_open(&file, filename, file_options,
- bdrv_open_flags(bs, flags));
+ bdrv_open_flags(bs, flags | BDRV_O_UNMAP));
if (ret < 0) {
goto fail;
}
if (local_err != NULL) {
error_propagate(errp, local_err);
} else {
- error_set(errp, QERR_OPEN_FILE_FAILED,
- reopen_state->bs->filename);
+ error_setg(errp, "failed while preparing to reopen image '%s'",
+ reopen_state->bs->filename);
}
goto error;
}
void bdrv_close(BlockDriverState *bs)
{
- bdrv_flush(bs);
if (bs->job) {
block_job_cancel_sync(bs->job);
}
- bdrv_drain_all();
+ bdrv_drain_all(); /* complete I/O */
+ bdrv_flush(bs);
+ bdrv_drain_all(); /* in case flush left pending I/O */
notifier_list_notify(&bs->close_notifiers, bs);
if (bs->drv) {
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
*
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);
return bs->open_flags;
}
-void bdrv_flush_all(void)
+int bdrv_flush_all(void)
{
BlockDriverState *bs;
+ int result = 0;
QTAILQ_FOREACH(bs, &bdrv_states, list) {
- bdrv_flush(bs);
+ int ret = bdrv_flush(bs);
+ if (ret < 0 && !result) {
+ result = ret;
+ }
}
+
+ return result;
+}
+
+int bdrv_has_zero_init_1(BlockDriverState *bs)
+{
+ return 1;
}
int bdrv_has_zero_init(BlockDriverState *bs)
return bs->drv->bdrv_has_zero_init(bs);
}
- return 1;
+ /* safe default */
+ return 0;
}
typedef struct BdrvCoIsAllocatedData {
return;
}
- proto_drv = bdrv_find_protocol(filename);
+ proto_drv = bdrv_find_protocol(filename, true);
if (!proto_drv) {
error_setg(errp, "Unknown protocol '%s'", filename);
return;
/* 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);
+}