bs->is_temporary = 0;
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;
drv = find_image_format(filename);
}
}
+
if (!drv) {
ret = -ENOENT;
goto unlink_and_fail;
}
+ if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
+ ret = -ENOTSUP;
+ goto unlink_and_fail;
+ }
+
bs->drv = drv;
bs->opaque = qemu_mallocz(drv->instance_size);
if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
bs->enable_write_cache = 1;
- bs->read_only = (flags & BDRV_O_RDWR) == 0;
- if (!(flags & BDRV_O_FILE)) {
- open_flags = (flags & (BDRV_O_RDWR | BDRV_O_CACHE_MASK|BDRV_O_NATIVE_AIO));
- if (bs->is_temporary) { /* snapshot should be writeable */
- open_flags |= BDRV_O_RDWR;
- }
- } else {
- open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
- }
- if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
- ret = -ENOTSUP;
- } else {
- ret = drv->bdrv_open(bs, filename, open_flags);
+ /*
+ * Clear flags that are internal to the block layer before opening the
+ * image.
+ */
+ open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
+
+ /*
+ * Snapshots should be writeable.
+ *
+ * XXX(hch): and what is the point of a snapshot during a read-only open?
+ */
+ if (!(flags & BDRV_O_FILE) && bs->is_temporary) {
+ open_flags |= BDRV_O_RDWR;
}
+
+ ret = drv->bdrv_open(bs, filename, open_flags);
if (ret < 0) {
- qemu_free(bs->opaque);
- bs->opaque = NULL;
- bs->drv = NULL;
- unlink_and_fail:
- if (bs->is_temporary)
- unlink(filename);
- return ret;
+ goto free_and_fail;
}
+
+ bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
if (drv->bdrv_getlength) {
bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
}
filename, bs->backing_file);
if (bs->backing_format[0] != '\0')
back_drv = bdrv_find_format(bs->backing_format);
+
+ /* backing files always opened read-only */
+ open_flags &= ~BDRV_O_RDWR;
+
ret = bdrv_open2(bs->backing_hd, backing_filename, open_flags,
back_drv);
- bs->backing_hd->read_only = (open_flags & BDRV_O_RDWR) == 0;
if (ret < 0) {
bdrv_close(bs);
return ret;
}
+ if (bs->is_temporary) {
+ bs->backing_hd->keep_read_only = !(flags & BDRV_O_RDWR);
+ } else {
+ /* base image inherits from "parent" */
+ bs->backing_hd->keep_read_only = bs->keep_read_only;
+ }
}
if (!bdrv_key_required(bs)) {
bs->change_cb(bs->change_opaque);
}
return 0;
+
+free_and_fail:
+ qemu_free(bs->opaque);
+ bs->opaque = NULL;
+ bs->drv = NULL;
+unlink_and_fail:
+ if (bs->is_temporary)
+ unlink(filename);
+ return ret;
}
void bdrv_close(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
int64_t i, total_sectors;
- int n, j;
- int ret = 0;
+ int n, j, ro, open_flags;
+ int ret = 0, rw_ret = 0;
unsigned char sector[512];
+ char filename[1024];
+ BlockDriverState *bs_rw, *bs_ro;
if (!drv)
return -ENOMEDIUM;
-
- if (bs->read_only) {
- return -EACCES;
+
+ if (!bs->backing_hd) {
+ return -ENOTSUP;
}
- if (!bs->backing_hd) {
- return -ENOTSUP;
+ if (bs->backing_hd->keep_read_only) {
+ return -EACCES;
+ }
+
+ ro = bs->backing_hd->read_only;
+ strncpy(filename, bs->backing_hd->filename, sizeof(filename));
+ open_flags = bs->backing_hd->open_flags;
+
+ if (ro) {
+ /* re-open as RW */
+ bdrv_delete(bs->backing_hd);
+ bs->backing_hd = NULL;
+ bs_rw = bdrv_new("");
+ rw_ret = bdrv_open2(bs_rw, filename, open_flags | BDRV_O_RDWR, NULL);
+ if (rw_ret < 0) {
+ bdrv_delete(bs_rw);
+ /* try to re-open read-only */
+ bs_ro = bdrv_new("");
+ ret = bdrv_open2(bs_ro, filename, open_flags & ~BDRV_O_RDWR, NULL);
+ if (ret < 0) {
+ bdrv_delete(bs_ro);
+ /* drive not functional anymore */
+ bs->drv = NULL;
+ return ret;
+ }
+ bs->backing_hd = bs_ro;
+ return rw_ret;
+ }
+ bs->backing_hd = bs_rw;
}
total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {
for(j = 0; j < n; j++) {
if (bdrv_read(bs, i, sector, 1) != 0) {
- return -EIO;
+ ret = -EIO;
+ goto ro_cleanup;
}
if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
- return -EIO;
+ ret = -EIO;
+ goto ro_cleanup;
}
i++;
}
*/
if (bs->backing_hd)
bdrv_flush(bs->backing_hd);
+
+ro_cleanup:
+
+ if (ro) {
+ /* re-open as RO */
+ bdrv_delete(bs->backing_hd);
+ bs->backing_hd = NULL;
+ bs_ro = bdrv_new("");
+ ret = bdrv_open2(bs_ro, filename, open_flags & ~BDRV_O_RDWR, NULL);
+ if (ret < 0) {
+ bdrv_delete(bs_ro);
+ /* drive not functional anymore */
+ bs->drv = NULL;
+ return ret;
+ }
+ bs->backing_hd = bs_ro;
+ bs->backing_hd->keep_read_only = 0;
+ }
+
return ret;
}
bit = start % (sizeof(unsigned long) * 8);
val = bs->dirty_bitmap[idx];
if (dirty) {
- val |= 1 << bit;
+ if (!(val & (1 << bit))) {
+ bs->dirty_count++;
+ val |= 1 << bit;
+ }
} else {
- val &= ~(1 << bit);
+ if (val & (1 << bit)) {
+ bs->dirty_count--;
+ val &= ~(1 << bit);
+ }
}
bs->dirty_bitmap[idx] = val;
}
return bs->read_only;
}
-int bdrv_set_read_only(BlockDriverState *bs, int read_only)
-{
- int ret = bs->read_only;
- bs->read_only = read_only;
- return ret;
-}
-
int bdrv_is_sg(BlockDriverState *bs)
{
return bs->sg;
if (!bs->encrypted)
return 0;
}
- if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)
- return -1;
+ if (!bs->encrypted) {
+ return -EINVAL;
+ } else if (!bs->drv || !bs->drv->bdrv_set_key) {
+ return -ENOMEDIUM;
+ }
ret = bs->drv->bdrv_set_key(bs, key);
if (ret < 0) {
bs->valid_key = 0;
return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum);
}
+void bdrv_mon_event(const BlockDriverState *bdrv,
+ BlockMonEventAction action, int is_read)
+{
+ QObject *data;
+ const char *action_str;
+
+ switch (action) {
+ case BDRV_ACTION_REPORT:
+ action_str = "report";
+ break;
+ case BDRV_ACTION_IGNORE:
+ action_str = "ignore";
+ break;
+ case BDRV_ACTION_STOP:
+ action_str = "stop";
+ break;
+ default:
+ abort();
+ }
+
+ data = qobject_from_jsonf("{ 'device': %s, 'action': %s, 'operation': %s }",
+ bdrv->device_name,
+ action_str,
+ is_read ? "read" : "write");
+ monitor_protocol_event(QEVENT_BLOCK_IO_ERROR, data);
+
+ qobject_decref(data);
+}
+
static void bdrv_print_dict(QObject *obj, void *opaque)
{
QDict *bs_dict;
"'removable': %i, 'locked': %i }",
bs->device_name, type, bs->removable,
bs->locked);
- assert(bs_obj != NULL);
if (bs->drv) {
QObject *obj;
bs->filename, bs->read_only,
bs->drv->format_name,
bdrv_is_encrypted(bs));
- assert(obj != NULL);
if (bs->backing_file[0] != '\0') {
QDict *qdict = qobject_to_qdict(obj);
qdict_put(qdict, "backing_file",
bs->device_name,
bs->rd_bytes, bs->wr_bytes,
bs->rd_ops, bs->wr_ops);
- assert(obj != NULL);
qlist_append_obj(devices, obj);
}
for (i = 0; i < mcb->num_callbacks; i++) {
mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error);
qemu_free(mcb->callbacks[i].free_qiov);
- qemu_free(mcb->callbacks[i].free_buf);
+ qemu_vfree(mcb->callbacks[i].free_buf);
}
}
merge = bs->drv->bdrv_merge_requests(bs, &reqs[outidx], &reqs[i]);
}
+ if (reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1 > IOV_MAX) {
+ merge = 0;
+ }
+
if (merge) {
size_t size;
QEMUIOVector *qiov = qemu_mallocz(sizeof(*qiov));
{
int64_t bitmap_size;
+ bs->dirty_count = 0;
if (enable) {
if (!bs->dirty_bitmap) {
bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
{
set_dirty_bitmap(bs, cur_sector, nr_sectors, 0);
}
+
+int64_t bdrv_get_dirty_count(BlockDriverState *bs)
+{
+ return bs->dirty_count;
+}