-/*
- * Handle a write request in coroutine context
- */
-static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
- int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
- BdrvRequestFlags flags)
-{
- BdrvTrackedRequest req;
- uint64_t align = bdrv_get_align(bs);
- uint8_t *head_buf = NULL;
- uint8_t *tail_buf = NULL;
- QEMUIOVector local_qiov;
- bool use_local_qiov = false;
- int ret;
-
- if (!bs->drv) {
- return -ENOMEDIUM;
- }
- if (bs->read_only) {
- return -EACCES;
- }
-
- ret = bdrv_check_byte_request(bs, offset, bytes);
- if (ret < 0) {
- return ret;
- }
-
- /* throttling disk I/O */
- if (bs->io_limits_enabled) {
- bdrv_io_limits_intercept(bs, bytes, true);
- }
-
- /*
- * Align write if necessary by performing a read-modify-write cycle.
- * Pad qiov with the read parts and be sure to have a tracked request not
- * only for bdrv_aligned_pwritev, but also for the reads of the RMW cycle.
- */
- tracked_request_begin(&req, bs, offset, bytes, true);
-
- if (offset & (align - 1)) {
- QEMUIOVector head_qiov;
- struct iovec head_iov;
-
- mark_request_serialising(&req, align);
- wait_serialising_requests(&req);
-
- head_buf = qemu_blockalign(bs, align);
- head_iov = (struct iovec) {
- .iov_base = head_buf,
- .iov_len = align,
- };
- qemu_iovec_init_external(&head_qiov, &head_iov, 1);
-
- BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_HEAD);
- ret = bdrv_aligned_preadv(bs, &req, offset & ~(align - 1), align,
- align, &head_qiov, 0);
- if (ret < 0) {
- goto fail;
- }
- BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
-
- qemu_iovec_init(&local_qiov, qiov->niov + 2);
- qemu_iovec_add(&local_qiov, head_buf, offset & (align - 1));
- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size);
- use_local_qiov = true;
-
- bytes += offset & (align - 1);
- offset = offset & ~(align - 1);
- }
-
- if ((offset + bytes) & (align - 1)) {
- QEMUIOVector tail_qiov;
- struct iovec tail_iov;
- size_t tail_bytes;
- bool waited;
-
- mark_request_serialising(&req, align);
- waited = wait_serialising_requests(&req);
- assert(!waited || !use_local_qiov);
-
- tail_buf = qemu_blockalign(bs, align);
- tail_iov = (struct iovec) {
- .iov_base = tail_buf,
- .iov_len = align,
- };
- qemu_iovec_init_external(&tail_qiov, &tail_iov, 1);
-
- BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_TAIL);
- ret = bdrv_aligned_preadv(bs, &req, (offset + bytes) & ~(align - 1), align,
- align, &tail_qiov, 0);
- if (ret < 0) {
- goto fail;
- }
- BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
-
- if (!use_local_qiov) {
- qemu_iovec_init(&local_qiov, qiov->niov + 1);
- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size);
- use_local_qiov = true;
- }
-
- tail_bytes = (offset + bytes) & (align - 1);
- qemu_iovec_add(&local_qiov, tail_buf + tail_bytes, align - tail_bytes);
-
- bytes = ROUND_UP(bytes, align);
- }
-
- if (use_local_qiov) {
- /* Local buffer may have non-zero data. */
- flags &= ~BDRV_REQ_ZERO_WRITE;
- }
- ret = bdrv_aligned_pwritev(bs, &req, offset, bytes,
- use_local_qiov ? &local_qiov : qiov,
- flags);
-
-fail:
- tracked_request_end(&req);
-
- if (use_local_qiov) {
- qemu_iovec_destroy(&local_qiov);
- }
- qemu_vfree(head_buf);
- qemu_vfree(tail_buf);
-
- return ret;
-}
-
-static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
- BdrvRequestFlags flags)
-{
- if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
- return -EINVAL;
- }
-
- return bdrv_co_do_pwritev(bs, sector_num << BDRV_SECTOR_BITS,
- nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
-}
-
-int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
- int nb_sectors, QEMUIOVector *qiov)
-{
- trace_bdrv_co_writev(bs, sector_num, nb_sectors);
-
- return bdrv_co_do_writev(bs, sector_num, nb_sectors, qiov, 0);
-}
-
-int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors,
- BdrvRequestFlags flags)
-{
- int ret;
-
- trace_bdrv_co_write_zeroes(bs, sector_num, nb_sectors, flags);
-
- if (!(bs->open_flags & BDRV_O_UNMAP)) {
- flags &= ~BDRV_REQ_MAY_UNMAP;
- }
- if (bdrv_req_is_aligned(bs, sector_num << BDRV_SECTOR_BITS,
- nb_sectors << BDRV_SECTOR_BITS)) {
- ret = bdrv_co_do_writev(bs, sector_num, nb_sectors, NULL,
- BDRV_REQ_ZERO_WRITE | flags);
- } else {
- uint8_t *buf;
- QEMUIOVector local_qiov;
- size_t bytes = nb_sectors << BDRV_SECTOR_BITS;
-
- buf = qemu_memalign(bdrv_opt_mem_align(bs), bytes);
- memset(buf, 0, bytes);
- qemu_iovec_init(&local_qiov, 1);
- qemu_iovec_add(&local_qiov, buf, bytes);
-
- ret = bdrv_co_do_writev(bs, sector_num, nb_sectors, &local_qiov,
- BDRV_REQ_ZERO_WRITE | flags);
- qemu_vfree(buf);
- }
- return ret;
-}
-
-/**
- * Truncate file to 'offset' bytes (needed only for file protocols)
- */
-int bdrv_truncate(BlockDriverState *bs, int64_t offset)
-{
- BlockDriver *drv = bs->drv;
- int ret;
- if (!drv)
- return -ENOMEDIUM;
- if (!drv->bdrv_truncate)
- return -ENOTSUP;
- if (bs->read_only)
- return -EACCES;
-
- ret = drv->bdrv_truncate(bs, offset);
- if (ret == 0) {
- ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
- if (bs->blk) {
- blk_dev_resize_cb(bs->blk);
- }
- }
- return ret;
-}
-
-/**
- * Length of a allocated file in bytes. Sparse files are counted by actual
- * allocated space. Return < 0 if error or unknown.
- */
-int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
-{
- BlockDriver *drv = bs->drv;
- if (!drv) {
- return -ENOMEDIUM;
- }
- if (drv->bdrv_get_allocated_file_size) {
- return drv->bdrv_get_allocated_file_size(bs);
- }
- if (bs->file) {
- return bdrv_get_allocated_file_size(bs->file);
- }
- return -ENOTSUP;
-}
-
-/**
- * Return number of sectors on success, -errno on error.
- */
-int64_t bdrv_nb_sectors(BlockDriverState *bs)
-{
- BlockDriver *drv = bs->drv;
-
- if (!drv)
- return -ENOMEDIUM;
-
- if (drv->has_variable_length) {
- int ret = refresh_total_sectors(bs, bs->total_sectors);
- if (ret < 0) {
- return ret;
- }
- }
- return bs->total_sectors;
-}
-
-/**
- * Return length in bytes on success, -errno on error.
- * The length is always a multiple of BDRV_SECTOR_SIZE.
- */
-int64_t bdrv_getlength(BlockDriverState *bs)
-{
- int64_t ret = bdrv_nb_sectors(bs);
-
- return ret < 0 ? ret : ret * BDRV_SECTOR_SIZE;
-}
-
-/* return 0 as number of sectors if no device present or error */
-void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
-{
- int64_t nb_sectors = bdrv_nb_sectors(bs);
-
- *nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
-}
-
-void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error,
- BlockdevOnError on_write_error)
-{
- bs->on_read_error = on_read_error;
- bs->on_write_error = on_write_error;
-}
-
-BlockdevOnError bdrv_get_on_error(BlockDriverState *bs, bool is_read)
-{
- return is_read ? bs->on_read_error : bs->on_write_error;
-}
-
-BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int error)
-{
- BlockdevOnError on_err = is_read ? bs->on_read_error : bs->on_write_error;
-
- switch (on_err) {
- case BLOCKDEV_ON_ERROR_ENOSPC:
- return (error == ENOSPC) ?
- BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT;
- case BLOCKDEV_ON_ERROR_STOP:
- return BLOCK_ERROR_ACTION_STOP;
- case BLOCKDEV_ON_ERROR_REPORT:
- return BLOCK_ERROR_ACTION_REPORT;
- case BLOCKDEV_ON_ERROR_IGNORE:
- return BLOCK_ERROR_ACTION_IGNORE;
- default:
- abort();
- }
-}
-
-static void send_qmp_error_event(BlockDriverState *bs,
- BlockErrorAction action,
- bool is_read, int error)
-{
- IoOperationType optype;
-
- optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
- qapi_event_send_block_io_error(bdrv_get_device_name(bs), optype, action,
- bdrv_iostatus_is_enabled(bs),
- error == ENOSPC, strerror(error),
- &error_abort);
-}
-
-/* This is done by device models because, while the block layer knows
- * about the error, it does not know whether an operation comes from
- * the device or the block layer (from a job, for example).
- */
-void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action,
- bool is_read, int error)
-{
- assert(error >= 0);
-
- if (action == BLOCK_ERROR_ACTION_STOP) {
- /* First set the iostatus, so that "info block" returns an iostatus
- * that matches the events raised so far (an additional error iostatus
- * is fine, but not a lost one).
- */
- bdrv_iostatus_set_err(bs, error);
-
- /* Then raise the request to stop the VM and the event.
- * qemu_system_vmstop_request_prepare has two effects. First,
- * it ensures that the STOP event always comes after the
- * BLOCK_IO_ERROR event. Second, it ensures that even if management
- * can observe the STOP event and do a "cont" before the STOP
- * event is issued, the VM will not stop. In this case, vm_start()
- * also ensures that the STOP/RESUME pair of events is emitted.
- */
- qemu_system_vmstop_request_prepare();
- send_qmp_error_event(bs, action, is_read, error);
- qemu_system_vmstop_request(RUN_STATE_IO_ERROR);
- } else {
- send_qmp_error_event(bs, action, is_read, error);
- }
-}
-
-int bdrv_is_read_only(BlockDriverState *bs)
-{
- return bs->read_only;
-}
-
-int bdrv_is_sg(BlockDriverState *bs)
-{
- return bs->sg;
-}
-
-int bdrv_enable_write_cache(BlockDriverState *bs)
-{
- return bs->enable_write_cache;
-}
-
-void bdrv_set_enable_write_cache(BlockDriverState *bs, bool wce)
-{
- bs->enable_write_cache = wce;
-
- /* so a reopen() will preserve wce */
- if (wce) {
- bs->open_flags |= BDRV_O_CACHE_WB;
- } else {
- bs->open_flags &= ~BDRV_O_CACHE_WB;
- }
-}
-
-int bdrv_is_encrypted(BlockDriverState *bs)
-{
- if (bs->backing_hd && bs->backing_hd->encrypted)
- return 1;
- return bs->encrypted;
-}
-
-int bdrv_key_required(BlockDriverState *bs)
-{
- BlockDriverState *backing_hd = bs->backing_hd;
-
- if (backing_hd && backing_hd->encrypted && !backing_hd->valid_key)
- return 1;
- return (bs->encrypted && !bs->valid_key);
-}
-
-int bdrv_set_key(BlockDriverState *bs, const char *key)
-{
- int ret;
- if (bs->backing_hd && bs->backing_hd->encrypted) {
- ret = bdrv_set_key(bs->backing_hd, key);
- if (ret < 0)
- return ret;
- if (!bs->encrypted)
- return 0;
- }
- if (!bs->encrypted) {
- return -EINVAL;
- } else if (!bs->drv || !bs->drv->bdrv_set_key) {
- return -ENOMEDIUM;
- }
- ret = bs->drv->bdrv_set_key(bs, key);
- if (ret < 0) {
- bs->valid_key = 0;
- } else if (!bs->valid_key) {
- bs->valid_key = 1;
- if (bs->blk) {
- /* call the change callback now, we skipped it on open */
- blk_dev_change_media_cb(bs->blk, true);
- }
- }
- return ret;
-}
-
-/*
- * Provide an encryption key for @bs.
- * If @key is non-null:
- * If @bs is not encrypted, fail.
- * Else if the key is invalid, fail.
- * Else set @bs's key to @key, replacing the existing key, if any.
- * If @key is null:
- * If @bs is encrypted and still lacks a key, fail.
- * Else do nothing.
- * On failure, store an error object through @errp if non-null.
- */
-void bdrv_add_key(BlockDriverState *bs, const char *key, Error **errp)
-{
- if (key) {
- if (!bdrv_is_encrypted(bs)) {
- error_setg(errp, "Node '%s' is not encrypted",
- bdrv_get_device_or_node_name(bs));
- } else if (bdrv_set_key(bs, key) < 0) {
- error_set(errp, QERR_INVALID_PASSWORD);
- }
- } else {
- if (bdrv_key_required(bs)) {
- error_set(errp, ERROR_CLASS_DEVICE_ENCRYPTED,
- "'%s' (%s) is encrypted",
- bdrv_get_device_or_node_name(bs),
- bdrv_get_encrypted_filename(bs));
- }
- }
-}
-
-const char *bdrv_get_format_name(BlockDriverState *bs)
-{
- return bs->drv ? bs->drv->format_name : NULL;
-}
-
-static int qsort_strcmp(const void *a, const void *b)
-{
- return strcmp(a, b);
-}
-
-void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
- void *opaque)
-{
- BlockDriver *drv;
- int count = 0;
- int i;
- const char **formats = NULL;
-
- QLIST_FOREACH(drv, &bdrv_drivers, list) {
- if (drv->format_name) {
- bool found = false;
- int i = count;
- while (formats && i && !found) {
- found = !strcmp(formats[--i], drv->format_name);
- }
-
- if (!found) {
- formats = g_renew(const char *, formats, count + 1);
- formats[count++] = drv->format_name;
- }
- }
- }
-
- qsort(formats, count, sizeof(formats[0]), qsort_strcmp);
-
- for (i = 0; i < count; i++) {
- it(opaque, formats[i]);
- }
-
- g_free(formats);
-}
-
-/* This function is to find a node in the bs graph */
-BlockDriverState *bdrv_find_node(const char *node_name)
-{
- BlockDriverState *bs;
-
- assert(node_name);
-
- QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) {
- if (!strcmp(node_name, bs->node_name)) {
- return bs;
- }
- }
- return NULL;
-}
-
-/* Put this QMP function here so it can access the static graph_bdrv_states. */
-BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp)
-{
- BlockDeviceInfoList *list, *entry;
- BlockDriverState *bs;
-
- list = NULL;
- QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) {
- BlockDeviceInfo *info = bdrv_block_device_info(bs, errp);
- if (!info) {
- qapi_free_BlockDeviceInfoList(list);
- return NULL;
- }
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = list;
- list = entry;
- }
-
- return list;
-}
-
-BlockDriverState *bdrv_lookup_bs(const char *device,
- const char *node_name,
- Error **errp)
-{
- BlockBackend *blk;
- BlockDriverState *bs;
-
- if (device) {
- blk = blk_by_name(device);
-
- if (blk) {
- return blk_bs(blk);
- }
- }
-
- if (node_name) {
- bs = bdrv_find_node(node_name);
-
- if (bs) {
- return bs;
- }
- }
-
- error_setg(errp, "Cannot find device=%s nor node_name=%s",
- device ? device : "",
- node_name ? node_name : "");
- return NULL;
-}
-
-/* If 'base' is in the same chain as 'top', return true. Otherwise,
- * return false. If either argument is NULL, return false. */
-bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base)
-{
- while (top && top != base) {
- top = top->backing_hd;
- }
-
- return top != NULL;
-}
-
-BlockDriverState *bdrv_next_node(BlockDriverState *bs)
-{
- if (!bs) {
- return QTAILQ_FIRST(&graph_bdrv_states);
- }
- return QTAILQ_NEXT(bs, node_list);
-}
-
-BlockDriverState *bdrv_next(BlockDriverState *bs)
-{
- if (!bs) {
- return QTAILQ_FIRST(&bdrv_states);
- }
- return QTAILQ_NEXT(bs, device_list);
-}
-
-const char *bdrv_get_node_name(const BlockDriverState *bs)
-{
- return bs->node_name;
-}
-
-/* TODO check what callers really want: bs->node_name or blk_name() */
-const char *bdrv_get_device_name(const BlockDriverState *bs)
-{
- return bs->blk ? blk_name(bs->blk) : "";
-}
-
-/* This can be used to identify nodes that might not have a device
- * name associated. Since node and device names live in the same
- * namespace, the result is unambiguous. The exception is if both are
- * absent, then this returns an empty (non-null) string. */
-const char *bdrv_get_device_or_node_name(const BlockDriverState *bs)
-{
- return bs->blk ? blk_name(bs->blk) : bs->node_name;
-}
-
-int bdrv_get_flags(BlockDriverState *bs)
-{
- return bs->open_flags;
-}
-
-int bdrv_flush_all(void)
-{
- BlockDriverState *bs;
- int result = 0;
-
- QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
- AioContext *aio_context = bdrv_get_aio_context(bs);
- int ret;
-
- aio_context_acquire(aio_context);
- ret = bdrv_flush(bs);
- if (ret < 0 && !result) {
- result = ret;
- }
- aio_context_release(aio_context);
- }
-
- return result;
-}
-
-int bdrv_has_zero_init_1(BlockDriverState *bs)
-{
- return 1;
-}
-
-int bdrv_has_zero_init(BlockDriverState *bs)
-{
- assert(bs->drv);
-
- /* If BS is a copy on write image, it is initialized to
- the contents of the base image, which may not be zeroes. */
- if (bs->backing_hd) {
- return 0;
- }
- if (bs->drv->bdrv_has_zero_init) {
- return bs->drv->bdrv_has_zero_init(bs);
- }
-
- /* safe default */
- return 0;
-}
-
-bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs)
-{
- BlockDriverInfo bdi;
-
- if (bs->backing_hd) {
- return false;
- }
-
- if (bdrv_get_info(bs, &bdi) == 0) {
- return bdi.unallocated_blocks_are_zero;
- }
-
- return false;
-}
-
-bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs)
-{
- BlockDriverInfo bdi;
-
- if (bs->backing_hd || !(bs->open_flags & BDRV_O_UNMAP)) {
- return false;
- }
-
- if (bdrv_get_info(bs, &bdi) == 0) {
- return bdi.can_write_zeroes_with_unmap;
- }
-
- return false;
-}
-
-typedef struct BdrvCoGetBlockStatusData {
- BlockDriverState *bs;
- BlockDriverState *base;
- int64_t sector_num;
- int nb_sectors;
- int *pnum;
- int64_t ret;
- bool done;
-} BdrvCoGetBlockStatusData;
-
-/*
- * Returns the allocation status of the specified sectors.
- * Drivers not implementing the functionality are assumed to not support
- * backing files, hence all their sectors are reported as allocated.
- *
- * If 'sector_num' is beyond the end of the disk image the return value is 0
- * and 'pnum' is set to 0.
- *
- * 'pnum' is set to the number of sectors (including and immediately following
- * the specified sector) that are known to be in the same
- * allocated/unallocated state.
- *
- * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
- * beyond the end of the disk image it will be clamped.
- */
-static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num,
- int nb_sectors, int *pnum)
-{
- int64_t total_sectors;
- int64_t n;
- int64_t ret, ret2;
-
- total_sectors = bdrv_nb_sectors(bs);
- if (total_sectors < 0) {
- return total_sectors;
- }
-
- if (sector_num >= total_sectors) {
- *pnum = 0;
- return 0;
- }
-
- n = total_sectors - sector_num;
- if (n < nb_sectors) {
- nb_sectors = n;
- }
-
- if (!bs->drv->bdrv_co_get_block_status) {
- *pnum = nb_sectors;
- ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
- if (bs->drv->protocol_name) {
- ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
- }
- return ret;
- }
-
- ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum);
- if (ret < 0) {
- *pnum = 0;
- return ret;
- }
-
- if (ret & BDRV_BLOCK_RAW) {
- assert(ret & BDRV_BLOCK_OFFSET_VALID);
- return bdrv_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS,
- *pnum, pnum);
- }
-
- if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
- ret |= BDRV_BLOCK_ALLOCATED;
- }
-
- if (!(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO)) {
- if (bdrv_unallocated_blocks_are_zero(bs)) {
- ret |= BDRV_BLOCK_ZERO;
- } else if (bs->backing_hd) {
- BlockDriverState *bs2 = bs->backing_hd;
- int64_t nb_sectors2 = bdrv_nb_sectors(bs2);
- if (nb_sectors2 >= 0 && sector_num >= nb_sectors2) {
- ret |= BDRV_BLOCK_ZERO;
- }
- }
- }
-
- if (bs->file &&
- (ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
- (ret & BDRV_BLOCK_OFFSET_VALID)) {
- int file_pnum;
-
- ret2 = bdrv_co_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS,
- *pnum, &file_pnum);
- if (ret2 >= 0) {
- /* Ignore errors. This is just providing extra information, it
- * is useful but not necessary.
- */
- if (!file_pnum) {
- /* !file_pnum indicates an offset at or beyond the EOF; it is
- * perfectly valid for the format block driver to point to such
- * offsets, so catch it and mark everything as zero */
- ret |= BDRV_BLOCK_ZERO;
- } else {
- /* Limit request to the range reported by the protocol driver */
- *pnum = file_pnum;
- ret |= (ret2 & BDRV_BLOCK_ZERO);
- }
- }
- }
-
- return ret;
-}
-
-/* Coroutine wrapper for bdrv_get_block_status() */
-static void coroutine_fn bdrv_get_block_status_co_entry(void *opaque)
-{
- BdrvCoGetBlockStatusData *data = opaque;
- BlockDriverState *bs = data->bs;
-
- data->ret = bdrv_co_get_block_status(bs, data->sector_num, data->nb_sectors,
- data->pnum);
- data->done = true;
-}
-
-/*
- * Synchronous wrapper around bdrv_co_get_block_status().
- *
- * See bdrv_co_get_block_status() for details.
- */
-int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num,
- int nb_sectors, int *pnum)
-{
- Coroutine *co;
- BdrvCoGetBlockStatusData data = {
- .bs = bs,
- .sector_num = sector_num,
- .nb_sectors = nb_sectors,
- .pnum = pnum,
- .done = false,
- };
-
- if (qemu_in_coroutine()) {
- /* Fast-path if already in coroutine context */
- bdrv_get_block_status_co_entry(&data);
- } else {
- AioContext *aio_context = bdrv_get_aio_context(bs);
-
- co = qemu_coroutine_create(bdrv_get_block_status_co_entry);
- qemu_coroutine_enter(co, &data);
- while (!data.done) {
- aio_poll(aio_context, true);
- }
- }
- return data.ret;
-}
-
-int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
- int nb_sectors, int *pnum)
-{
- int64_t ret = bdrv_get_block_status(bs, sector_num, nb_sectors, pnum);
- if (ret < 0) {
- return ret;
- }
- return !!(ret & BDRV_BLOCK_ALLOCATED);
-}
-
-/*
- * Given an image chain: ... -> [BASE] -> [INTER1] -> [INTER2] -> [TOP]
- *
- * Return true if the given sector is allocated in any image between
- * BASE and TOP (inclusive). BASE can be NULL to check if the given
- * sector is allocated in any image of the chain. Return false otherwise.
- *
- * 'pnum' is set to the number of sectors (including and immediately following
- * the specified sector) that are known to be in the same
- * allocated/unallocated state.
- *
- */
-int bdrv_is_allocated_above(BlockDriverState *top,
- BlockDriverState *base,
- int64_t sector_num,
- int nb_sectors, int *pnum)
-{
- BlockDriverState *intermediate;
- int ret, n = nb_sectors;
-
- intermediate = top;
- while (intermediate && intermediate != base) {
- int pnum_inter;
- ret = bdrv_is_allocated(intermediate, sector_num, nb_sectors,
- &pnum_inter);
- if (ret < 0) {
- return ret;
- } else if (ret) {
- *pnum = pnum_inter;
- return 1;
- }
-
- /*
- * [sector_num, nb_sectors] is unallocated on top but intermediate
- * might have
- *
- * [sector_num+x, nr_sectors] allocated.
- */
- if (n > pnum_inter &&
- (intermediate == top ||
- sector_num + pnum_inter < intermediate->total_sectors)) {
- n = pnum_inter;
- }
-
- intermediate = intermediate->backing_hd;
- }
-
- *pnum = n;
- return 0;
-}
-
-const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
-{
- if (bs->backing_hd && bs->backing_hd->encrypted)
- return bs->backing_file;
- else if (bs->encrypted)
- return bs->filename;
- else
- return NULL;
-}
-
-void bdrv_get_backing_filename(BlockDriverState *bs,
- char *filename, int filename_size)
-{
- pstrcpy(filename, filename_size, bs->backing_file);
-}
-
-int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
- const uint8_t *buf, int nb_sectors)
-{
- BlockDriver *drv = bs->drv;
- int ret;
-
- if (!drv) {
- return -ENOMEDIUM;
- }
- if (!drv->bdrv_write_compressed) {
- return -ENOTSUP;
- }
- ret = bdrv_check_request(bs, sector_num, nb_sectors);
- if (ret < 0) {
- return ret;
- }
-
- assert(QLIST_EMPTY(&bs->dirty_bitmaps));
-
- return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
-}
-
-int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
-{
- BlockDriver *drv = bs->drv;
- if (!drv)
- return -ENOMEDIUM;
- if (!drv->bdrv_get_info)
- return -ENOTSUP;
- memset(bdi, 0, sizeof(*bdi));
- return drv->bdrv_get_info(bs, bdi);
-}
-
-ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs)
-{
- BlockDriver *drv = bs->drv;
- if (drv && drv->bdrv_get_specific_info) {
- return drv->bdrv_get_specific_info(bs);
- }
- return NULL;
-}
-
-int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
- int64_t pos, int size)
-{
- QEMUIOVector qiov;
- struct iovec iov = {
- .iov_base = (void *) buf,
- .iov_len = size,
- };
-
- qemu_iovec_init_external(&qiov, &iov, 1);
- return bdrv_writev_vmstate(bs, &qiov, pos);
-}
-
-int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
-{
- BlockDriver *drv = bs->drv;
-
- if (!drv) {
- return -ENOMEDIUM;
- } else if (drv->bdrv_save_vmstate) {
- return drv->bdrv_save_vmstate(bs, qiov, pos);
- } else if (bs->file) {
- return bdrv_writev_vmstate(bs->file, qiov, pos);
- }
-
- return -ENOTSUP;
-}
-
-int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
- int64_t pos, int size)
-{
- BlockDriver *drv = bs->drv;
- if (!drv)
- return -ENOMEDIUM;
- if (drv->bdrv_load_vmstate)
- return drv->bdrv_load_vmstate(bs, buf, pos, size);
- if (bs->file)
- return bdrv_load_vmstate(bs->file, buf, pos, size);
- return -ENOTSUP;
-}
-
-void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
-{
- if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) {
- return;
- }
-
- bs->drv->bdrv_debug_event(bs, event);
-}
-
-int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
- const char *tag)
-{
- while (bs && bs->drv && !bs->drv->bdrv_debug_breakpoint) {
- bs = bs->file;
- }
-
- if (bs && bs->drv && bs->drv->bdrv_debug_breakpoint) {
- return bs->drv->bdrv_debug_breakpoint(bs, event, tag);
- }
-
- return -ENOTSUP;
-}
-
-int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag)
-{
- while (bs && bs->drv && !bs->drv->bdrv_debug_remove_breakpoint) {
- bs = bs->file;
- }
-
- if (bs && bs->drv && bs->drv->bdrv_debug_remove_breakpoint) {
- return bs->drv->bdrv_debug_remove_breakpoint(bs, tag);
- }
-
- return -ENOTSUP;
-}
-
-int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
-{
- while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) {
- bs = bs->file;
- }
-
- if (bs && bs->drv && bs->drv->bdrv_debug_resume) {
- return bs->drv->bdrv_debug_resume(bs, tag);
- }
-
- return -ENOTSUP;
-}
-
-bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag)
-{
- while (bs && bs->drv && !bs->drv->bdrv_debug_is_suspended) {
- bs = bs->file;
- }
-
- if (bs && bs->drv && bs->drv->bdrv_debug_is_suspended) {
- return bs->drv->bdrv_debug_is_suspended(bs, tag);
- }
-
- return false;
-}
-
-int bdrv_is_snapshot(BlockDriverState *bs)
-{
- return !!(bs->open_flags & BDRV_O_SNAPSHOT);
-}
-
-/* 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
- * the CWD rather than the chain. */
-BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
- const char *backing_file)
-{
- char *filename_full = NULL;
- char *backing_file_full = NULL;
- char *filename_tmp = NULL;
- int is_protocol = 0;
- BlockDriverState *curr_bs = NULL;
- BlockDriverState *retval = NULL;
-
- if (!bs || !bs->drv || !backing_file) {
- return NULL;
- }
-
- filename_full = g_malloc(PATH_MAX);
- backing_file_full = g_malloc(PATH_MAX);
- filename_tmp = g_malloc(PATH_MAX);
-
- is_protocol = path_has_protocol(backing_file);
-
- for (curr_bs = bs; curr_bs->backing_hd; curr_bs = curr_bs->backing_hd) {
-
- /* If either of the filename paths is actually a protocol, then
- * compare unmodified paths; otherwise make paths relative */
- if (is_protocol || path_has_protocol(curr_bs->backing_file)) {
- if (strcmp(backing_file, curr_bs->backing_file) == 0) {
- retval = curr_bs->backing_hd;
- break;
- }
- } else {
- /* If not an absolute filename path, make it relative to the current
- * image's filename path */
- path_combine(filename_tmp, PATH_MAX, curr_bs->filename,
- backing_file);
-
- /* We are going to compare absolute pathnames */
- if (!realpath(filename_tmp, filename_full)) {
- continue;
- }
-
- /* We need to make sure the backing filename we are comparing against
- * is relative to the current image filename (or absolute) */
- path_combine(filename_tmp, PATH_MAX, curr_bs->filename,
- curr_bs->backing_file);
-
- if (!realpath(filename_tmp, backing_file_full)) {
- continue;
- }
-
- if (strcmp(backing_file_full, filename_full) == 0) {
- retval = curr_bs->backing_hd;
- break;
- }
- }
- }
-
- g_free(filename_full);
- g_free(backing_file_full);
- g_free(filename_tmp);
- return retval;
-}
-
-int bdrv_get_backing_file_depth(BlockDriverState *bs)
-{
- if (!bs->drv) {
- return 0;
- }
-
- if (!bs->backing_hd) {
- return 0;
- }
-
- return 1 + bdrv_get_backing_file_depth(bs->backing_hd);
-}
-
-/**************************************************************/
-/* async I/Os */
-
-BlockAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
- QEMUIOVector *qiov, int nb_sectors,
- BlockCompletionFunc *cb, void *opaque)
-{
- trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
-
- return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0,
- cb, opaque, false);
-}
-
-BlockAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
- QEMUIOVector *qiov, int nb_sectors,
- BlockCompletionFunc *cb, void *opaque)
-{
- trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
-
- return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0,
- cb, opaque, true);
-}
-
-BlockAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, BdrvRequestFlags flags,
- BlockCompletionFunc *cb, void *opaque)
-{
- trace_bdrv_aio_write_zeroes(bs, sector_num, nb_sectors, flags, opaque);
-
- return bdrv_co_aio_rw_vector(bs, sector_num, NULL, nb_sectors,
- BDRV_REQ_ZERO_WRITE | flags,
- cb, opaque, true);
-}
-
-
-typedef struct MultiwriteCB {
- int error;
- int num_requests;
- int num_callbacks;
- struct {
- BlockCompletionFunc *cb;
- void *opaque;
- QEMUIOVector *free_qiov;
- } callbacks[];
-} MultiwriteCB;
-
-static void multiwrite_user_cb(MultiwriteCB *mcb)
-{
- int i;
-
- for (i = 0; i < mcb->num_callbacks; i++) {
- mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error);
- if (mcb->callbacks[i].free_qiov) {
- qemu_iovec_destroy(mcb->callbacks[i].free_qiov);
- }
- g_free(mcb->callbacks[i].free_qiov);
- }
-}
-
-static void multiwrite_cb(void *opaque, int ret)
-{
- MultiwriteCB *mcb = opaque;
-
- trace_multiwrite_cb(mcb, ret);
-
- if (ret < 0 && !mcb->error) {
- mcb->error = ret;
- }
-
- mcb->num_requests--;
- if (mcb->num_requests == 0) {
- multiwrite_user_cb(mcb);
- g_free(mcb);
- }
-}
-
-static int multiwrite_req_compare(const void *a, const void *b)
-{
- const BlockRequest *req1 = a, *req2 = b;
-
- /*
- * Note that we can't simply subtract req2->sector from req1->sector
- * here as that could overflow the return value.
- */
- if (req1->sector > req2->sector) {
- return 1;
- } else if (req1->sector < req2->sector) {
- return -1;
- } else {
- return 0;
- }
-}
-
-/*
- * Takes a bunch of requests and tries to merge them. Returns the number of
- * requests that remain after merging.
- */
-static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
- int num_reqs, MultiwriteCB *mcb)
-{
- int i, outidx;
-
- // Sort requests by start sector
- qsort(reqs, num_reqs, sizeof(*reqs), &multiwrite_req_compare);
-
- // Check if adjacent requests touch the same clusters. If so, combine them,
- // filling up gaps with zero sectors.
- outidx = 0;
- for (i = 1; i < num_reqs; i++) {
- int merge = 0;
- int64_t oldreq_last = reqs[outidx].sector + reqs[outidx].nb_sectors;
-
- // Handle exactly sequential writes and overlapping writes.
- if (reqs[i].sector <= oldreq_last) {
- merge = 1;
- }