static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, const char *replaces, int64_t speed, int64_t granularity, int64_t buf_size, BlockdevOnError on_source_error, BlockdevOnError on_target_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp, const BlockJobDriver *driver, bool is_none_mode, BlockDriverState *base) { MirrorBlockJob *s; if (granularity == 0) { /* Choose the default granularity based on the target file's cluster * size, clamped between 4k and 64k. */ BlockDriverInfo bdi; if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) { granularity = MAX(4096, bdi.cluster_size); granularity = MIN(65536, granularity); } else { granularity = 65536; } } assert ((granularity & (granularity - 1)) == 0); if ((on_source_error == BLOCKDEV_ON_ERROR_STOP || on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) && !bdrv_iostatus_is_enabled(bs)) { error_set(errp, QERR_INVALID_PARAMETER, "on-source-error"); return; } s = block_job_create(driver, bs, speed, cb, opaque, errp); if (!s) { return; } s->replaces = g_strdup(replaces); s->on_source_error = on_source_error; s->on_target_error = on_target_error; s->target = target; s->is_none_mode = is_none_mode; s->base = base; s->granularity = granularity; s->buf_size = MAX(buf_size, granularity); s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, errp); if (!s->dirty_bitmap) { return; } bdrv_set_enable_write_cache(s->target, true); bdrv_set_on_error(s->target, on_target_error, on_target_error); bdrv_iostatus_enable(s->target); s->common.co = qemu_coroutine_create(mirror_run); trace_mirror_start(bs, s, s->common.co, opaque); qemu_coroutine_enter(s->common.co, s); }
/* @p_info will be set only on success. */ void bdrv_query_info(BlockDriverState *bs, BlockInfo **p_info, Error **errp) { BlockInfo *info = g_malloc0(sizeof(*info)); BlockDriverState *bs0; ImageInfo **p_image_info; Error *local_err = NULL; 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 (!QLIST_EMPTY(&bs->dirty_bitmaps)) { info->has_dirty_bitmaps = true; info->dirty_bitmaps = bdrv_query_dirty_bitmaps(bs); } if (bs->drv) { info->has_inserted = true; info->inserted = bdrv_block_device_info(bs); bs0 = bs; p_image_info = &info->inserted->image; while (1) { bdrv_query_image_info(bs0, p_image_info, &local_err); if (local_err) { error_propagate(errp, local_err); goto err; } if (bs0->drv && bs0->backing_hd) { bs0 = bs0->backing_hd; (*p_image_info)->has_backing_image = true; p_image_info = &((*p_image_info)->backing_image); } else { break; } } } *p_info = info; return; err: qapi_free_BlockInfo(info); }
static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, const char *replaces, int64_t speed, uint32_t granularity, int64_t buf_size, BlockdevOnError on_source_error, BlockdevOnError on_target_error, BlockCompletionFunc *cb, void *opaque, Error **errp, const BlockJobDriver *driver, bool is_none_mode, BlockDriverState *base) { MirrorBlockJob *s; if (granularity == 0) { granularity = bdrv_get_default_bitmap_granularity(target); } assert ((granularity & (granularity - 1)) == 0); if ((on_source_error == BLOCKDEV_ON_ERROR_STOP || on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) && !bdrv_iostatus_is_enabled(bs)) { error_setg(errp, QERR_INVALID_PARAMETER, "on-source-error"); return; } s = block_job_create(driver, bs, speed, cb, opaque, errp); if (!s) { return; } s->replaces = g_strdup(replaces); s->on_source_error = on_source_error; s->on_target_error = on_target_error; s->target = target; s->is_none_mode = is_none_mode; s->base = base; s->granularity = granularity; s->buf_size = MAX(buf_size, granularity); s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp); if (!s->dirty_bitmap) { return; } bdrv_set_enable_write_cache(s->target, true); bdrv_set_on_error(s->target, on_target_error, on_target_error); bdrv_iostatus_enable(s->target); s->common.co = qemu_coroutine_create(mirror_run); trace_mirror_start(bs, s, s->common.co, opaque); qemu_coroutine_enter(s->common.co, s); }
/* @p_info will be set only on success. */ void bdrv_query_info(BlockDriverState *bs, BlockInfo **p_info, Error **errp) { BlockInfo *info = g_malloc0(sizeof(*info)); BlockDriverState *bs0; ImageInfo **p_image_info; Error *local_err = NULL; 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) { ThrottleConfig cfg; throttle_get_config(&bs->throttle_state, &cfg); info->inserted->bps = cfg.buckets[THROTTLE_BPS_TOTAL].avg; info->inserted->bps_rd = cfg.buckets[THROTTLE_BPS_READ].avg; info->inserted->bps_wr = cfg.buckets[THROTTLE_BPS_WRITE].avg; info->inserted->iops = cfg.buckets[THROTTLE_OPS_TOTAL].avg; info->inserted->iops_rd = cfg.buckets[THROTTLE_OPS_READ].avg; info->inserted->iops_wr = cfg.buckets[THROTTLE_OPS_WRITE].avg; info->inserted->has_bps_max = cfg.buckets[THROTTLE_BPS_TOTAL].max; info->inserted->bps_max = cfg.buckets[THROTTLE_BPS_TOTAL].max; info->inserted->has_bps_rd_max = cfg.buckets[THROTTLE_BPS_READ].max; info->inserted->bps_rd_max = cfg.buckets[THROTTLE_BPS_READ].max; info->inserted->has_bps_wr_max = cfg.buckets[THROTTLE_BPS_WRITE].max; info->inserted->bps_wr_max = cfg.buckets[THROTTLE_BPS_WRITE].max; info->inserted->has_iops_max = cfg.buckets[THROTTLE_OPS_TOTAL].max; info->inserted->iops_max = cfg.buckets[THROTTLE_OPS_TOTAL].max; info->inserted->has_iops_rd_max = cfg.buckets[THROTTLE_OPS_READ].max; info->inserted->iops_rd_max = cfg.buckets[THROTTLE_OPS_READ].max; info->inserted->has_iops_wr_max = cfg.buckets[THROTTLE_OPS_WRITE].max; info->inserted->iops_wr_max = cfg.buckets[THROTTLE_OPS_WRITE].max; info->inserted->has_iops_size = cfg.op_size; info->inserted->iops_size = cfg.op_size; } bs0 = bs; p_image_info = &info->inserted->image; while (1) { bdrv_query_image_info(bs0, p_image_info, &local_err); if (error_is_set(&local_err)) { error_propagate(errp, local_err); goto err; } if (bs0->drv && bs0->backing_hd) { bs0 = bs0->backing_hd; (*p_image_info)->has_backing_image = true; p_image_info = &((*p_image_info)->backing_image); } else { break; } } } *p_info = info; return; err: qapi_free_BlockInfo(info); }
void commit_start(BlockDriverState *bs, BlockDriverState *base, BlockDriverState *top, int64_t speed, BlockErrorAction on_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp) { CommitBlockJob *s; BlockReopenQueue *reopen_queue = NULL; int orig_overlay_flags; int orig_base_flags; BlockDriverState *overlay_bs; Error *local_err = NULL; if ((on_error == BLOCK_ERR_STOP_ANY || on_error == BLOCK_ERR_STOP_ENOSPC) && !bdrv_iostatus_is_enabled(bs)) { error_set(errp, QERR_INVALID_PARAMETER_COMBINATION); return; } /* Once we support top == active layer, remove this check */ if (top == bs) { error_set(errp, QERR_TOP_IS_ACTIVE); return; } if (top == base) { error_set(errp, QERR_TOP_AND_BASE_IDENTICAL); return; } overlay_bs = bdrv_find_overlay(bs, top); if (overlay_bs == NULL) { error_set(errp, QERR_TOP_NOT_FOUND, top->filename); return; } orig_base_flags = bdrv_get_flags(base); orig_overlay_flags = bdrv_get_flags(overlay_bs); /* convert base & overlay_bs to r/w, if necessary */ if (!(orig_base_flags & BDRV_O_RDWR)) { reopen_queue = bdrv_reopen_queue(reopen_queue, base, orig_base_flags | BDRV_O_RDWR); } if (!(orig_overlay_flags & BDRV_O_RDWR)) { reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, orig_overlay_flags | BDRV_O_RDWR); } if (reopen_queue) { bdrv_reopen_multiple(reopen_queue, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; } } s = block_job_create(&commit_job_type, bs, speed, cb, opaque); if (!s) { error_set(errp, QERR_DEVICE_IN_USE, bs->device_name); return; } s->base = base; s->top = top; s->active = bs; s->base_flags = orig_base_flags; s->orig_overlay_flags = orig_overlay_flags; s->on_error = on_error; s->common.co = qemu_coroutine_create(commit_run); trace_commit_start(bs, base, top, s, s->common.co, opaque); qemu_coroutine_enter(s->common.co, s); }
void commit_start(BlockDriverState *bs, BlockDriverState *base, BlockDriverState *top, int64_t speed, BlockdevOnError on_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp) { CommitBlockJob *s; BlockReopenQueue *reopen_queue = NULL; int orig_overlay_flags; int orig_base_flags; BlockDriverState *overlay_bs; Error *local_err = NULL; if ((on_error == BLOCKDEV_ON_ERROR_STOP || on_error == BLOCKDEV_ON_ERROR_ENOSPC) && !bdrv_iostatus_is_enabled(bs)) { error_set(errp, QERR_INVALID_PARAMETER_COMBINATION); return; } /* Once we support top == active layer, remove this check */ if (top == bs) { error_setg(errp, "Top image as the active layer is currently unsupported"); return; } if (top == base) { error_setg(errp, "Invalid files for merge: top and base are the same"); return; } overlay_bs = bdrv_find_overlay(bs, top); if (overlay_bs == NULL) { error_setg(errp, "Could not find overlay image for %s:", top->filename); return; } orig_base_flags = bdrv_get_flags(base); orig_overlay_flags = bdrv_get_flags(overlay_bs); /* convert base & overlay_bs to r/w, if necessary */ if (!(orig_base_flags & BDRV_O_RDWR)) { reopen_queue = bdrv_reopen_queue(reopen_queue, base, orig_base_flags | BDRV_O_RDWR); } if (!(orig_overlay_flags & BDRV_O_RDWR)) { reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, orig_overlay_flags | BDRV_O_RDWR); } if (reopen_queue) { bdrv_reopen_multiple(reopen_queue, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; } } s = block_job_create(&commit_job_type, bs, speed, cb, opaque, errp); if (!s) { return; } s->base = base; s->top = top; s->active = bs; s->base_flags = orig_base_flags; s->orig_overlay_flags = orig_overlay_flags; s->on_error = on_error; s->common.co = qemu_coroutine_create(commit_run); trace_commit_start(bs, base, top, s, s->common.co, opaque); qemu_coroutine_enter(s->common.co, s); }