qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH V6 1/5] block/qemu-img: Refine and export infini


From: Fam Zheng
Subject: Re: [Qemu-devel] [PATCH V6 1/5] block/qemu-img: Refine and export infinite loop checking in collect_image_info_list()
Date: Fri, 8 Nov 2013 18:19:40 +0800
User-agent: Mutt/1.5.21 (2010-09-15)

On Tue, 11/05 22:09, 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 <address@hidden>
> ---
>  block.c               | 117 
> ++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/block/block.h |   4 ++
>  qemu-img.c            |  44 ++++++++-----------
>  3 files changed, 139 insertions(+), 26 deletions(-)
> 
> diff --git a/block.c b/block.c
> index 58efb5b..3443117 100644
> --- a/block.c
> +++ b/block.c
> @@ -4490,6 +4490,123 @@ bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie 
> *cookie)
>      bs->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
>  }
>  
> +static gboolean str_equal_func(gconstpointer a, gconstpointer b)
> +{
> +    return strcmp(a, b) == 0;
> +}

Just use g_str_equal here.

> +
> +static bool file_chain_loop_check(GHashTable *filenames, const char 
> *filename,
> +                                  const char *fmt) {

Open brace '{' should be in a new line for functions.

Still confusing function name and return type. Suggest file_chain_has_loop().

> +    BlockDriverState *bs;
> +    BlockDriver *drv;
> +    char fbuf[1024];

Could use PATH_MAX.

> +    int ret;
> +    Error *local_err = NULL;
> +
> +    while (filename && (filename[0] != '\0')) {
> +        if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) {
> +            error_report("Backing file '%s' creates an infinite loop.",
> +                         filename);
> +            return true;
> +        }
> +        g_hash_table_insert(filenames, (gpointer)filename, NULL);
> +
> +        bs = bdrv_new("image");
> +
> +        if (fmt) {
> +            drv = bdrv_find_format(fmt);
> +            if (!drv) {
> +                error_report("Unknown file format '%s'", fmt);
> +                bdrv_delete(bs);
> +                return true;
> +            }
> +        } else {
> +            drv = NULL;
> +        }

No need to call bdrv_find_format for multiple times. Also it doesn't look good
to write format checking here, just let the caller pass in drv.

> +
> +        ret = bdrv_open(bs, filename, NULL,
> +                        BDRV_O_CACHE_WB | BDRV_O_NO_BACKING, drv, 
> &local_err);
> +        if (ret < 0) {
> +            error_report("Could not open '%s': %s", filename,
> +                         error_get_pretty(local_err));
> +            error_free(local_err);
> +            local_err = NULL;
> +            return true;
> +        }
> +
> +        bdrv_get_backing_filename(bs, fbuf, sizeof(fbuf));
> +        filename = fbuf;
> +        fmt = 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.
> + * @fmt: topmost image format of backing file chain(may be NULL to 
> autodetect).
> + *
> + * Returns: true for backing file loop or error happened, false for no loop.

Really?

> + */
> +bool bdrv_backing_chain_okay(const char *filename, const char *fmt) {
> +    GHashTable *filenames;
> +
> +    if (filename == NULL || filename[0] == '\0') {
> +        return true;

Please don't mix "goto err" and multiple "return true". Could be

           goto exit;

...

> +    }
> +
> +    filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, 
> NULL);
> +
> +    if (file_chain_loop_check(filenames, filename, fmt)) {
> +        goto err;
> +    }
> +
> +    g_hash_table_destroy(filenames);
  exit:

> +    return true;
> +
> +err:
> +    g_hash_table_destroy(filenames);
> +    return false;
> +}
> +
> +/**
> + * Check if there is loop exists in the backing file chain and if there will
> + * be loop occur after backing file chain updated or new image created.
> + *
> + * @filename: the image filename to be created.
> + * @backing_file: topmost image filename of backing file chain.
> + * @backing_fmt: topmost image format (may be NULL to autodetect).
> + *
> + * Returns: true for backing file loop or error happened, false for no loop.

I don't think so.

> + */
> +bool bdrv_new_chain_okay(const char *filename, const char *backing_file,
> +                          const char *backing_fmt) {

Please align arguments:     ^

This function could be merged to bdrv_backing_chain_ok by adding an optional
argument const char *new_filename. If it's not NULL you add it to the hash
table, like:

    bool bdrv_backing_chain_okay(const char *filename, const char *fmt,
                                 const char *new_filename)
    {
        GHashTable *filenames;

        if (filename == NULL || filename[0] == '\0') {
            goto exit;
        }

        filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, 
NULL);

        if (new_filename && new_filename[0] != '\0') {
            g_hash_table_insert(filenames, (gpointer)filename, NULL);
        }

        if (file_chain_loop_check(filenames, filename, fmt)) {
            goto err;
        }

        g_hash_table_destroy(filenames);
    exit:
        return true;

    err:
        g_hash_table_destroy(filenames);
        return false;
    }


> +    GHashTable *filenames;
> +
> +    if (backing_file == NULL || backing_file[0] == '\0') {
> +        return true;
> +    }
> +
> +    filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, 
> NULL);
> +
> +    g_hash_table_insert(filenames, (gpointer)filename, NULL);
> +
> +    if (file_chain_loop_check(filenames, backing_file, backing_fmt)) {
> +        goto err;
> +    }
> +
> +    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..0945c09 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -378,6 +378,10 @@ 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, const char *fmt);
> +bool bdrv_new_chain_okay(const char *filename, const char *backing_file,
> +                            const char *backing_fmt);

Please align arguments:     ^

> +
>  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 bf3fb4f..d5ec45b 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -1641,11 +1641,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 +1658,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 +1700,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;
>  }

Is backing chain loop still checked in collect_image_info_list()?

Fam



reply via email to

[Prev in Thread] Current Thread [Next in Thread]