From: Jeff Cody <jcody@redhat.com>
To: Xu Wang <gesaint@linux.vnet.ibm.com>
Cc: kwolf@redhat.com, stefanha@gmail.com, famz@redhat.com,
qemu-devel@nongnu.org, wdongxu@linux.vnet.ibm.com
Subject: Re: [Qemu-devel] [PATCH V9 1/4] block/qemu-img: Refine and export infinite loop checking in collect_image_info_list()
Date: Thu, 19 Dec 2013 11:18:29 -0500 [thread overview]
Message-ID: <20131219161829.GD4699@localhost.localdomain> (raw)
In-Reply-To: <1385447913-19004-2-git-send-email-gesaint@linux.vnet.ibm.com>
On Tue, Nov 26, 2013 at 01:38:30AM -0500, Xu Wang wrote:
> If there is a loop in the backing file chain, it could cause problems
> such as no response or a segfault during system boot. Hence detecting a
> backing file loop is necessary. This patch extracts the loop check from
> collect_image_info_list() in block.c into independent functions
> bdrv_backing_chain_okay() and bdrv_image_create_okay().
>
> Signed-off-by: Xu Wang <gesaint@linux.vnet.ibm.com>
> ---
> block.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++
> include/block/block.h | 3 +++
> qemu-img.c | 52 ++++++++++++++++++------------------
> 3 files changed, 102 insertions(+), 26 deletions(-)
>
> diff --git a/block.c b/block.c
> index 382ea71..7016ce8 100644
> --- a/block.c
> +++ b/block.c
> @@ -4497,6 +4497,79 @@ bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie)
> bs->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
> }
>
> +static bool file_chain_has_loop(GHashTable *filenames, const char *filename,
> + BlockDriver *drv, Error **errp)
> +{
> + BlockDriverState *bs;
> + char fbuf[PATH_MAX];
> + Error *local_err = NULL;
> + int ret;
> +
> + while (filename && (filename[0] != '\0')) {
> + if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) {
> + error_setg(errp, "Backing file '%s' creates an infinite loop.",
> + filename);
> + return true;
> + }
> + g_hash_table_insert(filenames, (gpointer)filename, NULL);
> +
> + bs = bdrv_new("image");
> + ret = bdrv_open(bs, filename, NULL,
> + BDRV_O_CACHE_WB | BDRV_O_NO_BACKING, drv, &local_err);
> + if (ret < 0) {
> + error_setg(errp, "Could not open '%s': %s", filename,
> + error_get_pretty(local_err));
This also leaks local_err here - you should call error_free(local_err).
> + return true;
> + }
> +
> + bdrv_get_backing_filename(bs, fbuf, sizeof(fbuf));
> + filename = fbuf;
> + drv = NULL;
> +
> + bdrv_unref(bs);
> + }
> +
> + return false;
> +}
> +
> +/**
> + * Check backing file chain if there is a loop in it.
> + *
> + * @filename: topmost image filename of backing file chain.
> + * @drv: topmost image driver(may be NULL to autodetect).
> + * @new_filename: if a new image to be created and takes @filename as backing
> + * file, the new chain should be checked before creating.
> + *
> + * Returns: true for backing chain okay, false for loop happened.
> + */
> +bool bdrv_backing_chain_okay(const char *filename, BlockDriver *drv,
> + const char *new_filename, Error **errp)
> +{
> + GHashTable *filenames;
> +
> + filenames = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
> +
> + if (filename == NULL || filename[0] == '\0') {
> + goto exit;
> + }
> +
> + if (new_filename && new_filename[0] != '\0') {
> + g_hash_table_insert(filenames, (gpointer)new_filename, NULL);
> + }
> +
> + if (file_chain_has_loop(filenames, filename, drv, errp)) {
> + goto err;
> + }
> +
> +exit:
> + g_hash_table_destroy(filenames);
> + return true;
> +
> +err:
> + g_hash_table_destroy(filenames);
> + return false;
> +}
> +
> void 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,
> diff --git a/include/block/block.h b/include/block/block.h
> index 3560deb..f5e84dc 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -378,6 +378,9 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
> int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
> int64_t pos, int size);
>
> +bool bdrv_backing_chain_okay(const char *filename, BlockDriver *drv,
> + const char *new_filename, Error **errp);
> +
> void 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,
> diff --git a/qemu-img.c b/qemu-img.c
> index b6b5644..1f38267 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -281,6 +281,14 @@ static BlockDriverState *bdrv_new_open(const char *filename,
> drv = NULL;
> }
>
> + /* check backing file loop if the whole chain need to be opened */
> + if (!(flags & BDRV_O_NO_BACKING) &&
> + !bdrv_backing_chain_okay(filename, drv, NULL, &local_err)) {
> + error_report("bdrv_new_open: Open %s failed: %s", filename,
> + error_get_pretty(local_err));
> + goto fail;
> + }
> +
> ret = bdrv_open(bs, filename, NULL, flags, drv, &local_err);
> if (ret < 0) {
> error_report("Could not open '%s': %s", filename,
> @@ -1641,11 +1649,6 @@ static void dump_human_image_info_list(ImageInfoList *list)
> }
> }
>
> -static gboolean str_equal_func(gconstpointer a, gconstpointer b)
> -{
> - return strcmp(a, b) == 0;
> -}
> -
> /**
> * Open an image file chain and return an ImageInfoList
> *
> @@ -1663,30 +1666,24 @@ static ImageInfoList *collect_image_info_list(const char *filename,
> bool chain)
> {
> ImageInfoList *head = NULL;
> + BlockDriverState *bs;
> + ImageInfoList *elem;
> ImageInfoList **last = &head;
> - GHashTable *filenames;
> + ImageInfo *info;
> Error *err = NULL;
> + int flags = BDRV_O_FLAGS;
>
> - filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL);
> -
> - while (filename) {
> - BlockDriverState *bs;
> - ImageInfo *info;
> - ImageInfoList *elem;
> -
> - if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) {
> - error_report("Backing file '%s' creates an infinite loop.",
> - filename);
> - goto err;
> - }
> - g_hash_table_insert(filenames, (gpointer)filename, NULL);
> + if (!chain) {
> + flags |= BDRV_O_NO_BACKING;
> + }
>
> - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING,
> - false, false);
> - if (!bs) {
> - goto err;
> - }
> + bs = bdrv_new_open(filename, fmt, flags,
> + false, false);
> + if (!bs) {
> + goto err;
> + }
>
> + while (filename) {
> bdrv_query_image_info(bs, &info, &err);
> if (error_is_set(&err)) {
> error_report("%s", error_get_pretty(err));
> @@ -1711,14 +1708,17 @@ static ImageInfoList *collect_image_info_list(const char *filename,
> if (info->has_backing_filename_format) {
> fmt = info->backing_filename_format;
> }
> +
> + if (filename) {
> + bs = bdrv_find_backing_image(bs, filename);
> + }
> }
> }
> - g_hash_table_destroy(filenames);
> +
> return head;
>
> err:
> qapi_free_ImageInfoList(head);
> - g_hash_table_destroy(filenames);
> return NULL;
> }
>
> --
> 1.8.1.4
>
>
next prev parent reply other threads:[~2013-12-19 20:37 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-11-26 6:38 [Qemu-devel] [PATCH V9 0/4] Refine and export backing file loop check Xu Wang
2013-11-26 6:38 ` [Qemu-devel] [PATCH V9 1/4] block/qemu-img: Refine and export infinite loop checking in collect_image_info_list() Xu Wang
2013-12-19 15:23 ` Jeff Cody
2013-12-19 16:18 ` Jeff Cody [this message]
2013-11-26 6:38 ` [Qemu-devel] [PATCH V9 2/4] block: Add check infinite loop in bdrv_img_create() Xu Wang
2013-12-19 16:27 ` Jeff Cody
2013-11-26 6:38 ` [Qemu-devel] [PATCH V9 3/4] block: Add backing file loop check in change_backing_file() Xu Wang
2013-12-19 16:13 ` Jeff Cody
2013-11-26 6:38 ` [Qemu-devel] [PATCH V9 4/4] blockdev: Add infinite loop check in drive_init() Xu Wang
2013-12-19 17:25 ` Jeff Cody
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=20131219161829.GD4699@localhost.localdomain \
--to=jcody@redhat.com \
--cc=famz@redhat.com \
--cc=gesaint@linux.vnet.ibm.com \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@gmail.com \
--cc=wdongxu@linux.vnet.ibm.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.