/** * Delete an internal snapshot by @snapshot_id and @name. * @bs: block device used in the operation * @snapshot_id: unique snapshot ID, or NULL * @name: snapshot name, or NULL * @errp: location to store error * * If both @snapshot_id and @name are specified, delete the first one with * id @snapshot_id and name @name. * If only @snapshot_id is specified, delete the first one with id * @snapshot_id. * If only @name is specified, delete the first one with name @name. * if none is specified, return -EINVAL. * * Returns: 0 on success, -errno on failure. If @bs is not inserted, return * -ENOMEDIUM. If @snapshot_id and @name are both NULL, return -EINVAL. If @bs * does not support internal snapshot deletion, return -ENOTSUP. If @bs does * not support parameter @snapshot_id or @name, or one of them is not correctly * specified, return -EINVAL. If @bs can't find one matching @id and @name, * return -ENOENT. If @errp != NULL, it will always be filled with error * message on failure. */ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id, const char *name, Error **errp) { BlockDriver *drv = bs->drv; if (!drv) { error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs)); return -ENOMEDIUM; } if (!snapshot_id && !name) { error_setg(errp, "snapshot_id and name are both NULL"); return -EINVAL; } /* drain all pending i/o before deleting snapshot */ bdrv_drain_all(); if (drv->bdrv_snapshot_delete) { return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp); } if (bs->file) { return bdrv_snapshot_delete(bs->file, snapshot_id, name, errp); } error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, drv->format_name, bdrv_get_device_name(bs), "internal snapshot deletion"); return -ENOTSUP; }
static BlockStats *bdrv_query_stats(const BlockDriverState *bs) { BlockStats *s; s = g_malloc0(sizeof(*s)); if (bdrv_get_device_name(bs)[0]) { s->has_device = true; s->device = g_strdup(bdrv_get_device_name(bs)); } s->stats = g_malloc0(sizeof(*s->stats)); s->stats->rd_bytes = bs->stats.nr_bytes[BLOCK_ACCT_READ]; s->stats->wr_bytes = bs->stats.nr_bytes[BLOCK_ACCT_WRITE]; s->stats->rd_operations = bs->stats.nr_ops[BLOCK_ACCT_READ]; s->stats->wr_operations = bs->stats.nr_ops[BLOCK_ACCT_WRITE]; s->stats->wr_highest_offset = bs->stats.wr_highest_sector * BDRV_SECTOR_SIZE; s->stats->flush_operations = bs->stats.nr_ops[BLOCK_ACCT_FLUSH]; s->stats->wr_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_WRITE]; s->stats->rd_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_READ]; s->stats->flush_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_FLUSH]; if (bs->file) { s->has_parent = true; s->parent = bdrv_query_stats(bs->file); } if (bs->backing_hd) { s->has_backing = true; s->backing = bdrv_query_stats(bs->backing_hd); } return s; }
/** * Temporarily load an internal snapshot by @snapshot_id and @name. * @bs: block device used in the operation * @snapshot_id: unique snapshot ID, or NULL * @name: snapshot name, or NULL * @errp: location to store error * * If both @snapshot_id and @name are specified, load the first one with * id @snapshot_id and name @name. * If only @snapshot_id is specified, load the first one with id * @snapshot_id. * If only @name is specified, load the first one with name @name. * if none is specified, return -EINVAL. * * Returns: 0 on success, -errno on fail. If @bs is not inserted, return * -ENOMEDIUM. If @bs is not readonly, return -EINVAL. If @bs did not support * internal snapshot, return -ENOTSUP. If qemu can't find a matching @id and * @name, return -ENOENT. If @errp != NULL, it will always be filled on * failure. */ int bdrv_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_id, const char *name, Error **errp) { BlockDriver *drv = bs->drv; if (!drv) { error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs)); return -ENOMEDIUM; } if (!snapshot_id && !name) { error_setg(errp, "snapshot_id and name are both NULL"); return -EINVAL; } if (!bs->read_only) { error_setg(errp, "Device is not readonly"); return -EINVAL; } if (drv->bdrv_snapshot_load_tmp) { return drv->bdrv_snapshot_load_tmp(bs, snapshot_id, name, errp); } error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, drv->format_name, bdrv_get_device_name(bs), "temporarily load internal snapshot"); return -ENOTSUP; }
/** * Delete an internal snapshot by @snapshot_id and @name. * @bs: block device used in the operation * @snapshot_id: unique snapshot ID, or NULL * @name: snapshot name, or NULL * @errp: location to store error * * If both @snapshot_id and @name are specified, delete the first one with * id @snapshot_id and name @name. * If only @snapshot_id is specified, delete the first one with id * @snapshot_id. * If only @name is specified, delete the first one with name @name. * if none is specified, return -EINVAL. * * Returns: 0 on success, -errno on failure. If @bs is not inserted, return * -ENOMEDIUM. If @snapshot_id and @name are both NULL, return -EINVAL. If @bs * does not support internal snapshot deletion, return -ENOTSUP. If @bs does * not support parameter @snapshot_id or @name, or one of them is not correctly * specified, return -EINVAL. If @bs can't find one matching @id and @name, * return -ENOENT. If @errp != NULL, it will always be filled with error * message on failure. */ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id, const char *name, Error **errp) { BlockDriver *drv = bs->drv; if (!drv) { error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs)); return -ENOMEDIUM; } if (!snapshot_id && !name) { error_setg(errp, "snapshot_id and name are both NULL"); return -EINVAL; } /* drain all pending i/o before deleting snapshot */ bdrv_drain(bs); if (drv->bdrv_snapshot_delete) { return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp); } if (bs->file) { return bdrv_snapshot_delete(bs->file->bs, snapshot_id, name, errp); } error_setg(errp, "Block format '%s' used by device '%s' " "does not support internal snapshot deletion", drv->format_name, bdrv_get_device_name(bs)); return -ENOTSUP; }
/** * Temporarily load an internal snapshot by @snapshot_id and @name. * @bs: block device used in the operation * @snapshot_id: unique snapshot ID, or NULL * @name: snapshot name, or NULL * @errp: location to store error * * If both @snapshot_id and @name are specified, load the first one with * id @snapshot_id and name @name. * If only @snapshot_id is specified, load the first one with id * @snapshot_id. * If only @name is specified, load the first one with name @name. * if none is specified, return -EINVAL. * * Returns: 0 on success, -errno on fail. If @bs is not inserted, return * -ENOMEDIUM. If @bs is not readonly, return -EINVAL. If @bs did not support * internal snapshot, return -ENOTSUP. If qemu can't find a matching @id and * @name, return -ENOENT. If @errp != NULL, it will always be filled on * failure. */ int bdrv_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_id, const char *name, Error **errp) { BlockDriver *drv = bs->drv; if (!drv) { error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs)); return -ENOMEDIUM; } if (!snapshot_id && !name) { error_setg(errp, "snapshot_id and name are both NULL"); return -EINVAL; } if (!bs->read_only) { error_setg(errp, "Device is not readonly"); return -EINVAL; } if (drv->bdrv_snapshot_load_tmp) { return drv->bdrv_snapshot_load_tmp(bs, snapshot_id, name, errp); } error_setg(errp, "Block format '%s' used by device '%s' " "does not support temporarily loading internal snapshots", drv->format_name, bdrv_get_device_name(bs)); return -ENOTSUP; }
void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs, int64_t speed, BlockDriverCompletionFunc *cb, void *opaque, Error **errp) { BlockJob *job; if (bs->job || bdrv_in_use(bs)) { error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs)); return NULL; } bdrv_set_in_use(bs, 1); job = g_malloc0(job_type->instance_size); job->job_type = job_type; job->bs = bs; job->cb = cb; job->opaque = opaque; job->busy = true; bs->job = job; /* Only set speed when necessary to avoid NotSupported error */ if (speed != 0) { Error *local_err = NULL; block_job_set_speed(job, speed, &local_err); if (error_is_set(&local_err)) { bs->job = NULL; g_free(job); bdrv_set_in_use(bs, 0); error_propagate(errp, local_err); return NULL; } } return job; }
static void mirror_complete(BlockJob *job, Error **errp) { MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); Error *local_err = NULL; int ret; ret = bdrv_open_backing_file(s->target, NULL, &local_err); if (ret < 0) { error_propagate(errp, local_err); return; } if (!s->synced) { error_set(errp, QERR_BLOCK_JOB_NOT_READY, bdrv_get_device_name(job->bs)); return; } /* check the target bs is not blocked and block all operations on it */ if (s->replaces) { s->to_replace = check_to_replace_node(s->replaces, &local_err); if (!s->to_replace) { error_propagate(errp, local_err); return; } error_setg(&s->replace_blocker, "block device is in use by block-job-complete"); bdrv_op_block_all(s->to_replace, s->replace_blocker); bdrv_ref(s->to_replace); } s->should_complete = true; block_job_resume(job); }
void block_job_event_ready(BlockJob *job) { qapi_event_send_block_job_ready(job->driver->job_type, bdrv_get_device_name(job->bs), job->len, job->offset, job->speed, &error_abort); }
/* * Returns 0 on success, with *p_list either set to describe snapshot * information, or NULL because there are no snapshots. Returns -errno on * error, with *p_list untouched. */ int bdrv_query_snapshot_info_list(BlockDriverState *bs, SnapshotInfoList **p_list, Error **errp) { int i, sn_count; QEMUSnapshotInfo *sn_tab = NULL; SnapshotInfoList *info_list, *cur_item = NULL, *head = NULL; SnapshotInfo *info; sn_count = bdrv_snapshot_list(bs, &sn_tab); if (sn_count < 0) { const char *dev = bdrv_get_device_name(bs); switch (sn_count) { case -ENOMEDIUM: error_setg(errp, "Device '%s' is not inserted", dev); break; case -ENOTSUP: error_setg(errp, "Device '%s' does not support internal snapshots", dev); break; default: error_setg_errno(errp, -sn_count, "Can't list snapshots of device '%s'", dev); break; } return sn_count; } for (i = 0; i < sn_count; i++) { info = g_new0(SnapshotInfo, 1); info->id = g_strdup(sn_tab[i].id_str); info->name = g_strdup(sn_tab[i].name); info->vm_state_size = sn_tab[i].vm_state_size; info->date_sec = sn_tab[i].date_sec; info->date_nsec = sn_tab[i].date_nsec; info->vm_clock_sec = sn_tab[i].vm_clock_nsec / 1000000000; info->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000; info_list = g_new0(SnapshotInfoList, 1); info_list->value = info; /* XXX: waiting for the qapi to support qemu-queue.h types */ if (!cur_item) { head = cur_item = info_list; } else { cur_item->next = info_list; cur_item = info_list; } } g_free(sn_tab); *p_list = head; return 0; }
void block_job_complete(BlockJob *job, Error **errp) { if (job->pause_count || job->cancelled || !job->driver->complete) { error_set(errp, QERR_BLOCK_JOB_NOT_READY, bdrv_get_device_name(job->bs)); return; } job->driver->complete(job, errp); }
void block_job_event_completed(BlockJob *job, const char *msg) { qapi_event_send_block_job_completed(job->driver->job_type, bdrv_get_device_name(job->bs), job->len, job->offset, job->speed, !!msg, msg, &error_abort); }
BlockJobInfo *block_job_query(BlockJob *job) { BlockJobInfo *info = g_new0(BlockJobInfo, 1); info->type = g_strdup(BlockJobType_lookup[job->driver->job_type]); info->device = g_strdup(bdrv_get_device_name(job->bs)); info->len = job->len; info->busy = job->busy; info->paused = job->paused; info->offset = job->offset; info->speed = job->speed; info->io_status = job->iostatus; return info; }
QObject *qobject_from_block_job(BlockJob *job) { return qobject_from_jsonf("{ 'type': %s," "'device': %s," "'len': %" PRId64 "," "'offset': %" PRId64 "," "'speed': %" PRId64 " }", BlockJobType_lookup[job->driver->job_type], bdrv_get_device_name(job->bs), job->len, job->offset, job->speed); }
void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs, int64_t speed, BlockCompletionFunc *cb, void *opaque, Error **errp) { BlockJob *job; if (bs->job) { error_setg(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs)); return NULL; } bdrv_ref(bs); job = g_malloc0(driver->instance_size); error_setg(&job->blocker, "block device is in use by block job: %s", BlockJobType_lookup[driver->job_type]); bdrv_op_block_all(bs, job->blocker); bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker); job->driver = driver; job->id = g_strdup(bdrv_get_device_name(bs)); job->bs = bs; job->cb = cb; job->opaque = opaque; job->busy = true; bs->job = job; /* Only set speed when necessary to avoid NotSupported error */ if (speed != 0) { Error *local_err = NULL; block_job_set_speed(job, speed, &local_err); if (local_err) { block_job_release(bs); error_propagate(errp, local_err); return NULL; } } return job; }
int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) { Error *errp = NULL; const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; object_property_set_str(OBJECT(dev), bdrv_name, name, &errp); if (errp) { qerror_report_err(errp); error_free(errp); return -1; } return 0; }
BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs, BlockdevOnError on_err, int is_read, int error) { BlockErrorAction action; switch (on_err) { case BLOCKDEV_ON_ERROR_ENOSPC: action = (error == ENOSPC) ? BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT; break; case BLOCKDEV_ON_ERROR_STOP: action = BLOCK_ERROR_ACTION_STOP; break; case BLOCKDEV_ON_ERROR_REPORT: action = BLOCK_ERROR_ACTION_REPORT; break; case BLOCKDEV_ON_ERROR_IGNORE: action = BLOCK_ERROR_ACTION_IGNORE; break; default: abort(); } qapi_event_send_block_job_error(bdrv_get_device_name(job->bs), is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE, action, &error_abort); if (action == BLOCK_ERROR_ACTION_STOP) { /* make the pause user visible, which will be resumed from QMP. */ job->user_paused = true; block_job_pause(job); block_job_iostatus_set_err(job, error); if (bs != job->bs) { bdrv_iostatus_set_err(bs, error); } } return action; }
static char *print_drive(void *ptr) { return g_strdup(bdrv_get_device_name(ptr)); }
static int vpc_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVVPCState *s = bs->opaque; int i; VHDFooter *footer; VHDDynDiskHeader *dyndisk_header; uint8_t buf[HEADER_SIZE]; uint32_t checksum; uint64_t computed_size; int disk_type = VHD_DYNAMIC; int ret; ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE); if (ret < 0) { goto fail; } footer = (VHDFooter *) s->footer_buf; if (strncmp(footer->creator, "conectix", 8)) { int64_t offset = bdrv_getlength(bs->file); if (offset < 0) { ret = offset; goto fail; } else if (offset < HEADER_SIZE) { ret = -EINVAL; goto fail; } /* If a fixed disk, the footer is found only at the end of the file */ ret = bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf, HEADER_SIZE); if (ret < 0) { goto fail; } if (strncmp(footer->creator, "conectix", 8)) { error_setg(errp, "invalid VPC image"); ret = -EINVAL; goto fail; } disk_type = VHD_FIXED; } checksum = be32_to_cpu(footer->checksum); footer->checksum = 0; if (vpc_checksum(s->footer_buf, HEADER_SIZE) != checksum) fprintf(stderr, "block-vpc: The header checksum of '%s' is " "incorrect.\n", bs->filename); /* Write 'checksum' back to footer, or else will leave it with zero. */ footer->checksum = cpu_to_be32(checksum); // The visible size of a image in Virtual PC depends on the geometry // rather than on the size stored in the footer (the size in the footer // is too large usually) bs->total_sectors = (int64_t) be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl; /* Images that have exactly the maximum geometry are probably bigger and * would be truncated if we adhered to the geometry for them. Rely on * footer->current_size for them. */ if (bs->total_sectors == VHD_MAX_GEOMETRY) { bs->total_sectors = be64_to_cpu(footer->current_size) / BDRV_SECTOR_SIZE; } /* Allow a maximum disk size of approximately 2 TB */ if (bs->total_sectors >= VHD_MAX_SECTORS) { ret = -EFBIG; goto fail; } if (disk_type == VHD_DYNAMIC) { ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE); if (ret < 0) { goto fail; } dyndisk_header = (VHDDynDiskHeader *) buf; if (strncmp(dyndisk_header->magic, "cxsparse", 8)) { ret = -EINVAL; goto fail; } s->block_size = be32_to_cpu(dyndisk_header->block_size); if (!is_power_of_2(s->block_size) || s->block_size < BDRV_SECTOR_SIZE) { error_setg(errp, "Invalid block size %" PRIu32, s->block_size); ret = -EINVAL; goto fail; } s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511; s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries); if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) { ret = -EINVAL; goto fail; } if (s->max_table_entries > (VHD_MAX_SECTORS * 512) / s->block_size) { ret = -EINVAL; goto fail; } computed_size = (uint64_t) s->max_table_entries * s->block_size; if (computed_size < bs->total_sectors * 512) { ret = -EINVAL; goto fail; } s->pagetable = qemu_try_blockalign(bs->file, s->max_table_entries * 4); if (s->pagetable == NULL) { ret = -ENOMEM; goto fail; } s->bat_offset = be64_to_cpu(dyndisk_header->table_offset); ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable, s->max_table_entries * 4); if (ret < 0) { goto fail; } s->free_data_block_offset = (s->bat_offset + (s->max_table_entries * 4) + 511) & ~511; for (i = 0; i < s->max_table_entries; i++) { be32_to_cpus(&s->pagetable[i]); if (s->pagetable[i] != 0xFFFFFFFF) { int64_t next = (512 * (int64_t) s->pagetable[i]) + s->bitmap_size + s->block_size; if (next > s->free_data_block_offset) { s->free_data_block_offset = next; } } } if (s->free_data_block_offset > bdrv_getlength(bs->file)) { error_setg(errp, "block-vpc: free_data_block_offset points after " "the end of file. The image has been truncated."); ret = -EINVAL; goto fail; } s->last_bitmap_offset = (int64_t) -1; #ifdef CACHE s->pageentry_u8 = g_malloc(512); s->pageentry_u32 = s->pageentry_u8; s->pageentry_u16 = s->pageentry_u8; s->last_pagetable = -1; #endif } qemu_co_mutex_init(&s->lock); /* Disable migration when VHD images are used */ error_set(&s->migration_blocker, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, "vpc", bdrv_get_device_name(bs), "live migration"); migrate_add_blocker(s->migration_blocker); return 0; fail: qemu_vfree(s->pagetable); #ifdef CACHE g_free(s->pageentry_u8); #endif return ret; }
BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, BlockDriverState *bs, Error **errp) { ImageInfo **p_image_info; BlockDriverState *bs0; BlockDeviceInfo *info = g_malloc0(sizeof(*info)); info->file = g_strdup(bs->filename); info->ro = bs->read_only; info->drv = g_strdup(bs->drv->format_name); info->encrypted = bs->encrypted; info->encryption_key_missing = false; info->cache = g_new(BlockdevCacheInfo, 1); *info->cache = (BlockdevCacheInfo) { .writeback = blk ? blk_enable_write_cache(blk) : true, .direct = !!(bs->open_flags & BDRV_O_NOCACHE), .no_flush = !!(bs->open_flags & BDRV_O_NO_FLUSH), }; if (bs->node_name[0]) { info->has_node_name = true; info->node_name = g_strdup(bs->node_name); } if (bs->backing_file[0]) { info->has_backing_file = true; info->backing_file = g_strdup(bs->backing_file); } info->detect_zeroes = bs->detect_zeroes; if (blk && blk_get_public(blk)->throttle_state) { ThrottleConfig cfg; throttle_group_get_config(blk, &cfg); info->bps = cfg.buckets[THROTTLE_BPS_TOTAL].avg; info->bps_rd = cfg.buckets[THROTTLE_BPS_READ].avg; info->bps_wr = cfg.buckets[THROTTLE_BPS_WRITE].avg; info->iops = cfg.buckets[THROTTLE_OPS_TOTAL].avg; info->iops_rd = cfg.buckets[THROTTLE_OPS_READ].avg; info->iops_wr = cfg.buckets[THROTTLE_OPS_WRITE].avg; info->has_bps_max = cfg.buckets[THROTTLE_BPS_TOTAL].max; info->bps_max = cfg.buckets[THROTTLE_BPS_TOTAL].max; info->has_bps_rd_max = cfg.buckets[THROTTLE_BPS_READ].max; info->bps_rd_max = cfg.buckets[THROTTLE_BPS_READ].max; info->has_bps_wr_max = cfg.buckets[THROTTLE_BPS_WRITE].max; info->bps_wr_max = cfg.buckets[THROTTLE_BPS_WRITE].max; info->has_iops_max = cfg.buckets[THROTTLE_OPS_TOTAL].max; info->iops_max = cfg.buckets[THROTTLE_OPS_TOTAL].max; info->has_iops_rd_max = cfg.buckets[THROTTLE_OPS_READ].max; info->iops_rd_max = cfg.buckets[THROTTLE_OPS_READ].max; info->has_iops_wr_max = cfg.buckets[THROTTLE_OPS_WRITE].max; info->iops_wr_max = cfg.buckets[THROTTLE_OPS_WRITE].max; info->has_bps_max_length = info->has_bps_max; info->bps_max_length = cfg.buckets[THROTTLE_BPS_TOTAL].burst_length; info->has_bps_rd_max_length = info->has_bps_rd_max; info->bps_rd_max_length = cfg.buckets[THROTTLE_BPS_READ].burst_length; info->has_bps_wr_max_length = info->has_bps_wr_max; info->bps_wr_max_length = cfg.buckets[THROTTLE_BPS_WRITE].burst_length; info->has_iops_max_length = info->has_iops_max; info->iops_max_length = cfg.buckets[THROTTLE_OPS_TOTAL].burst_length; info->has_iops_rd_max_length = info->has_iops_rd_max; info->iops_rd_max_length = cfg.buckets[THROTTLE_OPS_READ].burst_length; info->has_iops_wr_max_length = info->has_iops_wr_max; info->iops_wr_max_length = cfg.buckets[THROTTLE_OPS_WRITE].burst_length; info->has_iops_size = cfg.op_size; info->iops_size = cfg.op_size; info->has_group = true; info->group = g_strdup(throttle_group_get_name(blk)); } info->write_threshold = bdrv_write_threshold_get(bs); bs0 = bs; p_image_info = &info->image; info->backing_file_depth = 0; while (1) { Error *local_err = NULL; bdrv_query_image_info(bs0, p_image_info, &local_err); if (local_err) { error_propagate(errp, local_err); qapi_free_BlockDeviceInfo(info); return NULL; } if (bs0->drv && bs0->backing) { info->backing_file_depth++; bs0 = bs0->backing->bs; (*p_image_info)->has_backing_image = true; p_image_info = &((*p_image_info)->backing_image); } else { break; } /* Skip automatically inserted nodes that the user isn't aware of for * query-block (blk != NULL), but not for query-named-block-nodes */ while (blk && bs0->drv && bs0->implicit) { bs0 = backing_bs(bs0); assert(bs0); } } return info; } /* * Returns 0 on success, with *p_list either set to describe snapshot * information, or NULL because there are no snapshots. Returns -errno on * error, with *p_list untouched. */ int bdrv_query_snapshot_info_list(BlockDriverState *bs, SnapshotInfoList **p_list, Error **errp) { int i, sn_count; QEMUSnapshotInfo *sn_tab = NULL; SnapshotInfoList *info_list, *cur_item = NULL, *head = NULL; SnapshotInfo *info; sn_count = bdrv_snapshot_list(bs, &sn_tab); if (sn_count < 0) { const char *dev = bdrv_get_device_name(bs); switch (sn_count) { case -ENOMEDIUM: error_setg(errp, "Device '%s' is not inserted", dev); break; case -ENOTSUP: error_setg(errp, "Device '%s' does not support internal snapshots", dev); break; default: error_setg_errno(errp, -sn_count, "Can't list snapshots of device '%s'", dev); break; } return sn_count; } for (i = 0; i < sn_count; i++) { info = g_new0(SnapshotInfo, 1); info->id = g_strdup(sn_tab[i].id_str); info->name = g_strdup(sn_tab[i].name); info->vm_state_size = sn_tab[i].vm_state_size; info->date_sec = sn_tab[i].date_sec; info->date_nsec = sn_tab[i].date_nsec; info->vm_clock_sec = sn_tab[i].vm_clock_nsec / 1000000000; info->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000; info_list = g_new0(SnapshotInfoList, 1); info_list->value = info; /* XXX: waiting for the qapi to support qemu-queue.h types */ if (!cur_item) { head = cur_item = info_list; } else { cur_item->next = info_list; cur_item = info_list; } } g_free(sn_tab); *p_list = head; return 0; }
static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len) { BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); return snprintf(dest, len, "%s", *ptr ? bdrv_get_device_name(*ptr) : "<null>"); }
static BlockStats *bdrv_query_stats(const BlockDriverState *bs, bool query_backing) { BlockStats *s; s = g_malloc0(sizeof(*s)); if (bdrv_get_device_name(bs)[0]) { s->has_device = true; s->device = g_strdup(bdrv_get_device_name(bs)); } if (bdrv_get_node_name(bs)[0]) { s->has_node_name = true; s->node_name = g_strdup(bdrv_get_node_name(bs)); } s->stats = g_malloc0(sizeof(*s->stats)); if (bs->blk) { BlockAcctStats *stats = blk_get_stats(bs->blk); BlockAcctTimedStats *ts = NULL; s->stats->rd_bytes = stats->nr_bytes[BLOCK_ACCT_READ]; s->stats->wr_bytes = stats->nr_bytes[BLOCK_ACCT_WRITE]; s->stats->rd_operations = stats->nr_ops[BLOCK_ACCT_READ]; s->stats->wr_operations = stats->nr_ops[BLOCK_ACCT_WRITE]; s->stats->failed_rd_operations = stats->failed_ops[BLOCK_ACCT_READ]; s->stats->failed_wr_operations = stats->failed_ops[BLOCK_ACCT_WRITE]; s->stats->failed_flush_operations = stats->failed_ops[BLOCK_ACCT_FLUSH]; s->stats->invalid_rd_operations = stats->invalid_ops[BLOCK_ACCT_READ]; s->stats->invalid_wr_operations = stats->invalid_ops[BLOCK_ACCT_WRITE]; s->stats->invalid_flush_operations = stats->invalid_ops[BLOCK_ACCT_FLUSH]; s->stats->rd_merged = stats->merged[BLOCK_ACCT_READ]; s->stats->wr_merged = stats->merged[BLOCK_ACCT_WRITE]; s->stats->flush_operations = stats->nr_ops[BLOCK_ACCT_FLUSH]; s->stats->wr_total_time_ns = stats->total_time_ns[BLOCK_ACCT_WRITE]; s->stats->rd_total_time_ns = stats->total_time_ns[BLOCK_ACCT_READ]; s->stats->flush_total_time_ns = stats->total_time_ns[BLOCK_ACCT_FLUSH]; s->stats->has_idle_time_ns = stats->last_access_time_ns > 0; if (s->stats->has_idle_time_ns) { s->stats->idle_time_ns = block_acct_idle_time_ns(stats); } s->stats->account_invalid = stats->account_invalid; s->stats->account_failed = stats->account_failed; while ((ts = block_acct_interval_next(stats, ts))) { BlockDeviceTimedStatsList *timed_stats = g_malloc0(sizeof(*timed_stats)); BlockDeviceTimedStats *dev_stats = g_malloc0(sizeof(*dev_stats)); timed_stats->next = s->stats->timed_stats; timed_stats->value = dev_stats; s->stats->timed_stats = timed_stats; TimedAverage *rd = &ts->latency[BLOCK_ACCT_READ]; TimedAverage *wr = &ts->latency[BLOCK_ACCT_WRITE]; TimedAverage *fl = &ts->latency[BLOCK_ACCT_FLUSH]; dev_stats->interval_length = ts->interval_length; dev_stats->min_rd_latency_ns = timed_average_min(rd); dev_stats->max_rd_latency_ns = timed_average_max(rd); dev_stats->avg_rd_latency_ns = timed_average_avg(rd); dev_stats->min_wr_latency_ns = timed_average_min(wr); dev_stats->max_wr_latency_ns = timed_average_max(wr); dev_stats->avg_wr_latency_ns = timed_average_avg(wr); dev_stats->min_flush_latency_ns = timed_average_min(fl); dev_stats->max_flush_latency_ns = timed_average_max(fl); dev_stats->avg_flush_latency_ns = timed_average_avg(fl); dev_stats->avg_rd_queue_depth = block_acct_queue_depth(ts, BLOCK_ACCT_READ); dev_stats->avg_wr_queue_depth = block_acct_queue_depth(ts, BLOCK_ACCT_WRITE); } } s->stats->wr_highest_offset = bs->wr_highest_offset; if (bs->file) { s->has_parent = true; s->parent = bdrv_query_stats(bs->file->bs, query_backing); } if (query_backing && bs->backing) { s->has_backing = true; s->backing = bdrv_query_stats(bs->backing->bs, query_backing); } return s; }
static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVQEDState *s = bs->opaque; QEDHeader le_header; int64_t file_size; int ret; s->bs = bs; QSIMPLEQ_INIT(&s->allocating_write_reqs); ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header)); if (ret < 0) { return ret; } qed_header_le_to_cpu(&le_header, &s->header); if (s->header.magic != QED_MAGIC) { error_setg(errp, "Image not in QED format"); return -EINVAL; } if (s->header.features & ~QED_FEATURE_MASK) { /* image uses unsupported feature bits */ char buf[64]; snprintf(buf, sizeof(buf), "%" PRIx64, s->header.features & ~QED_FEATURE_MASK); error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, bdrv_get_device_name(bs), "QED", buf); return -ENOTSUP; } if (!qed_is_cluster_size_valid(s->header.cluster_size)) { return -EINVAL; } /* Round down file size to the last cluster */ file_size = bdrv_getlength(bs->file); if (file_size < 0) { return file_size; } s->file_size = qed_start_of_cluster(s, file_size); if (!qed_is_table_size_valid(s->header.table_size)) { return -EINVAL; } if (!qed_is_image_size_valid(s->header.image_size, s->header.cluster_size, s->header.table_size)) { return -EINVAL; } if (!qed_check_table_offset(s, s->header.l1_table_offset)) { return -EINVAL; } s->table_nelems = (s->header.cluster_size * s->header.table_size) / sizeof(uint64_t); s->l2_shift = ffs(s->header.cluster_size) - 1; s->l2_mask = s->table_nelems - 1; s->l1_shift = s->l2_shift + ffs(s->table_nelems) - 1; /* Header size calculation must not overflow uint32_t */ if (s->header.header_size > UINT32_MAX / s->header.cluster_size) { return -EINVAL; } if ((s->header.features & QED_F_BACKING_FILE)) { if ((uint64_t)s->header.backing_filename_offset + s->header.backing_filename_size > s->header.cluster_size * s->header.header_size) { return -EINVAL; } ret = qed_read_string(bs->file, s->header.backing_filename_offset, s->header.backing_filename_size, bs->backing_file, sizeof(bs->backing_file)); if (ret < 0) { return ret; } if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) { pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw"); } } /* Reset unknown autoclear feature bits. This is a backwards * compatibility mechanism that allows images to be opened by older * programs, which "knock out" unknown feature bits. When an image is * opened by a newer program again it can detect that the autoclear * feature is no longer valid. */ if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 && !bdrv_is_read_only(bs->file) && !(flags & BDRV_O_INCOMING)) { s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK; ret = qed_write_header_sync(s); if (ret) { return ret; } /* From here on only known autoclear feature bits are valid */ bdrv_flush(bs->file); } s->l1_table = qed_alloc_table(s); qed_init_l2_cache(&s->l2_cache); ret = qed_read_l1_table_sync(s); if (ret) { goto out; } /* If image was not closed cleanly, check consistency */ if (!(flags & BDRV_O_CHECK) && (s->header.features & QED_F_NEED_CHECK)) { /* Read-only images cannot be fixed. There is no risk of corruption * since write operations are not possible. Therefore, allow * potentially inconsistent images to be opened read-only. This can * aid data recovery from an otherwise inconsistent image. */ if (!bdrv_is_read_only(bs->file) && !(flags & BDRV_O_INCOMING)) { BdrvCheckResult result = {0}; ret = qed_check(s, &result, true); if (ret) { goto out; } } } bdrv_qed_attach_aio_context(bs, bdrv_get_aio_context(bs)); out: if (ret) { qed_free_l2_cache(&s->l2_cache); qemu_vfree(s->l1_table); } return ret; }
static const char *print_drive(void *ptr) { return bdrv_get_device_name(ptr); }
/** * bdrv_query_image_info: * @bs: block device to examine * @p_info: location to store image information * @errp: location to store error information * * Store "flat" image information in @p_info. * * "Flat" means it does *not* query backing image information, * i.e. (*pinfo)->has_backing_image will be set to false and * (*pinfo)->backing_image to NULL even when the image does in fact have * a backing image. * * @p_info will be set only on success. On error, store error in @errp. */ void bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, Error **errp) { int64_t size; const char *backing_filename; char backing_filename2[1024]; BlockDriverInfo bdi; int ret; Error *err = NULL; ImageInfo *info; #ifdef __linux__ int fd, attr; #endif size = bdrv_getlength(bs); if (size < 0) { error_setg_errno(errp, -size, "Can't get size of device '%s'", bdrv_get_device_name(bs)); return; } info = g_new0(ImageInfo, 1); info->filename = g_strdup(bs->filename); info->format = g_strdup(bdrv_get_format_name(bs)); info->virtual_size = size; info->actual_size = bdrv_get_allocated_file_size(bs); info->has_actual_size = info->actual_size >= 0; if (bdrv_is_encrypted(bs)) { info->encrypted = true; info->has_encrypted = true; } if (bdrv_get_info(bs, &bdi) >= 0) { if (bdi.cluster_size != 0) { info->cluster_size = bdi.cluster_size; info->has_cluster_size = true; } info->dirty_flag = bdi.is_dirty; info->has_dirty_flag = true; } info->format_specific = bdrv_get_specific_info(bs); info->has_format_specific = info->format_specific != NULL; #ifdef __linux__ /* get NOCOW info */ fd = qemu_open(bs->filename, O_RDONLY | O_NONBLOCK); if (fd >= 0) { if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0 && (attr & FS_NOCOW_FL)) { info->has_nocow = true; info->nocow = true; } qemu_close(fd); } #endif backing_filename = bs->backing_file; if (backing_filename[0] != '\0') { info->backing_filename = g_strdup(backing_filename); info->has_backing_filename = true; bdrv_get_full_backing_filename(bs, backing_filename2, sizeof(backing_filename2)); if (strcmp(backing_filename, backing_filename2) != 0) { info->full_backing_filename = g_strdup(backing_filename2); info->has_full_backing_filename = true; } if (bs->backing_format[0]) { info->backing_filename_format = g_strdup(bs->backing_format); info->has_backing_filename_format = true; } } ret = bdrv_query_snapshot_info_list(bs, &info->snapshots, &err); switch (ret) { case 0: if (info->snapshots) { info->has_snapshots = true; } break; /* recoverable error */ case -ENOMEDIUM: case -ENOTSUP: error_free(err); break; default: error_propagate(errp, err); qapi_free_ImageInfo(info); return; } *p_info = info; }
/** * bdrv_query_image_info: * @bs: block device to examine * @p_info: location to store image information * @errp: location to store error information * * Store "flat" image information in @p_info. * * "Flat" means it does *not* query backing image information, * i.e. (*pinfo)->has_backing_image will be set to false and * (*pinfo)->backing_image to NULL even when the image does in fact have * a backing image. * * @p_info will be set only on success. On error, store error in @errp. */ void bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, Error **errp) { int64_t size; const char *backing_filename; BlockDriverInfo bdi; int ret; Error *err = NULL; ImageInfo *info; aio_context_acquire(bdrv_get_aio_context(bs)); size = bdrv_getlength(bs); if (size < 0) { error_setg_errno(errp, -size, "Can't get size of device '%s'", bdrv_get_device_name(bs)); goto out; } info = g_new0(ImageInfo, 1); info->filename = g_strdup(bs->filename); info->format = g_strdup(bdrv_get_format_name(bs)); info->virtual_size = size; info->actual_size = bdrv_get_allocated_file_size(bs); info->has_actual_size = info->actual_size >= 0; if (bdrv_is_encrypted(bs)) { info->encrypted = true; info->has_encrypted = true; } if (bdrv_get_info(bs, &bdi) >= 0) { if (bdi.cluster_size != 0) { info->cluster_size = bdi.cluster_size; info->has_cluster_size = true; } info->dirty_flag = bdi.is_dirty; info->has_dirty_flag = true; } info->format_specific = bdrv_get_specific_info(bs); info->has_format_specific = info->format_specific != NULL; backing_filename = bs->backing_file; if (backing_filename[0] != '\0') { char *backing_filename2 = g_malloc0(PATH_MAX); info->backing_filename = g_strdup(backing_filename); info->has_backing_filename = true; bdrv_get_full_backing_filename(bs, backing_filename2, PATH_MAX, &err); if (err) { /* Can't reconstruct the full backing filename, so we must omit * this field and apply a Best Effort to this query. */ g_free(backing_filename2); backing_filename2 = NULL; error_free(err); err = NULL; } /* Always report the full_backing_filename if present, even if it's the * same as backing_filename. That they are same is useful info. */ if (backing_filename2) { info->full_backing_filename = g_strdup(backing_filename2); info->has_full_backing_filename = true; } if (bs->backing_format[0]) { info->backing_filename_format = g_strdup(bs->backing_format); info->has_backing_filename_format = true; } g_free(backing_filename2); } ret = bdrv_query_snapshot_info_list(bs, &info->snapshots, &err); switch (ret) { case 0: if (info->snapshots) { info->has_snapshots = true; } break; /* recoverable error */ case -ENOMEDIUM: case -ENOTSUP: error_free(err); break; default: error_propagate(errp, err); qapi_free_ImageInfo(info); goto out; } *p_info = info; out: aio_context_release(bdrv_get_aio_context(bs)); }
/** * bdrv_query_image_info: * @bs: block device to examine * @p_info: location to store image information * @errp: location to store error information * * Store "flat" image information in @p_info. * * "Flat" means it does *not* query backing image information, * i.e. (*pinfo)->has_backing_image will be set to false and * (*pinfo)->backing_image to NULL even when the image does in fact have * a backing image. * * @p_info will be set only on success. On error, store error in @errp. */ void bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, Error **errp) { int64_t size; const char *backing_filename; BlockDriverInfo bdi; int ret; Error *err = NULL; ImageInfo *info; size = bdrv_getlength(bs); if (size < 0) { error_setg_errno(errp, -size, "Can't get size of device '%s'", bdrv_get_device_name(bs)); return; } info = g_new0(ImageInfo, 1); info->filename = g_strdup(bs->filename); info->format = g_strdup(bdrv_get_format_name(bs)); info->virtual_size = size; info->actual_size = bdrv_get_allocated_file_size(bs); info->has_actual_size = info->actual_size >= 0; if (bdrv_is_encrypted(bs)) { info->encrypted = true; info->has_encrypted = true; } if (bdrv_get_info(bs, &bdi) >= 0) { if (bdi.cluster_size != 0) { info->cluster_size = bdi.cluster_size; info->has_cluster_size = true; } info->dirty_flag = bdi.is_dirty; info->has_dirty_flag = true; } info->format_specific = bdrv_get_specific_info(bs); info->has_format_specific = info->format_specific != NULL; backing_filename = bs->backing_file; if (backing_filename[0] != '\0') { char *backing_filename2 = g_malloc0(PATH_MAX); info->backing_filename = g_strdup(backing_filename); info->has_backing_filename = true; bdrv_get_full_backing_filename(bs, backing_filename2, PATH_MAX, &err); if (err) { error_propagate(errp, err); qapi_free_ImageInfo(info); g_free(backing_filename2); return; } if (strcmp(backing_filename, backing_filename2) != 0) { info->full_backing_filename = g_strdup(backing_filename2); info->has_full_backing_filename = true; } if (bs->backing_format[0]) { info->backing_filename_format = g_strdup(bs->backing_format); info->has_backing_filename_format = true; } g_free(backing_filename2); } ret = bdrv_query_snapshot_info_list(bs, &info->snapshots, &err); switch (ret) { case 0: if (info->snapshots) { info->has_snapshots = true; } break; /* recoverable error */ case -ENOMEDIUM: case -ENOTSUP: error_free(err); break; default: error_propagate(errp, err); qapi_free_ImageInfo(info); return; } *p_info = info; }