pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
bs_src->device_name);
bs_dest->device_list = bs_src->device_list;
+ bs_dest->blk = bs_src->blk;
+
memcpy(bs_dest->op_blockers, bs_src->op_blockers,
sizeof(bs_dest->op_blockers));
}
* This will modify the BlockDriverState fields, and swap contents
* between bs_new and bs_old. Both bs_new and bs_old are modified.
*
- * bs_new is required to be anonymous.
+ * bs_new must be nameless and not attached to a BlockBackend.
*
* This function does not create any image files.
*/
QTAILQ_REMOVE(&graph_bdrv_states, bs_old, node_list);
}
- /* bs_new must be anonymous and shouldn't have anything fancy enabled */
+ /* bs_new must be nameless and shouldn't have anything fancy enabled */
assert(bs_new->device_name[0] == '\0');
+ assert(!bs_new->blk);
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
assert(bs_new->job == NULL);
assert(bs_new->dev == NULL);
bdrv_move_feature_fields(bs_old, bs_new);
bdrv_move_feature_fields(bs_new, &tmp);
- /* bs_new shouldn't be in bdrv_states even after the swap! */
+ /* bs_new must remain nameless and unattached */
assert(bs_new->device_name[0] == '\0');
+ assert(!bs_new->blk);
/* Check a few fields that should remain attached to the device */
assert(bs_new->dev == NULL);
* This will modify the BlockDriverState fields, and swap contents
* between bs_new and bs_top. Both bs_new and bs_top are modified.
*
- * bs_new is required to be anonymous.
+ * bs_new must be nameless and not attached to a BlockBackend.
*
* This function does not create any image files.
*/
struct BlockBackend {
char *name;
int refcnt;
+ BlockDriverState *bs;
QTAILQ_ENTRY(BlockBackend) link; /* for blk_backends */
};
-/* All the BlockBackends */
+/* All the BlockBackends (except for hidden ones) */
static QTAILQ_HEAD(, BlockBackend) blk_backends =
QTAILQ_HEAD_INITIALIZER(blk_backends);
return blk;
}
+/*
+ * Create a new BlockBackend with a new BlockDriverState attached.
+ * Both have a reference count of one. Caller owns *both* references.
+ * TODO Let caller own only the BlockBackend reference
+ * Otherwise just like blk_new(), which see.
+ */
+BlockBackend *blk_new_with_bs(const char *name, Error **errp)
+{
+ BlockBackend *blk;
+ BlockDriverState *bs;
+
+ blk = blk_new(name, errp);
+ if (!blk) {
+ return NULL;
+ }
+
+ bs = bdrv_new_root(name, errp);
+ if (!bs) {
+ blk_unref(blk);
+ return NULL;
+ }
+
+ blk->bs = bs;
+ bs->blk = blk;
+ return blk;
+}
+
static void blk_delete(BlockBackend *blk)
{
assert(!blk->refcnt);
- QTAILQ_REMOVE(&blk_backends, blk, link);
+ if (blk->bs) {
+ blk->bs->blk = NULL;
+ blk->bs = NULL;
+ }
+ /* Avoid double-remove after blk_hide_on_behalf_of_do_drive_del() */
+ if (blk->name[0]) {
+ QTAILQ_REMOVE(&blk_backends, blk, link);
+ }
g_free(blk->name);
g_free(blk);
}
* Decrement @blk's reference count.
* If this drops it to zero, destroy @blk.
* For convenience, do nothing if @blk is null.
+ * Does *not* touch the attached BlockDriverState's reference count.
+ * TODO Decrement it!
*/
void blk_unref(BlockBackend *blk)
{
}
/*
- * Return @blk's name, a non-null, non-empty string.
+ * Return @blk's name, a non-null string.
+ * Wart: the name is empty iff @blk has been hidden with
+ * blk_hide_on_behalf_of_do_drive_del().
*/
const char *blk_name(BlockBackend *blk)
{
}
return NULL;
}
+
+/*
+ * Return the BlockDriverState attached to @blk if any, else null.
+ */
+BlockDriverState *blk_bs(BlockBackend *blk)
+{
+ return blk->bs;
+}
+
+/*
+ * Hide @blk.
+ * @blk must not have been hidden already.
+ * Make attached BlockDriverState, if any, anonymous.
+ * Once hidden, @blk is invisible to all functions that don't receive
+ * it as argument. For example, blk_by_name() won't return it.
+ * Strictly for use by do_drive_del().
+ * TODO get rid of it!
+ */
+void blk_hide_on_behalf_of_do_drive_del(BlockBackend *blk)
+{
+ QTAILQ_REMOVE(&blk_backends, blk, link);
+ blk->name[0] = 0;
+ if (blk->bs) {
+ bdrv_make_anon(blk->bs);
+ }
+}
return 0;
}
-static BlockDriverState *bdrv_new_open(const char *id,
- const char *filename,
- const char *fmt,
- int flags,
- bool require_io,
- bool quiet)
+static BlockBackend *img_open(const char *id, const char *filename,
+ const char *fmt, int flags,
+ bool require_io, bool quiet)
{
+ BlockBackend *blk;
BlockDriverState *bs;
BlockDriver *drv;
char password[256];
Error *local_err = NULL;
int ret;
- bs = bdrv_new_root(id, &error_abort);
+ blk = blk_new_with_bs(id, &error_abort);
+ bs = blk_bs(blk);
if (fmt) {
drv = bdrv_find_format(fmt);
goto fail;
}
}
- return bs;
+ return blk;
fail:
bdrv_unref(bs);
+ blk_unref(blk);
return NULL;
}
BlockDriverState *bs;
int fix = 0;
int flags = BDRV_O_FLAGS | BDRV_O_CHECK;
- ImageCheck *check = NULL;
+ ImageCheck *check;
bool quiet = false;
fmt = NULL;
return 1;
}
- blk = blk_new("image", &error_abort);
- bs = bdrv_new_open("image", filename, fmt, flags, true, quiet);
- if (!bs) {
- ret = 1;
- goto fail;
+ blk = img_open("image", filename, fmt, flags, true, quiet);
+ if (!blk) {
+ return 1;
}
+ bs = blk_bs(blk);
check = g_new0(ImageCheck, 1);
ret = collect_image_check(bs, check, filename, fmt, fix);
return 1;
}
- blk = blk_new("image", &error_abort);
- bs = bdrv_new_open("image", filename, fmt, flags, true, quiet);
- if (!bs) {
- ret = -1;
- goto out;
+ blk = img_open("image", filename, fmt, flags, true, quiet);
+ if (!blk) {
+ return 1;
}
+ bs = blk_bs(blk);
+
ret = bdrv_commit(bs);
switch(ret) {
case 0:
break;
}
-out:
bdrv_unref(bs);
blk_unref(blk);
if (ret) {
goto out3;
}
- blk1 = blk_new("image_1", &error_abort);
- bs1 = bdrv_new_open("image_1", filename1, fmt1, flags, true, quiet);
- if (!bs1) {
+ blk1 = img_open("image_1", filename1, fmt1, flags, true, quiet);
+ if (!blk1) {
error_report("Can't open file %s", filename1);
ret = 2;
- goto out2;
+ goto out3;
}
+ bs1 = blk_bs(blk1);
- blk2 = blk_new("image_2", &error_abort);
- bs2 = bdrv_new_open("image_2", filename2, fmt2, flags, true, quiet);
- if (!bs2) {
+ blk2 = img_open("image_2", filename2, fmt2, flags, true, quiet);
+ if (!blk2) {
error_report("Can't open file %s", filename2);
ret = 2;
- goto out1;
+ goto out2;
}
+ bs2 = blk_bs(blk2);
buf1 = qemu_blockalign(bs1, IO_BUF_SIZE);
buf2 = qemu_blockalign(bs2, IO_BUF_SIZE);
out:
qemu_vfree(buf1);
qemu_vfree(buf2);
-out1:
bdrv_unref(bs2);
blk_unref(blk2);
out2:
for (bs_i = 0; bs_i < bs_n; bs_i++) {
char *id = bs_n > 1 ? g_strdup_printf("source_%d", bs_i)
: g_strdup("source");
- blk[bs_i] = blk_new(id, &error_abort);
- bs[bs_i] = bdrv_new_open(id, argv[optind + bs_i], fmt, src_flags,
- true, quiet);
+ blk[bs_i] = img_open(id, argv[optind + bs_i], fmt, src_flags,
+ true, quiet);
g_free(id);
- if (!bs[bs_i]) {
+ if (!blk[bs_i]) {
error_report("Could not open '%s'", argv[optind + bs_i]);
ret = -1;
goto out;
}
+ bs[bs_i] = blk_bs(blk[bs_i]);
bs_sectors[bs_i] = bdrv_nb_sectors(bs[bs_i]);
if (bs_sectors[bs_i] < 0) {
error_report("Could not get size of %s: %s",
goto out;
}
- out_blk = blk_new("target", &error_abort);
- out_bs = bdrv_new_open("target", out_filename, out_fmt, flags, true, quiet);
- if (!out_bs) {
+ out_blk = img_open("target", out_filename, out_fmt, flags, true, quiet);
+ if (!out_blk) {
ret = -1;
goto out;
}
+ out_bs = blk_bs(out_blk);
bs_i = 0;
bs_offset = 0;
}
g_hash_table_insert(filenames, (gpointer)filename, NULL);
- blk = blk_new("image", &error_abort);
- bs = bdrv_new_open("image", filename, fmt,
- BDRV_O_FLAGS | BDRV_O_NO_BACKING, false, false);
- if (!bs) {
- blk_unref(blk);
+ blk = img_open("image", filename, fmt,
+ BDRV_O_FLAGS | BDRV_O_NO_BACKING, false, false);
+ if (!blk) {
goto err;
}
+ bs = blk_bs(blk);
bdrv_query_image_info(bs, &info, &err);
if (err) {
return 1;
}
- blk = blk_new("image", &error_abort);
- bs = bdrv_new_open("image", filename, fmt, BDRV_O_FLAGS, true, false);
- if (!bs) {
- ret = -1;
- goto out;
+ blk = img_open("image", filename, fmt, BDRV_O_FLAGS, true, false);
+ if (!blk) {
+ return 1;
}
+ bs = blk_bs(blk);
if (output_format == OFORMAT_HUMAN) {
printf("%-16s%-16s%-16s%s\n", "Offset", "Length", "Mapped to", "File");
filename = argv[optind++];
/* Open the image */
- blk = blk_new("image", &error_abort);
- bs = bdrv_new_open("image", filename, NULL, bdrv_oflags, true, quiet);
- if (!bs) {
- ret = -1;
- goto out;
+ blk = img_open("image", filename, NULL, bdrv_oflags, true, quiet);
+ if (!blk) {
+ return 1;
}
+ bs = blk_bs(blk);
/* Perform the requested action */
switch(action) {
}
/* Cleanup */
-out:
bdrv_unref(bs);
blk_unref(blk);
if (ret) {
* Ignore the old backing file for unsafe rebase in case we want to correct
* the reference to a renamed or moved backing file.
*/
- blk = blk_new("image", &error_abort);
- bs = bdrv_new_open("image", filename, fmt, flags, true, quiet);
- if (!bs) {
+ blk = img_open("image", filename, fmt, flags, true, quiet);
+ if (!blk) {
ret = -1;
goto out;
}
+ bs = blk_bs(blk);
/* Find the right drivers for the backing files */
old_backing_drv = NULL;
if (!unsafe) {
char backing_name[1024];
- blk_old_backing = blk_new("old_backing", &error_abort);
- bs_old_backing = bdrv_new_root("old_backing", &error_abort);
+ blk_old_backing = blk_new_with_bs("old_backing", &error_abort);
+ bs_old_backing = blk_bs(blk_old_backing);
bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
ret = bdrv_open(&bs_old_backing, backing_name, NULL, NULL, src_flags,
old_backing_drv, &local_err);
goto out;
}
if (out_baseimg[0]) {
- blk_new_backing = blk_new("new_backing", &error_abort);
- bs_new_backing = bdrv_new_root("new_backing", &error_abort);
+ blk_new_backing = blk_new_with_bs("new_backing", &error_abort);
+ bs_new_backing = blk_bs(blk_new_backing);
ret = bdrv_open(&bs_new_backing, out_baseimg, NULL, NULL, src_flags,
new_backing_drv, &local_err);
if (ret) {
n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0);
qemu_opts_del(param);
- blk = blk_new("image", &error_abort);
- bs = bdrv_new_open("image", filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR,
- true, quiet);
- if (!bs) {
+ blk = img_open("image", filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR,
+ true, quiet);
+ if (!blk) {
ret = -1;
goto out;
}
+ bs = blk_bs(blk);
if (relative) {
total_size = bdrv_getlength(bs) + n * relative;
goto out;
}
- blk = blk_new("image", &error_abort);
- bs = bdrv_new_open("image", filename, fmt, flags, true, quiet);
- if (!bs) {
+ blk = img_open("image", filename, fmt, flags, true, quiet);
+ if (!blk) {
error_report("Could not open image '%s'", filename);
ret = -1;
goto out;
}
+ bs = blk_bs(blk);
fmt = bs->drv->format_name;