#include <windows.h>
#endif
+static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
{
BlockDriverState *bs;
- bs = qemu_mallocz(sizeof(BlockDriverState));
+ bs = g_malloc0(sizeof(BlockDriverState));
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
if (device_name[0] != '\0') {
QTAILQ_INSERT_TAIL(&bdrv_states, bs, list);
return 0;
}
+/**
+ * Set open flags for a given cache mode
+ *
+ * Return 0 on success, -1 if the cache mode was invalid.
+ */
+int bdrv_parse_cache_flags(const char *mode, int *flags)
+{
+ *flags &= ~BDRV_O_CACHE_MASK;
+
+ if (!strcmp(mode, "off") || !strcmp(mode, "none")) {
+ *flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
+ } else if (!strcmp(mode, "directsync")) {
+ *flags |= BDRV_O_NOCACHE;
+ } else if (!strcmp(mode, "writeback")) {
+ *flags |= BDRV_O_CACHE_WB;
+ } else if (!strcmp(mode, "unsafe")) {
+ *flags |= BDRV_O_CACHE_WB;
+ *flags |= BDRV_O_NO_FLUSH;
+ } else if (!strcmp(mode, "writethrough")) {
+ /* this is the default */
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* Common part for opening disk images and files
*/
bs->encrypted = 0;
bs->valid_key = 0;
bs->open_flags = flags;
- /* buffer_alignment defaulted to 512, drivers can change this value */
bs->buffer_alignment = 512;
pstrcpy(bs->filename, sizeof(bs->filename), filename);
}
bs->drv = drv;
- bs->opaque = qemu_mallocz(drv->instance_size);
+ bs->opaque = g_malloc0(drv->instance_size);
if (flags & BDRV_O_CACHE_WB)
bs->enable_write_cache = 1;
bdrv_delete(bs->file);
bs->file = NULL;
}
- qemu_free(bs->opaque);
+ g_free(bs->opaque);
bs->opaque = NULL;
bs->drv = NULL;
return ret;
}
if (!bdrv_key_required(bs)) {
- /* call the change callback */
- bs->media_changed = 1;
- if (bs->change_cb)
- bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
+ bdrv_dev_change_media_cb(bs, true);
}
return 0;
bs->backing_hd = NULL;
}
bs->drv->bdrv_close(bs);
- qemu_free(bs->opaque);
+ g_free(bs->opaque);
#ifdef _WIN32
if (bs->is_temporary) {
unlink(bs->filename);
bdrv_close(bs->file);
}
- /* call the change callback */
- bs->media_changed = 1;
- if (bs->change_cb)
- bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
+ bdrv_dev_change_media_cb(bs, false);
}
}
void bdrv_delete(BlockDriverState *bs)
{
- assert(!bs->peer);
+ assert(!bs->dev);
/* remove from list, if necessary */
bdrv_make_anon(bs);
}
assert(bs != bs_snapshots);
- qemu_free(bs);
+ g_free(bs);
}
-int bdrv_attach(BlockDriverState *bs, DeviceState *qdev)
+int bdrv_attach_dev(BlockDriverState *bs, void *dev)
+/* TODO change to DeviceState *dev when all users are qdevified */
{
- if (bs->peer) {
+ if (bs->dev) {
return -EBUSY;
}
- bs->peer = qdev;
+ bs->dev = dev;
return 0;
}
-void bdrv_detach(BlockDriverState *bs, DeviceState *qdev)
+/* TODO qdevified devices don't use this, remove when devices are qdevified */
+void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev)
{
- assert(bs->peer == qdev);
- bs->peer = NULL;
- bs->change_cb = NULL;
- bs->change_opaque = NULL;
+ if (bdrv_attach_dev(bs, dev) < 0) {
+ abort();
+ }
}
-DeviceState *bdrv_get_attached(BlockDriverState *bs)
+void bdrv_detach_dev(BlockDriverState *bs, void *dev)
+/* TODO change to DeviceState *dev when all users are qdevified */
{
- return bs->peer;
+ assert(bs->dev == dev);
+ bs->dev = NULL;
+ bs->dev_ops = NULL;
+ bs->dev_opaque = NULL;
+ bs->buffer_alignment = 512;
+}
+
+/* TODO change to return DeviceState * when all users are qdevified */
+void *bdrv_get_attached_dev(BlockDriverState *bs)
+{
+ return bs->dev;
+}
+
+void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
+ void *opaque)
+{
+ bs->dev_ops = ops;
+ bs->dev_opaque = opaque;
+ if (bdrv_dev_has_removable_media(bs) && bs == bs_snapshots) {
+ bs_snapshots = NULL;
+ }
+}
+
+static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
+{
+ if (bs->dev_ops && bs->dev_ops->change_media_cb) {
+ bs->dev_ops->change_media_cb(bs->dev_opaque, load);
+ }
+}
+
+bool bdrv_dev_has_removable_media(BlockDriverState *bs)
+{
+ return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
+}
+
+bool bdrv_dev_is_tray_open(BlockDriverState *bs)
+{
+ if (bs->dev_ops && bs->dev_ops->is_tray_open) {
+ return bs->dev_ops->is_tray_open(bs->dev_opaque);
+ }
+ return false;
+}
+
+static void bdrv_dev_resize_cb(BlockDriverState *bs)
+{
+ if (bs->dev_ops && bs->dev_ops->resize_cb) {
+ bs->dev_ops->resize_cb(bs->dev_opaque);
+ }
+}
+
+bool bdrv_dev_is_medium_locked(BlockDriverState *bs)
+{
+ if (bs->dev_ops && bs->dev_ops->is_medium_locked) {
+ return bs->dev_ops->is_medium_locked(bs->dev_opaque);
+ }
+ return false;
}
/*
}
total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
- buf = qemu_malloc(COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);
+ buf = g_malloc(COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);
for (sector = 0; sector < total_sectors; sector += n) {
if (drv->bdrv_is_allocated(bs, sector, COMMIT_BUF_SECTORS, &n)) {
bdrv_flush(bs->backing_hd);
ro_cleanup:
- qemu_free(buf);
+ g_free(buf);
if (ro) {
/* re-open as RO */
return ret;
}
- /* No flush needed for cache=writethrough, it uses O_DSYNC */
- if ((bs->open_flags & BDRV_O_CACHE_MASK) != 0) {
+ /* No flush needed for cache modes that use O_DSYNC */
+ if ((bs->open_flags & BDRV_O_CACHE_WB) != 0) {
bdrv_flush(bs);
}
ret = drv->bdrv_truncate(bs, offset);
if (ret == 0) {
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
- if (bs->change_cb) {
- bs->change_cb(bs->change_opaque, CHANGE_SIZE);
- }
+ bdrv_dev_resize_cb(bs);
}
return ret;
}
if (!drv)
return -ENOMEDIUM;
- if (bs->growable || bs->removable) {
+ if (bs->growable || bdrv_dev_has_removable_media(bs)) {
if (drv->bdrv_getlength) {
return drv->bdrv_getlength(bs);
}
uint8_t end_cyl; /* end cylinder */
uint32_t start_sect; /* starting sector counting from 0 */
uint32_t nr_sects; /* nr of sectors in partition */
-} __attribute__((packed));
+} QEMU_PACKED;
/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */
static int guess_disk_lchs(BlockDriverState *bs,
return is_read ? bs->on_read_error : bs->on_write_error;
}
-void bdrv_set_removable(BlockDriverState *bs, int removable)
-{
- bs->removable = removable;
- if (removable && bs == bs_snapshots) {
- bs_snapshots = NULL;
- }
-}
-
-int bdrv_is_removable(BlockDriverState *bs)
-{
- return bs->removable;
-}
-
int bdrv_is_read_only(BlockDriverState *bs)
{
return bs->read_only;
return bs->enable_write_cache;
}
-/* XXX: no longer used */
-void bdrv_set_change_cb(BlockDriverState *bs,
- void (*change_cb)(void *opaque, int reason),
- void *opaque)
-{
- bs->change_cb = change_cb;
- bs->change_opaque = opaque;
-}
-
int bdrv_is_encrypted(BlockDriverState *bs)
{
if (bs->backing_hd && bs->backing_hd->encrypted)
} else if (!bs->valid_key) {
bs->valid_key = 1;
/* call the change callback now, we skipped it on open */
- bs->media_changed = 1;
- if (bs->change_cb)
- bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
+ bdrv_dev_change_media_cb(bs, true);
}
return ret;
}
BlockDriverState *bs;
QTAILQ_FOREACH(bs, &bdrv_states, list) {
- if (bs->drv && !bdrv_is_read_only(bs) &&
- (!bdrv_is_removable(bs) || bdrv_is_inserted(bs))) {
+ if (!bdrv_is_read_only(bs) && bdrv_is_inserted(bs)) {
bdrv_flush(bs);
}
}
if (qdict_get_bool(bs_dict, "removable")) {
monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked"));
+ monitor_printf(mon, " tray-open=%d",
+ qdict_get_bool(bs_dict, "tray-open"));
}
-
if (qdict_haskey(bs_dict, "inserted")) {
QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
QTAILQ_FOREACH(bs, &bdrv_states, list) {
QObject *bs_obj;
+ QDict *bs_dict;
bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': 'unknown', "
"'removable': %i, 'locked': %i }",
- bs->device_name, bs->removable,
- bs->locked);
-
+ bs->device_name,
+ bdrv_dev_has_removable_media(bs),
+ bdrv_dev_is_medium_locked(bs));
+ bs_dict = qobject_to_qdict(bs_obj);
+
+ if (bdrv_dev_has_removable_media(bs)) {
+ qdict_put(bs_dict, "tray-open",
+ qbool_from_int(bdrv_dev_is_tray_open(bs)));
+ }
if (bs->drv) {
QObject *obj;
- QDict *bs_dict = qobject_to_qdict(bs_obj);
obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, "
"'encrypted': %i }",
" wr_bytes=%" PRId64
" rd_operations=%" PRId64
" wr_operations=%" PRId64
+ " flush_operations=%" PRId64
+ " wr_total_time_ns=%" PRId64
+ " rd_total_time_ns=%" PRId64
+ " flush_total_time_ns=%" PRId64
"\n",
qdict_get_int(qdict, "rd_bytes"),
qdict_get_int(qdict, "wr_bytes"),
qdict_get_int(qdict, "rd_operations"),
- qdict_get_int(qdict, "wr_operations"));
+ qdict_get_int(qdict, "wr_operations"),
+ qdict_get_int(qdict, "flush_operations"),
+ qdict_get_int(qdict, "wr_total_time_ns"),
+ qdict_get_int(qdict, "rd_total_time_ns"),
+ qdict_get_int(qdict, "flush_total_time_ns"));
}
void bdrv_stats_print(Monitor *mon, const QObject *data)
"'wr_bytes': %" PRId64 ","
"'rd_operations': %" PRId64 ","
"'wr_operations': %" PRId64 ","
- "'wr_highest_offset': %" PRId64
+ "'wr_highest_offset': %" PRId64 ","
+ "'flush_operations': %" PRId64 ","
+ "'wr_total_time_ns': %" PRId64 ","
+ "'rd_total_time_ns': %" PRId64 ","
+ "'flush_total_time_ns': %" PRId64
"} }",
- bs->rd_bytes, bs->wr_bytes,
- bs->rd_ops, bs->wr_ops,
+ bs->nr_bytes[BDRV_ACCT_READ],
+ bs->nr_bytes[BDRV_ACCT_WRITE],
+ bs->nr_ops[BDRV_ACCT_READ],
+ bs->nr_ops[BDRV_ACCT_WRITE],
bs->wr_highest_sector *
- (uint64_t)BDRV_SECTOR_SIZE);
+ (uint64_t)BDRV_SECTOR_SIZE,
+ bs->nr_ops[BDRV_ACCT_FLUSH],
+ bs->total_time_ns[BDRV_ACCT_WRITE],
+ bs->total_time_ns[BDRV_ACCT_READ],
+ bs->total_time_ns[BDRV_ACCT_FLUSH]);
dict = qobject_to_qdict(res);
if (*bs->device_name) {
int bdrv_can_snapshot(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
- if (!drv || bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
+ if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
return 0;
}
return buf;
}
-
/**************************************************************/
/* async I/Os */
BlockDriverCompletionFunc *cb, void *opaque)
{
BlockDriver *drv = bs->drv;
- BlockDriverAIOCB *ret;
trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
if (bdrv_check_request(bs, sector_num, nb_sectors))
return NULL;
- ret = drv->bdrv_aio_readv(bs, sector_num, qiov, nb_sectors,
- cb, opaque);
-
- if (ret) {
- /* Update stats even though technically transfer has not happened. */
- bs->rd_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
- bs->rd_ops ++;
- }
-
- return ret;
+ return drv->bdrv_aio_readv(bs, sector_num, qiov, nb_sectors,
+ cb, opaque);
}
typedef struct BlockCompleteData {
set_dirty_bitmap(b->bs, b->sector_num, b->nb_sectors, 1);
}
b->cb(b->opaque, ret);
- qemu_free(b);
+ g_free(b);
}
static BlockCompleteData *blk_dirty_cb_alloc(BlockDriverState *bs,
BlockDriverCompletionFunc *cb,
void *opaque)
{
- BlockCompleteData *blkdata = qemu_mallocz(sizeof(BlockCompleteData));
+ BlockCompleteData *blkdata = g_malloc0(sizeof(BlockCompleteData));
blkdata->bs = bs;
blkdata->cb = cb;
cb, opaque);
if (ret) {
- /* Update stats even though technically transfer has not happened. */
- bs->wr_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
- bs->wr_ops ++;
if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
bs->wr_highest_sector = sector_num + nb_sectors - 1;
}
if (mcb->callbacks[i].free_qiov) {
qemu_iovec_destroy(mcb->callbacks[i].free_qiov);
}
- qemu_free(mcb->callbacks[i].free_qiov);
+ g_free(mcb->callbacks[i].free_qiov);
qemu_vfree(mcb->callbacks[i].free_buf);
}
}
mcb->num_requests--;
if (mcb->num_requests == 0) {
multiwrite_user_cb(mcb);
- qemu_free(mcb);
+ g_free(mcb);
}
}
if (merge) {
size_t size;
- QEMUIOVector *qiov = qemu_mallocz(sizeof(*qiov));
+ QEMUIOVector *qiov = g_malloc0(sizeof(*qiov));
qemu_iovec_init(qiov,
reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1);
}
// Create MultiwriteCB structure
- mcb = qemu_mallocz(sizeof(*mcb) + num_reqs * sizeof(*mcb->callbacks));
+ mcb = g_malloc0(sizeof(*mcb) + num_reqs * sizeof(*mcb->callbacks));
mcb->num_requests = 0;
mcb->num_callbacks = num_reqs;
for (i = 0; i < mcb->num_callbacks; i++) {
reqs[i].error = -EIO;
}
- qemu_free(mcb);
+ g_free(mcb);
return -1;
}
acb = pool->free_aiocb;
pool->free_aiocb = acb->next;
} else {
- acb = qemu_mallocz(pool->aiocb_size);
+ acb = g_malloc0(pool->aiocb_size);
acb->pool = pool;
}
acb->bs = bs;
int bdrv_is_inserted(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
- int ret;
+
if (!drv)
return 0;
if (!drv->bdrv_is_inserted)
- return !bs->tray_open;
- ret = drv->bdrv_is_inserted(bs);
- return ret;
+ return 1;
+ return drv->bdrv_is_inserted(bs);
}
/**
- * Return TRUE if the media changed since the last call to this
- * function. It is currently only used for floppy disks
+ * Return whether the media changed since the last call to this
+ * function, or -ENOTSUP if we don't know. Most drivers don't know.
*/
int bdrv_media_changed(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
- int ret;
- if (!drv || !drv->bdrv_media_changed)
- ret = -ENOTSUP;
- else
- ret = drv->bdrv_media_changed(bs);
- if (ret == -ENOTSUP)
- ret = bs->media_changed;
- bs->media_changed = 0;
- return ret;
+ if (drv && drv->bdrv_media_changed) {
+ return drv->bdrv_media_changed(bs);
+ }
+ return -ENOTSUP;
}
/**
* If eject_flag is TRUE, eject the media. Otherwise, close the tray
*/
-int bdrv_eject(BlockDriverState *bs, int eject_flag)
+void bdrv_eject(BlockDriverState *bs, int eject_flag)
{
BlockDriver *drv = bs->drv;
- if (eject_flag && bs->locked) {
- return -EBUSY;
- }
-
if (drv && drv->bdrv_eject) {
drv->bdrv_eject(bs, eject_flag);
}
- bs->tray_open = eject_flag;
- return 0;
-}
-
-int bdrv_is_locked(BlockDriverState *bs)
-{
- return bs->locked;
}
/**
* Lock or unlock the media (if it is locked, the user won't be able
* to eject it manually).
*/
-void bdrv_set_locked(BlockDriverState *bs, int locked)
+void bdrv_lock_medium(BlockDriverState *bs, bool locked)
{
BlockDriver *drv = bs->drv;
- trace_bdrv_set_locked(bs, locked);
+ trace_bdrv_lock_medium(bs, locked);
- bs->locked = locked;
- if (drv && drv->bdrv_set_locked) {
- drv->bdrv_set_locked(bs, locked);
+ if (drv && drv->bdrv_lock_medium) {
+ drv->bdrv_lock_medium(bs, locked);
}
}
return NULL;
}
-
+void bdrv_set_buffer_alignment(BlockDriverState *bs, int align)
+{
+ bs->buffer_alignment = align;
+}
void *qemu_blockalign(BlockDriverState *bs, size_t size)
{
BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
- bs->dirty_bitmap = qemu_mallocz(bitmap_size);
+ bs->dirty_bitmap = g_malloc0(bitmap_size);
}
} else {
if (bs->dirty_bitmap) {
- qemu_free(bs->dirty_bitmap);
+ g_free(bs->dirty_bitmap);
bs->dirty_bitmap = NULL;
}
}
return bs->in_use;
}
+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;
+}
+
int 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)