#include "monitor.h"
#include "block_int.h"
#include "module.h"
+#include "qemu-objects.h"
#ifdef CONFIG_BSD
#include <sys/types.h>
#include <windows.h>
#endif
-#define SECTOR_BITS 9
-#define SECTOR_SIZE (1 << SECTOR_BITS)
-
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
static BlockDriver *first_drv;
+/* If non-zero, use only whitelisted block drivers */
+static int use_bdrv_whitelist;
+
int path_is_absolute(const char *path)
{
const char *p;
return NULL;
}
+static int bdrv_is_whitelisted(BlockDriver *drv)
+{
+ static const char *whitelist[] = {
+ CONFIG_BDRV_WHITELIST
+ };
+ const char **p;
+
+ if (!whitelist[0])
+ return 1; /* no whitelist, anything goes */
+
+ for (p = whitelist; *p; p++) {
+ if (!strcmp(drv->format_name, *p)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+BlockDriver *bdrv_find_whitelisted_format(const char *format_name)
+{
+ BlockDriver *drv = bdrv_find_format(format_name);
+ return drv && bdrv_is_whitelisted(drv) ? drv : NULL;
+}
+
int bdrv_create(BlockDriver *drv, const char* filename,
QEMUOptionParameter *options)
{
bdrv_delete(bs1);
return ret;
}
- total_size = bdrv_getlength(bs1) >> SECTOR_BITS;
+ total_size = bdrv_getlength(bs1) >> BDRV_SECTOR_BITS;
if (bs1->drv && bs1->drv->protocol_name)
is_protocol = 1;
(flags & (BDRV_O_CACHE_MASK|BDRV_O_NATIVE_AIO));
else
open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
- ret = drv->bdrv_open(bs, filename, open_flags);
+ if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv))
+ ret = -ENOTSUP;
+ else
+ ret = drv->bdrv_open(bs, filename, open_flags);
if ((ret == -EACCES || ret == -EPERM) && !(flags & BDRV_O_FILE)) {
ret = drv->bdrv_open(bs, filename, open_flags & ~BDRV_O_RDWR);
bs->read_only = 1;
return ret;
}
if (drv->bdrv_getlength) {
- bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
+ bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
}
#ifndef _WIN32
if (bs->is_temporary) {
return -ENOTSUP;
}
- total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
+ total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
for (i = 0; i < total_sectors;) {
if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {
for(j = 0; j < n; j++) {
return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
}
+static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
+ int nb_sectors, int dirty)
+{
+ int64_t start, end;
+ unsigned long val, idx, bit;
+
+ start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK;
+ end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK;
+
+ for (; start <= end; start++) {
+ idx = start / (sizeof(unsigned long) * 8);
+ bit = start % (sizeof(unsigned long) * 8);
+ val = bs->dirty_bitmap[idx];
+ if (dirty) {
+ val |= 1 << bit;
+ } else {
+ val &= ~(1 << bit);
+ }
+ bs->dirty_bitmap[idx] = val;
+ }
+}
+
/* Return < 0 if error. Important errors are:
-EIO generic I/O error (may happen for all errors)
-ENOMEDIUM No media inserted.
if (bdrv_check_request(bs, sector_num, nb_sectors))
return -EIO;
+ if (bs->dirty_bitmap) {
+ set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+ }
+
return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
}
int bdrv_pread(BlockDriverState *bs, int64_t offset,
void *buf, int count1)
{
- uint8_t tmp_buf[SECTOR_SIZE];
+ uint8_t tmp_buf[BDRV_SECTOR_SIZE];
int len, nb_sectors, count;
int64_t sector_num;
count = count1;
/* first read to align to sector start */
- len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);
+ len = (BDRV_SECTOR_SIZE - offset) & (BDRV_SECTOR_SIZE - 1);
if (len > count)
len = count;
- sector_num = offset >> SECTOR_BITS;
+ sector_num = offset >> BDRV_SECTOR_BITS;
if (len > 0) {
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
return -EIO;
- memcpy(buf, tmp_buf + (offset & (SECTOR_SIZE - 1)), len);
+ memcpy(buf, tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), len);
count -= len;
if (count == 0)
return count1;
}
/* read the sectors "in place" */
- nb_sectors = count >> SECTOR_BITS;
+ nb_sectors = count >> BDRV_SECTOR_BITS;
if (nb_sectors > 0) {
if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0)
return -EIO;
sector_num += nb_sectors;
- len = nb_sectors << SECTOR_BITS;
+ len = nb_sectors << BDRV_SECTOR_BITS;
buf += len;
count -= len;
}
int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
const void *buf, int count1)
{
- uint8_t tmp_buf[SECTOR_SIZE];
+ uint8_t tmp_buf[BDRV_SECTOR_SIZE];
int len, nb_sectors, count;
int64_t sector_num;
count = count1;
/* first write to align to sector start */
- len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);
+ len = (BDRV_SECTOR_SIZE - offset) & (BDRV_SECTOR_SIZE - 1);
if (len > count)
len = count;
- sector_num = offset >> SECTOR_BITS;
+ sector_num = offset >> BDRV_SECTOR_BITS;
if (len > 0) {
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
return -EIO;
- memcpy(tmp_buf + (offset & (SECTOR_SIZE - 1)), buf, len);
+ memcpy(tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), buf, len);
if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
return -EIO;
count -= len;
}
/* write the sectors "in place" */
- nb_sectors = count >> SECTOR_BITS;
+ nb_sectors = count >> BDRV_SECTOR_BITS;
if (nb_sectors > 0) {
if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0)
return -EIO;
sector_num += nb_sectors;
- len = nb_sectors << SECTOR_BITS;
+ len = nb_sectors << BDRV_SECTOR_BITS;
buf += len;
count -= len;
}
return -ENOMEDIUM;
if (!drv->bdrv_getlength) {
/* legacy mode */
- return bs->total_sectors * SECTOR_SIZE;
+ return bs->total_sectors * BDRV_SECTOR_SIZE;
}
return drv->bdrv_getlength(bs);
}
if (length < 0)
length = 0;
else
- length = length >> SECTOR_BITS;
+ length = length >> BDRV_SECTOR_BITS;
*nb_sectors_ptr = length;
}
return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum);
}
-void bdrv_info(Monitor *mon)
+static void bdrv_print_dict(QObject *obj, void *opaque)
{
+ QDict *bs_dict;
+ Monitor *mon = opaque;
+
+ bs_dict = qobject_to_qdict(obj);
+
+ monitor_printf(mon, "%s: type=%s removable=%d",
+ qdict_get_str(bs_dict, "device"),
+ qdict_get_str(bs_dict, "type"),
+ qdict_get_bool(bs_dict, "removable"));
+
+ if (qdict_get_bool(bs_dict, "removable")) {
+ monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked"));
+ }
+
+ if (qdict_haskey(bs_dict, "inserted")) {
+ QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
+
+ monitor_printf(mon, " file=");
+ monitor_print_filename(mon, qdict_get_str(qdict, "file"));
+ if (qdict_haskey(qdict, "backing_file")) {
+ monitor_printf(mon, " backing_file=");
+ monitor_print_filename(mon, qdict_get_str(qdict, "backing_file"));
+ }
+ monitor_printf(mon, " ro=%d drv=%s encrypted=%d",
+ qdict_get_bool(qdict, "ro"),
+ qdict_get_str(qdict, "drv"),
+ qdict_get_bool(qdict, "encrypted"));
+ } else {
+ monitor_printf(mon, " [not inserted]");
+ }
+
+ monitor_printf(mon, "\n");
+}
+
+void bdrv_info_print(Monitor *mon, const QObject *data)
+{
+ qlist_iter(qobject_to_qlist(data), bdrv_print_dict, mon);
+}
+
+/**
+ * bdrv_info(): Block devices information
+ *
+ * Each block device information is stored in a QDict and the
+ * returned QObject is a QList of all devices.
+ *
+ * The QDict contains the following:
+ *
+ * - "device": device name
+ * - "type": device type
+ * - "removable": true if the device is removable, false otherwise
+ * - "locked": true if the device is locked, false otherwise
+ * - "inserted": only present if the device is inserted, it is a QDict
+ * containing the following:
+ * - "file": device file name
+ * - "ro": true if read-only, false otherwise
+ * - "drv": driver format name
+ * - "backing_file": backing file name if one is used
+ * - "encrypted": true if encrypted, false otherwise
+ *
+ * Example:
+ *
+ * [ { "device": "ide0-hd0", "type": "hd", "removable": false, "locked": false,
+ * "inserted": { "file": "/tmp/foobar", "ro": false, "drv": "qcow2" } },
+ * { "device": "floppy0", "type": "floppy", "removable": true,
+ * "locked": false } ]
+ */
+void bdrv_info(Monitor *mon, QObject **ret_data)
+{
+ QList *bs_list;
BlockDriverState *bs;
+ bs_list = qlist_new();
+
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
- monitor_printf(mon, "%s:", bs->device_name);
- monitor_printf(mon, " type=");
+ QObject *bs_obj;
+ const char *type = "unknown";
+
switch(bs->type) {
case BDRV_TYPE_HD:
- monitor_printf(mon, "hd");
+ type = "hd";
break;
case BDRV_TYPE_CDROM:
- monitor_printf(mon, "cdrom");
+ type = "cdrom";
break;
case BDRV_TYPE_FLOPPY:
- monitor_printf(mon, "floppy");
+ type = "floppy";
break;
}
- monitor_printf(mon, " removable=%d", bs->removable);
- if (bs->removable) {
- monitor_printf(mon, " locked=%d", bs->locked);
- }
+
+ bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': %s, "
+ "'removable': %i, 'locked': %i }",
+ bs->device_name, type, bs->removable,
+ bs->locked);
+ assert(bs_obj != NULL);
+
if (bs->drv) {
- monitor_printf(mon, " file=");
- monitor_print_filename(mon, bs->filename);
+ QObject *obj;
+ QDict *bs_dict = qobject_to_qdict(bs_obj);
+
+ obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, "
+ "'encrypted': %i }",
+ bs->filename, bs->read_only,
+ bs->drv->format_name,
+ bdrv_is_encrypted(bs));
+ assert(obj != NULL);
if (bs->backing_file[0] != '\0') {
- monitor_printf(mon, " backing_file=");
- monitor_print_filename(mon, bs->backing_file);
+ QDict *qdict = qobject_to_qdict(obj);
+ qdict_put(qdict, "backing_file",
+ qstring_from_str(bs->backing_file));
}
- monitor_printf(mon, " ro=%d", bs->read_only);
- monitor_printf(mon, " drv=%s", bs->drv->format_name);
- monitor_printf(mon, " encrypted=%d", bdrv_is_encrypted(bs));
- } else {
- monitor_printf(mon, " [not inserted]");
+
+ qdict_put_obj(bs_dict, "inserted", obj);
}
- monitor_printf(mon, "\n");
+ qlist_append_obj(bs_list, bs_obj);
}
+
+ *ret_data = QOBJECT(bs_list);
}
-/* The "info blockstats" command. */
-void bdrv_info_stats(Monitor *mon)
+static void bdrv_stats_iter(QObject *data, void *opaque)
{
+ QDict *qdict;
+ Monitor *mon = opaque;
+
+ qdict = qobject_to_qdict(data);
+ monitor_printf(mon, "%s:", qdict_get_str(qdict, "device"));
+
+ qdict = qobject_to_qdict(qdict_get(qdict, "stats"));
+ monitor_printf(mon, " rd_bytes=%" PRId64
+ " wr_bytes=%" PRId64
+ " rd_operations=%" PRId64
+ " wr_operations=%" 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"));
+}
+
+void bdrv_stats_print(Monitor *mon, const QObject *data)
+{
+ qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon);
+}
+
+/**
+ * bdrv_info_stats(): show block device statistics
+ *
+ * Each device statistic information is stored in a QDict and
+ * the returned QObject is a QList of all devices.
+ *
+ * The QDict contains the following:
+ *
+ * - "device": device name
+ * - "stats": A QDict with the statistics information, it contains:
+ * - "rd_bytes": bytes read
+ * - "wr_bytes": bytes written
+ * - "rd_operations": read operations
+ * - "wr_operations": write operations
+ *
+ * Example:
+ *
+ * [ { "device": "ide0-hd0",
+ * "stats": { "rd_bytes": 512,
+ * "wr_bytes": 0,
+ * "rd_operations": 1,
+ * "wr_operations": 0 } },
+ * { "device": "ide1-cd0",
+ * "stats": { "rd_bytes": 0,
+ * "wr_bytes": 0,
+ * "rd_operations": 0,
+ * "wr_operations": 0 } } ]
+ */
+void bdrv_info_stats(Monitor *mon, QObject **ret_data)
+{
+ QObject *obj;
+ QList *devices;
BlockDriverState *bs;
+ devices = qlist_new();
+
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
- monitor_printf(mon, "%s:"
- " rd_bytes=%" PRIu64
- " wr_bytes=%" PRIu64
- " rd_operations=%" PRIu64
- " wr_operations=%" PRIu64
- "\n",
- bs->device_name,
- bs->rd_bytes, bs->wr_bytes,
- bs->rd_ops, bs->wr_ops);
+ obj = qobject_from_jsonf("{ 'device': %s, 'stats': {"
+ "'rd_bytes': %" PRId64 ","
+ "'wr_bytes': %" PRId64 ","
+ "'rd_operations': %" PRId64 ","
+ "'wr_operations': %" PRId64
+ "} }",
+ bs->device_name,
+ bs->rd_bytes, bs->wr_bytes,
+ bs->rd_ops, bs->wr_ops);
+ assert(obj != NULL);
+ qlist_append_obj(devices, obj);
}
+
+ *ret_data = QOBJECT(devices);
}
const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
return -ENOTSUP;
if (bdrv_check_request(bs, sector_num, nb_sectors))
return -EIO;
+
+ if (bs->dirty_bitmap) {
+ set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+ }
+
return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
}
if (ret) {
/* Update stats even though technically transfer has not happened. */
- bs->rd_bytes += (unsigned) nb_sectors * SECTOR_SIZE;
+ bs->rd_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
bs->rd_ops ++;
}
if (bdrv_check_request(bs, sector_num, nb_sectors))
return NULL;
+ if (bs->dirty_bitmap) {
+ set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+ }
+
ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
cb, opaque);
if (ret) {
/* Update stats even though technically transfer has not happened. */
- bs->wr_bytes += (unsigned) nb_sectors * SECTOR_SIZE;
+ bs->wr_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
bs->wr_ops ++;
}
module_call_init(MODULE_INIT_BLOCK);
}
+void bdrv_init_with_whitelist(void)
+{
+ use_bdrv_whitelist = 1;
+ bdrv_init();
+}
+
void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
return NULL;
}
+
+
void *qemu_blockalign(BlockDriverState *bs, size_t size)
{
return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size);
}
+
+void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable)
+{
+ int64_t bitmap_size;
+
+ if (enable) {
+ if (!bs->dirty_bitmap) {
+ bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
+ BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
+ bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
+
+ bs->dirty_bitmap = qemu_mallocz(bitmap_size);
+ }
+ } else {
+ if (bs->dirty_bitmap) {
+ qemu_free(bs->dirty_bitmap);
+ bs->dirty_bitmap = NULL;
+ }
+ }
+}
+
+int bdrv_get_dirty(BlockDriverState *bs, int64_t sector)
+{
+ int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
+
+ if (bs->dirty_bitmap &&
+ (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) {
+ return bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &
+ (1 << (chunk % (sizeof(unsigned long) * 8)));
+ } else {
+ return 0;
+ }
+}
+
+void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
+ int nr_sectors)
+{
+ set_dirty_bitmap(bs, cur_sector, nr_sectors, 0);
+}