From: Kevin Wolf <kwolf@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com
Subject: [Qemu-devel] [PULL 16/29] block: Add bdrv_refresh_filename()
Date: Fri, 22 Aug 2014 16:51:40 +0200 [thread overview]
Message-ID: <1408719113-5316-17-git-send-email-kwolf@redhat.com> (raw)
In-Reply-To: <1408719113-5316-1-git-send-email-kwolf@redhat.com>
From: Max Reitz <mreitz@redhat.com>
Some block devices may not have a filename in their BDS; and for some,
there may not even be a normal filename at all. To work around this, add
a function which tries to construct a valid filename for the
BDS.filename field.
If a filename exists or a block driver is able to reconstruct a valid
filename (which is placed in BDS.exact_filename), this can directly be
used.
If no filename can be constructed, we can still construct an options
QDict which is then converted to a JSON object and prefixed with the
"json:" pseudo protocol prefix. The QDict is placed in
BDS.full_open_options.
For most block drivers, this process can be done automatically; those
that need special handling may define a .bdrv_refresh_filename() method
to fill BDS.exact_filename and BDS.full_open_options themselves.
Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
block.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++
include/block/block.h | 1 +
include/block/block_int.h | 6 +++
3 files changed, 142 insertions(+)
diff --git a/block.c b/block.c
index 712f5db..e9380f6 100644
--- a/block.c
+++ b/block.c
@@ -964,6 +964,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
} 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);
@@ -1505,6 +1506,8 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
}
}
+ bdrv_refresh_filename(bs);
+
/* For snapshot=on, create a temporary qcow2 overlay. bs points to the
* temporary snapshot afterwards. */
if (snapshot_flags) {
@@ -1845,6 +1848,8 @@ void bdrv_close(BlockDriverState *bs)
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);
@@ -5894,3 +5899,133 @@ void bdrv_flush_io_queue(BlockDriverState *bs)
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);
+ }
+}
diff --git a/include/block/block.h b/include/block/block.h
index e94b701..8f4ad16 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -274,6 +274,7 @@ int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
const char *backing_file);
int bdrv_get_backing_file_depth(BlockDriverState *bs);
+void bdrv_refresh_filename(BlockDriverState *bs);
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
int64_t bdrv_nb_sectors(BlockDriverState *bs);
int64_t bdrv_getlength(BlockDriverState *bs);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 7b541a0..2334895 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -123,6 +123,9 @@ struct BlockDriver {
int (*bdrv_create)(const char *filename, QemuOpts *opts, Error **errp);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
int (*bdrv_make_empty)(BlockDriverState *bs);
+
+ void (*bdrv_refresh_filename)(BlockDriverState *bs);
+
/* aio */
BlockDriverAIOCB *(*bdrv_aio_readv)(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
@@ -323,6 +326,9 @@ struct BlockDriverState {
this file image */
char backing_format[16]; /* if non-zero and backing_file exists */
+ QDict *full_open_options;
+ char exact_filename[1024];
+
BlockDriverState *backing_hd;
BlockDriverState *file;
--
1.8.3.1
next prev parent reply other threads:[~2014-08-22 14:52 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-22 14:51 [Qemu-devel] [PULL 00/29] Block patches Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 01/29] block: Use g_new() & friends where that makes obvious sense Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 02/29] block: Use g_new() & friends to avoid multiplying sizes Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 03/29] qemu-io-cmds: g_renew() can't fail, bury dead error handling Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 04/29] block: Drop some superfluous casts from void * Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 05/29] runner: Add an argument for test duration Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 06/29] runner: Kill a program under test by time-out Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 07/29] qcow2: Constant cache size in bytes Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 08/29] qcow2: Use g_try_new0() for cache array Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 09/29] qcow2: Add runtime options for cache sizes Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 10/29] iotests: Add test for qcow2's cache options Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 11/29] test-coroutine: test cost introduced by coroutine Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 12/29] qemu-iotests: Fix 028 reference output for qed Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 13/29] block: acquire AioContext in qmp_block_resize() Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 14/29] virtio-blk: allow block_resize with dataplane Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 15/29] virtio-blk: fix reference a pointer which might be freed Kevin Wolf
2014-08-22 14:51 ` Kevin Wolf [this message]
2014-08-22 14:51 ` [Qemu-devel] [PULL 17/29] blkdebug: Implement bdrv_refresh_filename() Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 18/29] blkverify: " Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 19/29] nbd: " Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 20/29] quorum: " Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 21/29] iotests: Add test for image filename construction Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 22/29] block/vvfat.c: remove debugging code to reinit stderr if NULL Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 23/29] block/iscsi: fix memory corruption on iscsi resize Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 24/29] raw-posix: fix O_DIRECT short reads Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 25/29] qemu-iotests: add test case 101 for short file I/O Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 26/29] blkdebug: Delete BH in bdrv_aio_cancel Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 27/29] vmdk: Use bdrv_nb_sectors() where sectors, not bytes are wanted Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 28/29] qemu-img: Allow source cache mode specification Kevin Wolf
2014-08-22 14:51 ` [Qemu-devel] [PULL 29/29] qemu-img: Allow cache mode specification for amend Kevin Wolf
2014-08-22 15:09 ` [Qemu-devel] [PULL 00/29] Block patches Daniel H Barboza
2014-08-22 16:23 ` Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1408719113-5316-17-git-send-email-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).