return NULL;
}
- bs = g_malloc0(sizeof(BlockDriverState));
+ bs = g_new0(BlockDriverState, 1);
QLIST_INIT(&bs->dirty_bitmaps);
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
if (device_name[0] != '\0') {
} else {
bs->filename[0] = '\0';
}
+ pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), bs->filename);
bs->drv = drv;
bs->opaque = g_malloc0(drv->instance_size);
}
}
+ bdrv_refresh_filename(bs);
+
/* For snapshot=on, create a temporary qcow2 overlay. bs points to the
* temporary snapshot afterwards. */
if (snapshot_flags) {
void bdrv_close(BlockDriverState *bs)
{
+ BdrvAioNotifier *ban, *ban_next;
+
if (bs->job) {
block_job_cancel_sync(bs->job);
}
bs->zero_beyond_eof = false;
QDECREF(bs->options);
bs->options = NULL;
+ QDECREF(bs->full_open_options);
+ bs->full_open_options = NULL;
if (bs->file != NULL) {
bdrv_unref(bs->file);
if (bs->io_limits_enabled) {
bdrv_io_limits_disable(bs);
}
+
+ QLIST_FOREACH_SAFE(ban, &bs->aio_notifiers, list, ban_next) {
+ g_free(ban);
+ }
+ QLIST_INIT(&bs->aio_notifiers);
}
void bdrv_close_all(void)
*/
int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
{
+ if (bs->drv == NULL) {
+ return -ENOMEDIUM;
+ }
if (bs->drv->bdrv_check == NULL) {
return -ENOTSUP;
}
if (!drv)
return -ENOMEDIUM;
-
+
if (!bs->backing_hd) {
return -ENOTSUP;
}
* into our deletion queue, until we hit the 'base'
*/
while (intermediate) {
- intermediate_state = g_malloc0(sizeof(BlkIntermediateStates));
+ intermediate_state = g_new0(BlkIntermediateStates, 1);
intermediate_state->bs = intermediate;
QSIMPLEQ_INSERT_TAIL(&states_to_delete, intermediate_state, entry);
bdrv_set_dirty(bs, sector_num, nb_sectors);
- if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
- bs->wr_highest_sector = sector_num + nb_sectors - 1;
- }
+ block_acct_highest_sector(&bs->stats, sector_num, nb_sectors);
+
if (bs->growable && ret >= 0) {
bs->total_sectors = MAX(bs->total_sectors, sector_num + nb_sectors);
}
}
}
+static void send_qmp_error_event(BlockDriverState *bs,
+ BlockErrorAction action,
+ bool is_read, int error)
+{
+ BlockErrorAction ac;
+
+ ac = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
+ qapi_event_send_block_io_error(bdrv_get_device_name(bs), ac, 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).
* also ensures that the STOP/RESUME pair of events is emitted.
*/
qemu_system_vmstop_request_prepare();
- qapi_event_send_block_io_error(bdrv_get_device_name(bs),
- is_read ? IO_OPERATION_TYPE_READ :
- IO_OPERATION_TYPE_WRITE,
- action, &error_abort);
+ send_qmp_error_event(bs, action, is_read, error);
qemu_system_vmstop_request(RUN_STATE_IO_ERROR);
} else {
- qapi_event_send_block_io_error(bdrv_get_device_name(bs),
- is_read ? IO_OPERATION_TYPE_READ :
- IO_OPERATION_TYPE_WRITE,
- action, &error_abort);
+ send_qmp_error_event(bs, action, is_read, error);
}
}
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 (!found) {
- formats = g_realloc(formats, (count + 1) * sizeof(char *));
+ formats = g_renew(const char *, formats, count + 1);
formats[count++] = drv->format_name;
- it(opaque, drv->format_name);
}
}
}
+
+ qsort(formats, count, sizeof(formats[0]), qsort_strcmp);
+
+ for (i = 0; i < count; i++) {
+ it(opaque, formats[i]);
+ }
+
g_free(formats);
}
// Add the second request
qemu_iovec_concat(qiov, reqs[i].qiov, 0, reqs[i].qiov->size);
+ // Add tail of first request, if necessary
+ if (qiov->size < reqs[outidx].qiov->size) {
+ qemu_iovec_concat(qiov, reqs[outidx].qiov, qiov->size,
+ reqs[outidx].qiov->size - qiov->size);
+ }
+
reqs[outidx].nb_sectors = qiov->size >> 9;
reqs[outidx].qiov = qiov;
errno = -bitmap_size;
return NULL;
}
- bitmap = g_malloc0(sizeof(BdrvDirtyBitmap));
+ bitmap = g_new0(BdrvDirtyBitmap, 1);
bitmap->bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1);
QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
return bitmap;
BlockDirtyInfoList **plist = &list;
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
- BlockDirtyInfo *info = g_malloc0(sizeof(BlockDirtyInfo));
- BlockDirtyInfoList *entry = g_malloc0(sizeof(BlockDirtyInfoList));
+ BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1);
+ BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1);
info->count = bdrv_get_dirty_count(bs, bm);
info->granularity =
((int64_t) BDRV_SECTOR_SIZE << hbitmap_granularity(bm->bitmap));
BdrvOpBlocker *blocker;
assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
- blocker = g_malloc0(sizeof(BdrvOpBlocker));
+ blocker = g_new0(BdrvOpBlocker, 1);
blocker->reason = reason;
QLIST_INSERT_HEAD(&bs->op_blockers[op], blocker, list);
}
}
}
-void
-bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, int64_t bytes,
- enum BlockAcctType type)
-{
- assert(type < BDRV_MAX_IOTYPE);
-
- cookie->bytes = bytes;
- cookie->start_time_ns = get_clock();
- cookie->type = type;
-}
-
-void
-bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie)
-{
- assert(cookie->type < BDRV_MAX_IOTYPE);
-
- bs->nr_bytes[cookie->type] += cookie->bytes;
- bs->nr_ops[cookie->type]++;
- bs->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
-}
-
void bdrv_img_create(const char *filename, const char *fmt,
const char *base_filename, const char *base_fmt,
char *options, uint64_t img_size, int flags,
void bdrv_detach_aio_context(BlockDriverState *bs)
{
+ BdrvAioNotifier *baf;
+
if (!bs->drv) {
return;
}
+ QLIST_FOREACH(baf, &bs->aio_notifiers, list) {
+ baf->detach_aio_context(baf->opaque);
+ }
+
if (bs->io_limits_enabled) {
throttle_detach_aio_context(&bs->throttle_state);
}
void bdrv_attach_aio_context(BlockDriverState *bs,
AioContext *new_context)
{
+ BdrvAioNotifier *ban;
+
if (!bs->drv) {
return;
}
if (bs->io_limits_enabled) {
throttle_attach_aio_context(&bs->throttle_state, new_context);
}
+
+ QLIST_FOREACH(ban, &bs->aio_notifiers, list) {
+ ban->attached_aio_context(new_context, ban->opaque);
+ }
}
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
aio_context_release(new_context);
}
+void bdrv_add_aio_context_notifier(BlockDriverState *bs,
+ void (*attached_aio_context)(AioContext *new_context, void *opaque),
+ void (*detach_aio_context)(void *opaque), void *opaque)
+{
+ BdrvAioNotifier *ban = g_new(BdrvAioNotifier, 1);
+ *ban = (BdrvAioNotifier){
+ .attached_aio_context = attached_aio_context,
+ .detach_aio_context = detach_aio_context,
+ .opaque = opaque
+ };
+
+ QLIST_INSERT_HEAD(&bs->aio_notifiers, ban, list);
+}
+
+void bdrv_remove_aio_context_notifier(BlockDriverState *bs,
+ void (*attached_aio_context)(AioContext *,
+ void *),
+ void (*detach_aio_context)(void *),
+ void *opaque)
+{
+ BdrvAioNotifier *ban, *ban_next;
+
+ QLIST_FOREACH_SAFE(ban, &bs->aio_notifiers, list, ban_next) {
+ if (ban->attached_aio_context == attached_aio_context &&
+ ban->detach_aio_context == detach_aio_context &&
+ ban->opaque == opaque)
+ {
+ QLIST_REMOVE(ban, list);
+ g_free(ban);
+
+ return;
+ }
+ }
+
+ abort();
+}
+
void bdrv_add_before_write_notifier(BlockDriverState *bs,
NotifierWithReturn *notifier)
{
bdrv_flush_io_queue(bs->file);
}
}
+
+static bool append_open_options(QDict *d, BlockDriverState *bs)
+{
+ const QDictEntry *entry;
+ bool found_any = false;
+
+ for (entry = qdict_first(bs->options); entry;
+ entry = qdict_next(bs->options, entry))
+ {
+ /* Only take options for this level and exclude all non-driver-specific
+ * options */
+ if (!strchr(qdict_entry_key(entry), '.') &&
+ strcmp(qdict_entry_key(entry), "node-name"))
+ {
+ qobject_incref(qdict_entry_value(entry));
+ qdict_put_obj(d, qdict_entry_key(entry), qdict_entry_value(entry));
+ found_any = true;
+ }
+ }
+
+ return found_any;
+}
+
+/* Updates the following BDS fields:
+ * - exact_filename: A filename which may be used for opening a block device
+ * which (mostly) equals the given BDS (even without any
+ * other options; so reading and writing must return the same
+ * results, but caching etc. may be different)
+ * - full_open_options: Options which, when given when opening a block device
+ * (without a filename), result in a BDS (mostly)
+ * equalling the given one
+ * - filename: If exact_filename is set, it is copied here. Otherwise,
+ * full_open_options is converted to a JSON object, prefixed with
+ * "json:" (for use through the JSON pseudo protocol) and put here.
+ */
+void bdrv_refresh_filename(BlockDriverState *bs)
+{
+ BlockDriver *drv = bs->drv;
+ QDict *opts;
+
+ if (!drv) {
+ return;
+ }
+
+ /* This BDS's file name will most probably depend on its file's name, so
+ * refresh that first */
+ if (bs->file) {
+ bdrv_refresh_filename(bs->file);
+ }
+
+ if (drv->bdrv_refresh_filename) {
+ /* Obsolete information is of no use here, so drop the old file name
+ * information before refreshing it */
+ bs->exact_filename[0] = '\0';
+ if (bs->full_open_options) {
+ QDECREF(bs->full_open_options);
+ bs->full_open_options = NULL;
+ }
+
+ drv->bdrv_refresh_filename(bs);
+ } else if (bs->file) {
+ /* Try to reconstruct valid information from the underlying file */
+ bool has_open_options;
+
+ bs->exact_filename[0] = '\0';
+ if (bs->full_open_options) {
+ QDECREF(bs->full_open_options);
+ bs->full_open_options = NULL;
+ }
+
+ opts = qdict_new();
+ has_open_options = append_open_options(opts, bs);
+
+ /* If no specific options have been given for this BDS, the filename of
+ * the underlying file should suffice for this one as well */
+ if (bs->file->exact_filename[0] && !has_open_options) {
+ strcpy(bs->exact_filename, bs->file->exact_filename);
+ }
+ /* Reconstructing the full options QDict is simple for most format block
+ * drivers, as long as the full options are known for the underlying
+ * file BDS. The full options QDict of that file BDS should somehow
+ * contain a representation of the filename, therefore the following
+ * suffices without querying the (exact_)filename of this BDS. */
+ if (bs->file->full_open_options) {
+ qdict_put_obj(opts, "driver",
+ QOBJECT(qstring_from_str(drv->format_name)));
+ QINCREF(bs->file->full_open_options);
+ qdict_put_obj(opts, "file", QOBJECT(bs->file->full_open_options));
+
+ bs->full_open_options = opts;
+ } else {
+ QDECREF(opts);
+ }
+ } else if (!bs->full_open_options && qdict_size(bs->options)) {
+ /* There is no underlying file BDS (at least referenced by BDS.file),
+ * so the full options QDict should be equal to the options given
+ * specifically for this block device when it was opened (plus the
+ * driver specification).
+ * Because those options don't change, there is no need to update
+ * full_open_options when it's already set. */
+
+ opts = qdict_new();
+ append_open_options(opts, bs);
+ qdict_put_obj(opts, "driver",
+ QOBJECT(qstring_from_str(drv->format_name)));
+
+ if (bs->exact_filename[0]) {
+ /* This may not work for all block protocol drivers (some may
+ * require this filename to be parsed), but we have to find some
+ * default solution here, so just include it. If some block driver
+ * does not support pure options without any filename at all or
+ * needs some special format of the options QDict, it needs to
+ * implement the driver-specific bdrv_refresh_filename() function.
+ */
+ qdict_put_obj(opts, "filename",
+ QOBJECT(qstring_from_str(bs->exact_filename)));
+ }
+
+ bs->full_open_options = opts;
+ }
+
+ if (bs->exact_filename[0]) {
+ pstrcpy(bs->filename, sizeof(bs->filename), bs->exact_filename);
+ } else if (bs->full_open_options) {
+ QString *json = qobject_to_json(QOBJECT(bs->full_open_options));
+ snprintf(bs->filename, sizeof(bs->filename), "json:%s",
+ qstring_get_str(json));
+ QDECREF(json);
+ }
+}
+
+/* This accessor function purpose is to allow the device models to access the
+ * BlockAcctStats structure embedded inside a BlockDriverState without being
+ * aware of the BlockDriverState structure layout.
+ * It will go away when the BlockAcctStats structure will be moved inside
+ * the device models.
+ */
+BlockAcctStats *bdrv_get_stats(BlockDriverState *bs)
+{
+ return &bs->stats;
+}