X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=block.c;h=a387c1ad684a34208620e723004374880bda5027;hb=bc72ad67543f5c5d39c005ff0ca72da37642a1fb;hp=4ad663d3fae8e75e4c3eeddd5f6fc516bc8b3554;hpb=4ceb193d30fe9b1cda0dc73bddb8051659926fb9;p=qemu.git diff --git a/block.c b/block.c index 4ad663d3f..a387c1ad6 100644 --- a/block.c +++ b/block.c @@ -99,9 +99,6 @@ static QTAILQ_HEAD(, BlockDriverState) bdrv_states = static QLIST_HEAD(, BlockDriver) bdrv_drivers = QLIST_HEAD_INITIALIZER(bdrv_drivers); -/* The device to use for VM snapshots */ -static BlockDriverState *bs_snapshots; - /* If non-zero, use only whitelisted block drivers */ static int use_bdrv_whitelist; @@ -130,11 +127,11 @@ void bdrv_io_limits_disable(BlockDriverState *bs) { bs->io_limits_enabled = false; - while (qemu_co_queue_next(&bs->throttled_reqs)); + do {} while (qemu_co_enter_next(&bs->throttled_reqs)); if (bs->block_timer) { - qemu_del_timer(bs->block_timer); - qemu_free_timer(bs->block_timer); + timer_del(bs->block_timer); + timer_free(bs->block_timer); bs->block_timer = NULL; } @@ -146,13 +143,12 @@ static void bdrv_block_timer(void *opaque) { BlockDriverState *bs = opaque; - qemu_co_queue_next(&bs->throttled_reqs); + qemu_co_enter_next(&bs->throttled_reqs); } void bdrv_io_limits_enable(BlockDriverState *bs) { - qemu_co_queue_init(&bs->throttled_reqs); - bs->block_timer = qemu_new_timer_ns(vm_clock, bdrv_block_timer, bs); + bs->block_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, bdrv_block_timer, bs); bs->io_limits_enabled = true; } @@ -184,8 +180,8 @@ static void bdrv_io_limits_intercept(BlockDriverState *bs, */ while (bdrv_exceed_io_limits(bs, nb_sectors, is_write, &wait_time)) { - qemu_mod_timer(bs->block_timer, - wait_time + qemu_get_clock_ns(vm_clock)); + timer_mod(bs->block_timer, + wait_time + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); qemu_co_queue_wait_insert_head(&bs->throttled_reqs); } @@ -308,6 +304,8 @@ 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); + qemu_co_queue_init(&bs->throttled_reqs); return bs; } @@ -328,28 +326,40 @@ BlockDriver *bdrv_find_format(const char *format_name) return NULL; } -static int bdrv_is_whitelisted(BlockDriver *drv) +static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) { - static const char *whitelist[] = { - CONFIG_BDRV_WHITELIST + static const char *whitelist_rw[] = { + CONFIG_BDRV_RW_WHITELIST + }; + static const char *whitelist_ro[] = { + CONFIG_BDRV_RO_WHITELIST }; const char **p; - if (!whitelist[0]) + if (!whitelist_rw[0] && !whitelist_ro[0]) { return 1; /* no whitelist, anything goes */ + } - for (p = whitelist; *p; p++) { + for (p = whitelist_rw; *p; p++) { if (!strcmp(drv->format_name, *p)) { return 1; } } + if (read_only) { + for (p = whitelist_ro; *p; p++) { + if (!strcmp(drv->format_name, *p)) { + return 1; + } + } + } return 0; } -BlockDriver *bdrv_find_whitelisted_format(const char *format_name) +BlockDriver *bdrv_find_whitelisted_format(const char *format_name, + bool read_only) { BlockDriver *drv = bdrv_find_format(format_name); - return drv && bdrv_is_whitelisted(drv) ? drv : NULL; + return drv && bdrv_is_whitelisted(drv, read_only) ? drv : NULL; } typedef struct CreateCo { @@ -407,7 +417,7 @@ int bdrv_create_file(const char* filename, QEMUOptionParameter *options) { BlockDriver *drv; - drv = bdrv_find_protocol(filename); + drv = bdrv_find_protocol(filename, true); if (drv == NULL) { return -ENOENT; } @@ -472,7 +482,8 @@ static BlockDriver *find_hdev_driver(const char *filename) 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]; @@ -493,9 +504,10 @@ BlockDriver *bdrv_find_protocol(const char *filename) 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; @@ -667,21 +679,23 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags) * Removes all processed options from *options. */ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, - const char *filename, QDict *options, - int flags, BlockDriver *drv) + QDict *options, int flags, BlockDriver *drv) { int ret, open_flags; + const char *filename; assert(drv != NULL); assert(bs->file == NULL); assert(options != NULL && bs->options != options); - trace_bdrv_open_common(bs, filename, flags, drv->format_name); - - if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) { - return -ENOTSUP; + if (file != NULL) { + filename = file->filename; + } else { + filename = qdict_get_try_str(options, "filename"); } + trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name); + /* bdrv_open() with directly using a protocol as drv. This layer is already * opened, so assign it to bs (while file becomes a closed BlockDriverState) * and return immediately. */ @@ -692,9 +706,16 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, bs->open_flags = flags; bs->buffer_alignment = 512; + bs->zero_beyond_eof = true; + open_flags = bdrv_open_flags(bs, flags); + bs->read_only = !(open_flags & BDRV_O_RDWR); + + if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) { + return -ENOTSUP; + } assert(bs->copy_on_read == 0); /* bdrv_new() and bdrv_close() make it so */ - if ((flags & BDRV_O_RDWR) && (flags & BDRV_O_COPY_ON_READ)) { + if (!bs->read_only && (flags & BDRV_O_COPY_ON_READ)) { bdrv_enable_copy_on_read(bs); } @@ -708,16 +729,20 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, bs->opaque = g_malloc0(drv->instance_size); bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB); - open_flags = bdrv_open_flags(bs, flags); - - bs->read_only = !(open_flags & BDRV_O_RDWR); /* Open the image, either directly or using a protocol */ if (drv->bdrv_file_open) { assert(file == NULL); assert(drv->bdrv_parse_filename || filename != NULL); - ret = drv->bdrv_file_open(bs, filename, options, open_flags); + ret = drv->bdrv_file_open(bs, options, open_flags); } else { + if (file == NULL) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't use '%s' as a " + "block driver for the protocol level", + drv->format_name); + ret = -EINVAL; + goto free_and_fail; + } assert(file != NULL); bs->file = file; ret = drv->bdrv_open(bs, options, open_flags); @@ -762,6 +787,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, BlockDriverState *bs; BlockDriver *drv; const char *drvname; + bool allow_protocol_prefix = false; int ret; /* NULL means an empty set of options */ @@ -773,13 +799,29 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, bs->options = options; options = qdict_clone_shallow(options); + /* Fetch the file name from the options QDict if necessary */ + if (!filename) { + 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"); + ret = -EINVAL; + goto fail; + } + /* Find the right block driver */ drvname = qdict_get_try_str(options, "driver"); if (drvname) { - drv = bdrv_find_whitelisted_format(drvname); + 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"); @@ -801,6 +843,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, ret = -EINVAL; goto fail; } + qdict_del(options, "filename"); } else if (!drv->bdrv_parse_filename && !filename) { qerror_report(ERROR_CLASS_GENERIC_ERROR, "The '%s' block driver requires a file name", @@ -809,7 +852,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, goto fail; } - ret = bdrv_open_common(bs, NULL, filename, options, flags, drv); + ret = bdrv_open_common(bs, NULL, options, flags, drv); if (ret < 0) { goto fail; } @@ -838,18 +881,35 @@ fail: return ret; } -int bdrv_open_backing_file(BlockDriverState *bs) +/* + * Opens the backing file for a BlockDriverState if not yet open + * + * options is a QDict of options to pass to the block drivers, or NULL for an + * empty set of options. The reference to the QDict is transferred to this + * function (even on failure), so if the caller intends to reuse the dictionary, + * it needs to use QINCREF() before calling bdrv_file_open. + */ +int bdrv_open_backing_file(BlockDriverState *bs, QDict *options) { char backing_filename[PATH_MAX]; int back_flags, ret; BlockDriver *back_drv = NULL; if (bs->backing_hd != NULL) { + QDECREF(options); return 0; } + /* NULL means an empty set of options */ + if (options == NULL) { + options = qdict_new(); + } + bs->open_flags &= ~BDRV_O_NO_BACKING; - if (bs->backing_file[0] == '\0') { + if (qdict_haskey(options, "file.filename")) { + backing_filename[0] = '\0'; + } else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) { + QDECREF(options); return 0; } @@ -864,7 +924,8 @@ int bdrv_open_backing_file(BlockDriverState *bs) /* backing files always opened read-only */ back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT); - ret = bdrv_open(bs->backing_hd, backing_filename, NULL, + ret = bdrv_open(bs->backing_hd, + *backing_filename ? backing_filename : NULL, options, back_flags, back_drv); if (ret < 0) { bdrv_delete(bs->backing_hd); @@ -910,6 +971,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, char tmp_filename[PATH_MAX + 1]; BlockDriverState *file = NULL; QDict *file_options = NULL; + const char *drvname; /* NULL means an empty set of options */ if (options == NULL) { @@ -993,12 +1055,18 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, 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; } /* Find the right image format driver */ + drvname = qdict_get_try_str(options, "driver"); + if (drvname) { + drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR)); + qdict_del(options, "driver"); + } + if (!drv) { ret = find_image_format(file, filename, &drv); } @@ -1008,7 +1076,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, } /* Open the image */ - ret = bdrv_open_common(bs, file, filename, options, flags, drv); + ret = bdrv_open_common(bs, file, options, flags, drv); if (ret < 0) { goto unlink_and_fail; } @@ -1020,7 +1088,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, /* If there is a backing file, use it */ if ((flags & BDRV_O_NO_BACKING) == 0) { - ret = bdrv_open_backing_file(bs); + QDict *backing_options; + + extract_subqdict(options, &backing_options, "backing."); + ret = bdrv_open_backing_file(bs, backing_options); if (ret < 0) { goto close_and_fail; } @@ -1236,8 +1307,8 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, 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; } @@ -1302,17 +1373,15 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state) 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) { - if (bs == bs_snapshots) { - bs_snapshots = NULL; - } if (bs->backing_hd) { bdrv_delete(bs->backing_hd); bs->backing_hd = NULL; @@ -1334,6 +1403,7 @@ void bdrv_close(BlockDriverState *bs) bs->valid_key = 0; bs->sg = 0; bs->growable = 0; + bs->zero_beyond_eof = false; QDECREF(bs->options); bs->options = NULL; @@ -1360,6 +1430,35 @@ void bdrv_close_all(void) } } +/* Check if any requests are in-flight (including throttled requests) */ +static bool bdrv_requests_pending(BlockDriverState *bs) +{ + if (!QLIST_EMPTY(&bs->tracked_requests)) { + return true; + } + if (!qemu_co_queue_empty(&bs->throttled_reqs)) { + return true; + } + if (bs->file && bdrv_requests_pending(bs->file)) { + return true; + } + if (bs->backing_hd && bdrv_requests_pending(bs->backing_hd)) { + return true; + } + return false; +} + +static bool bdrv_requests_pending_all(void) +{ + BlockDriverState *bs; + QTAILQ_FOREACH(bs, &bdrv_states, list) { + if (bdrv_requests_pending(bs)) { + return true; + } + } + return false; +} + /* * Wait for pending requests to complete across all BlockDriverStates * @@ -1374,27 +1473,22 @@ void bdrv_close_all(void) */ void bdrv_drain_all(void) { + /* Always run first iteration so any pending completion BHs run */ + bool busy = true; BlockDriverState *bs; - bool busy; - - do { - busy = qemu_aio_wait(); + while (busy) { /* FIXME: We do not have timer support here, so this is effectively * a busy wait. */ QTAILQ_FOREACH(bs, &bdrv_states, list) { - if (!qemu_co_queue_empty(&bs->throttled_reqs)) { - qemu_co_queue_restart_all(&bs->throttled_reqs); + while (qemu_co_enter_next(&bs->throttled_reqs)) { busy = true; } } - } while (busy); - /* If requests are still pending there is a bug somewhere */ - QTAILQ_FOREACH(bs, &bdrv_states, list) { - assert(QLIST_EMPTY(&bs->tracked_requests)); - assert(qemu_co_queue_empty(&bs->throttled_reqs)); + busy = bdrv_requests_pending_all(); + busy |= aio_poll(qemu_get_aio_context(), busy); } } @@ -1539,12 +1633,11 @@ void bdrv_delete(BlockDriverState *bs) assert(!bs->job); assert(!bs->in_use); + bdrv_close(bs); + /* remove from list, if necessary */ bdrv_make_anon(bs); - bdrv_close(bs); - - assert(bs != bs_snapshots); g_free(bs); } @@ -1588,9 +1681,6 @@ void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops, { bs->dev_ops = ops; bs->dev_opaque = opaque; - if (bdrv_dev_has_removable_media(bs) && bs == bs_snapshots) { - bs_snapshots = NULL; - } } void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv, @@ -1792,16 +1882,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 * @@ -2115,6 +2195,7 @@ typedef struct RwCo { QEMUIOVector *qiov; bool is_write; int ret; + BdrvRequestFlags flags; } RwCo; static void coroutine_fn bdrv_rw_co_entry(void *opaque) @@ -2123,10 +2204,12 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque) if (!rwco->is_write) { rwco->ret = bdrv_co_do_readv(rwco->bs, rwco->sector_num, - rwco->nb_sectors, rwco->qiov, 0); + rwco->nb_sectors, rwco->qiov, + rwco->flags); } else { rwco->ret = bdrv_co_do_writev(rwco->bs, rwco->sector_num, - rwco->nb_sectors, rwco->qiov, 0); + rwco->nb_sectors, rwco->qiov, + rwco->flags); } } @@ -2134,7 +2217,8 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque) * Process a vectored synchronous request using coroutines */ static int bdrv_rwv_co(BlockDriverState *bs, int64_t sector_num, - QEMUIOVector *qiov, bool is_write) + QEMUIOVector *qiov, bool is_write, + BdrvRequestFlags flags) { Coroutine *co; RwCo rwco = { @@ -2144,6 +2228,7 @@ static int bdrv_rwv_co(BlockDriverState *bs, int64_t sector_num, .qiov = qiov, .is_write = is_write, .ret = NOT_DONE, + .flags = flags, }; assert((qiov->size & (BDRV_SECTOR_SIZE - 1)) == 0); @@ -2175,7 +2260,7 @@ static int bdrv_rwv_co(BlockDriverState *bs, int64_t sector_num, * Process a synchronous request using coroutines */ static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, - int nb_sectors, bool is_write) + int nb_sectors, bool is_write, BdrvRequestFlags flags) { QEMUIOVector qiov; struct iovec iov = { @@ -2184,14 +2269,14 @@ static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, }; qemu_iovec_init_external(&qiov, &iov, 1); - return bdrv_rwv_co(bs, sector_num, &qiov, is_write); + return bdrv_rwv_co(bs, sector_num, &qiov, is_write, flags); } /* return < 0 if error. See bdrv_write() for the return codes */ int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { - return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false); + return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false, 0); } /* Just like bdrv_read(), but with I/O throttling temporarily disabled */ @@ -2203,7 +2288,7 @@ int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num, enabled = bs->io_limits_enabled; bs->io_limits_enabled = false; - ret = bdrv_read(bs, 0, buf, 1); + ret = bdrv_read(bs, sector_num, buf, nb_sectors); bs->io_limits_enabled = enabled; return ret; } @@ -2217,12 +2302,18 @@ int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num, int bdrv_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { - return bdrv_rw_co(bs, sector_num, (uint8_t *)buf, nb_sectors, true); + return bdrv_rw_co(bs, sector_num, (uint8_t *)buf, nb_sectors, true, 0); } int bdrv_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov) { - return bdrv_rwv_co(bs, sector_num, qiov, true); + return bdrv_rwv_co(bs, sector_num, qiov, true, 0); +} + +int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num, int nb_sectors) +{ + return bdrv_rw_co(bs, sector_num, NULL, nb_sectors, true, + BDRV_REQ_ZERO_WRITE); } int bdrv_pread(BlockDriverState *bs, int64_t offset, @@ -2480,7 +2571,35 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs, } } - ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov); + if (!(bs->zero_beyond_eof && bs->growable)) { + ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov); + } else { + /* Read zeros after EOF of growable BDSes */ + int64_t len, total_sectors, max_nb_sectors; + + len = bdrv_getlength(bs); + if (len < 0) { + ret = len; + goto out; + } + + total_sectors = len >> BDRV_SECTOR_BITS; + max_nb_sectors = MAX(0, total_sectors - sector_num); + if (max_nb_sectors > 0) { + ret = drv->bdrv_co_readv(bs, sector_num, + MIN(nb_sectors, max_nb_sectors), qiov); + } else { + ret = 0; + } + + /* Reading beyond end of file is supposed to produce zeroes */ + if (ret == 0 && total_sectors < sector_num + nb_sectors) { + uint64_t offset = MAX(0, total_sectors - sector_num); + uint64_t bytes = (sector_num + nb_sectors - offset) * + BDRV_SECTOR_SIZE; + qemu_iovec_memset(qiov, offset * BDRV_SECTOR_SIZE, 0, bytes); + } + } out: tracked_request_end(&req); @@ -2572,7 +2691,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); @@ -2859,13 +2982,24 @@ int bdrv_get_flags(BlockDriverState *bs) 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) @@ -2876,7 +3010,8 @@ int bdrv_has_zero_init(BlockDriverState *bs) return bs->drv->bdrv_has_zero_init(bs); } - return 1; + /* safe default */ + return 0; } typedef struct BdrvCoIsAllocatedData { @@ -3052,128 +3187,6 @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, return data.ret; } -BlockInfo *bdrv_query_info(BlockDriverState *bs) -{ - BlockInfo *info = g_malloc0(sizeof(*info)); - info->device = g_strdup(bs->device_name); - info->type = g_strdup("unknown"); - info->locked = bdrv_dev_is_medium_locked(bs); - info->removable = bdrv_dev_has_removable_media(bs); - - if (bdrv_dev_has_removable_media(bs)) { - info->has_tray_open = true; - info->tray_open = bdrv_dev_is_tray_open(bs); - } - - if (bdrv_iostatus_is_enabled(bs)) { - info->has_io_status = true; - info->io_status = bs->iostatus; - } - - if (bs->dirty_bitmap) { - info->has_dirty = true; - info->dirty = g_malloc0(sizeof(*info->dirty)); - info->dirty->count = bdrv_get_dirty_count(bs) * BDRV_SECTOR_SIZE; - info->dirty->granularity = - ((int64_t) BDRV_SECTOR_SIZE << hbitmap_granularity(bs->dirty_bitmap)); - } - - if (bs->drv) { - info->has_inserted = true; - info->inserted = g_malloc0(sizeof(*info->inserted)); - info->inserted->file = g_strdup(bs->filename); - info->inserted->ro = bs->read_only; - info->inserted->drv = g_strdup(bs->drv->format_name); - info->inserted->encrypted = bs->encrypted; - info->inserted->encryption_key_missing = bdrv_key_required(bs); - - if (bs->backing_file[0]) { - info->inserted->has_backing_file = true; - info->inserted->backing_file = g_strdup(bs->backing_file); - } - - info->inserted->backing_file_depth = bdrv_get_backing_file_depth(bs); - - if (bs->io_limits_enabled) { - info->inserted->bps = - bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]; - info->inserted->bps_rd = - bs->io_limits.bps[BLOCK_IO_LIMIT_READ]; - info->inserted->bps_wr = - bs->io_limits.bps[BLOCK_IO_LIMIT_WRITE]; - info->inserted->iops = - bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]; - info->inserted->iops_rd = - bs->io_limits.iops[BLOCK_IO_LIMIT_READ]; - info->inserted->iops_wr = - bs->io_limits.iops[BLOCK_IO_LIMIT_WRITE]; - } - } - return info; -} - -BlockInfoList *qmp_query_block(Error **errp) -{ - BlockInfoList *head = NULL, **p_next = &head; - BlockDriverState *bs; - - QTAILQ_FOREACH(bs, &bdrv_states, list) { - BlockInfoList *info = g_malloc0(sizeof(*info)); - info->value = bdrv_query_info(bs); - - *p_next = info; - p_next = &info->next; - } - - return head; -} - -BlockStats *bdrv_query_stats(const BlockDriverState *bs) -{ - BlockStats *s; - - s = g_malloc0(sizeof(*s)); - - if (bs->device_name[0]) { - s->has_device = true; - s->device = g_strdup(bs->device_name); - } - - s->stats = g_malloc0(sizeof(*s->stats)); - s->stats->rd_bytes = bs->nr_bytes[BDRV_ACCT_READ]; - s->stats->wr_bytes = bs->nr_bytes[BDRV_ACCT_WRITE]; - s->stats->rd_operations = bs->nr_ops[BDRV_ACCT_READ]; - s->stats->wr_operations = bs->nr_ops[BDRV_ACCT_WRITE]; - s->stats->wr_highest_offset = bs->wr_highest_sector * BDRV_SECTOR_SIZE; - s->stats->flush_operations = bs->nr_ops[BDRV_ACCT_FLUSH]; - s->stats->wr_total_time_ns = bs->total_time_ns[BDRV_ACCT_WRITE]; - s->stats->rd_total_time_ns = bs->total_time_ns[BDRV_ACCT_READ]; - s->stats->flush_total_time_ns = bs->total_time_ns[BDRV_ACCT_FLUSH]; - - if (bs->file) { - s->has_parent = true; - s->parent = bdrv_query_stats(bs->file); - } - - return s; -} - -BlockStatsList *qmp_query_blockstats(Error **errp) -{ - BlockStatsList *head = NULL, **p_next = &head; - BlockDriverState *bs; - - QTAILQ_FOREACH(bs, &bdrv_states, list) { - BlockStatsList *info = g_malloc0(sizeof(*info)); - info->value = bdrv_query_stats(bs); - - *p_next = info; - p_next = &info->next; - } - - return head; -} - const char *bdrv_get_encrypted_filename(BlockDriverState *bs) { if (bs->backing_hd && bs->backing_hd->encrypted) @@ -3260,13 +3273,11 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event) { - BlockDriver *drv = bs->drv; - - if (!drv || !drv->bdrv_debug_event) { + if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) { return; } - drv->bdrv_debug_event(bs, event); + bs->drv->bdrv_debug_event(bs, event); } int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, @@ -3309,129 +3320,11 @@ bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag) return false; } -/**************************************************************/ -/* handling of snapshots */ - -int bdrv_can_snapshot(BlockDriverState *bs) -{ - BlockDriver *drv = bs->drv; - if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { - return 0; - } - - if (!drv->bdrv_snapshot_create) { - if (bs->file != NULL) { - return bdrv_can_snapshot(bs->file); - } - return 0; - } - - return 1; -} - int bdrv_is_snapshot(BlockDriverState *bs) { return !!(bs->open_flags & BDRV_O_SNAPSHOT); } -BlockDriverState *bdrv_snapshots(void) -{ - BlockDriverState *bs; - - if (bs_snapshots) { - return bs_snapshots; - } - - bs = NULL; - while ((bs = bdrv_next(bs))) { - if (bdrv_can_snapshot(bs)) { - bs_snapshots = bs; - return bs; - } - } - return NULL; -} - -int bdrv_snapshot_create(BlockDriverState *bs, - QEMUSnapshotInfo *sn_info) -{ - BlockDriver *drv = bs->drv; - if (!drv) - return -ENOMEDIUM; - if (drv->bdrv_snapshot_create) - return drv->bdrv_snapshot_create(bs, sn_info); - if (bs->file) - return bdrv_snapshot_create(bs->file, sn_info); - return -ENOTSUP; -} - -int bdrv_snapshot_goto(BlockDriverState *bs, - const char *snapshot_id) -{ - BlockDriver *drv = bs->drv; - int ret, open_ret; - - if (!drv) - return -ENOMEDIUM; - if (drv->bdrv_snapshot_goto) - return drv->bdrv_snapshot_goto(bs, snapshot_id); - - if (bs->file) { - drv->bdrv_close(bs); - ret = bdrv_snapshot_goto(bs->file, snapshot_id); - open_ret = drv->bdrv_open(bs, NULL, bs->open_flags); - if (open_ret < 0) { - bdrv_delete(bs->file); - bs->drv = NULL; - return open_ret; - } - return ret; - } - - return -ENOTSUP; -} - -int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id) -{ - BlockDriver *drv = bs->drv; - if (!drv) - return -ENOMEDIUM; - if (drv->bdrv_snapshot_delete) - return drv->bdrv_snapshot_delete(bs, snapshot_id); - if (bs->file) - return bdrv_snapshot_delete(bs->file, snapshot_id); - return -ENOTSUP; -} - -int bdrv_snapshot_list(BlockDriverState *bs, - QEMUSnapshotInfo **psn_info) -{ - BlockDriver *drv = bs->drv; - if (!drv) - return -ENOMEDIUM; - if (drv->bdrv_snapshot_list) - return drv->bdrv_snapshot_list(bs, psn_info); - if (bs->file) - return bdrv_snapshot_list(bs->file, psn_info); - return -ENOTSUP; -} - -int bdrv_snapshot_load_tmp(BlockDriverState *bs, - const char *snapshot_name) -{ - BlockDriver *drv = bs->drv; - if (!drv) { - return -ENOMEDIUM; - } - if (!bs->read_only) { - return -EINVAL; - } - if (drv->bdrv_snapshot_load_tmp) { - return drv->bdrv_snapshot_load_tmp(bs, snapshot_name); - } - return -ENOTSUP; -} - /* backing_file can either be relative, or absolute, or a protocol. If it is * relative, it must be relative to the chain. So, passing in bs->filename * from a BDS as backing_file should not be done, as that may be relative to @@ -3527,69 +3420,6 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs) return curr_bs; } -#define NB_SUFFIXES 4 - -char *get_human_readable_size(char *buf, int buf_size, int64_t size) -{ - static const char suffixes[NB_SUFFIXES] = "KMGT"; - int64_t base; - int i; - - if (size <= 999) { - snprintf(buf, buf_size, "%" PRId64, size); - } else { - base = 1024; - for(i = 0; i < NB_SUFFIXES; i++) { - if (size < (10 * base)) { - snprintf(buf, buf_size, "%0.1f%c", - (double)size / base, - suffixes[i]); - break; - } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) { - snprintf(buf, buf_size, "%" PRId64 "%c", - ((size + (base >> 1)) / base), - suffixes[i]); - break; - } - base = base * 1024; - } - } - return buf; -} - -char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) -{ - char buf1[128], date_buf[128], clock_buf[128]; - struct tm tm; - time_t ti; - int64_t secs; - - if (!sn) { - snprintf(buf, buf_size, - "%-10s%-20s%7s%20s%15s", - "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); - } else { - ti = sn->date_sec; - localtime_r(&ti, &tm); - strftime(date_buf, sizeof(date_buf), - "%Y-%m-%d %H:%M:%S", &tm); - secs = sn->vm_clock_nsec / 1000000000; - snprintf(clock_buf, sizeof(clock_buf), - "%02d:%02d:%02d.%03d", - (int)(secs / 3600), - (int)((secs / 60) % 60), - (int)(secs % 60), - (int)((sn->vm_clock_nsec / 1000000) % 1000)); - snprintf(buf, buf_size, - "%-10s%-20s%7s%20s%15s", - sn->id_str, sn->name, - get_human_readable_size(buf1, sizeof(buf1), sn->vm_state_size), - date_buf, - clock_buf); - } - return buf; -} - /**************************************************************/ /* async I/Os */ @@ -3917,7 +3747,7 @@ static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors, double elapsed_time; int bps_ret, iops_ret; - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (now > bs->slice_end) { bs->slice_start = now; bs->slice_end = now + BLOCK_IO_SLICE_TIME; @@ -3937,7 +3767,7 @@ static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors, *wait = max_wait; } - now = qemu_get_clock_ns(vm_clock); + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (bs->slice_end < now + max_wait) { bs->slice_end = now + max_wait; } @@ -4279,6 +4109,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) } /* Write back cached data to the OS even with cache=unsafe */ + BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_OS); if (bs->drv->bdrv_co_flush_to_os) { ret = bs->drv->bdrv_co_flush_to_os(bs); if (ret < 0) { @@ -4291,6 +4122,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) goto flush_parent; } + BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_DISK); if (bs->drv->bdrv_co_flush_to_disk) { ret = bs->drv->bdrv_co_flush_to_disk(bs); } else if (bs->drv->bdrv_aio_flush) { @@ -4705,7 +4537,7 @@ void bdrv_img_create(const char *filename, const char *fmt, 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; @@ -4810,8 +4642,12 @@ void bdrv_img_create(const char *filename, const char *fmt, error_setg(errp,"Formatting or formatting option not supported for " "file format '%s'", fmt); } else if (ret == -EFBIG) { - error_setg(errp, "The image size is too large for file format '%s'", - fmt); + const char *cluster_size_hint = ""; + if (get_option_parameter(create_options, BLOCK_OPT_CLUSTER_SIZE)) { + cluster_size_hint = " (try using a larger cluster size)"; + } + error_setg(errp, "The image size is too large for file format '%s'%s", + fmt, cluster_size_hint); } else { error_setg(errp, "%s: error while creating %s: %s", filename, fmt, strerror(-ret)); @@ -4832,3 +4668,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); +}