From patchwork Mon Jul 15 09:42:30 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xu Wang X-Patchwork-Id: 258970 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id D2EBD2C00BE for ; Mon, 15 Jul 2013 19:43:31 +1000 (EST) Received: from localhost ([::1]:33170 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UyfJZ-0007yM-JV for incoming@patchwork.ozlabs.org; Mon, 15 Jul 2013 05:43:29 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44714) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UyfJB-0007tS-0k for qemu-devel@nongnu.org; Mon, 15 Jul 2013 05:43:08 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UyfJ7-0002W4-Ek for qemu-devel@nongnu.org; Mon, 15 Jul 2013 05:43:04 -0400 Received: from mail-pb0-x233.google.com ([2607:f8b0:400e:c01::233]:52789) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UyfJ7-0002U7-5Y for qemu-devel@nongnu.org; Mon, 15 Jul 2013 05:43:01 -0400 Received: by mail-pb0-f51.google.com with SMTP id um15so11103963pbc.24 for ; Mon, 15 Jul 2013 02:43:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=Eljs4VtLrX3Y+PhFQVLlXTj/jVcYWOCGXG0p2u8OQMw=; b=QGkO9hDlNvCneq17x4VOzSLHqZLtiF7jonp31cW8U0+m1LZ71rYTnPfbFwRyLZqi6K rm5oNWFn1H0y9HW8jQWqclIz0tdtHdOpXF3LCv1bcfnjKUYESwekWLqwgrdD9seSGT/9 1IkiNUNtlRycoYps8wOQ6JjgqVAOgSCM1iJmaqPLpyPEkPo9f046cPncjeWzpWJcki/h K5QRO/6bVG+F1qnlciBpwD/fDjHlGKoELKrjDg50UTvsFVPSL6Fen5qq6rKyjXdBXWHk yakFQyWN1IeHgrMalZ5uO0/NqMagQnGzCc1XdM0YQuFJBM3ICj9hJqIVPTvTyPCXeI7o QY7g== X-Received: by 10.66.121.195 with SMTP id lm3mr54908444pab.116.1373881380373; Mon, 15 Jul 2013 02:43:00 -0700 (PDT) Received: from localhost.localdomain ([202.108.130.194]) by mx.google.com with ESMTPSA id py4sm16734218pbc.14.2013.07.15.02.42.57 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Mon, 15 Jul 2013 02:43:00 -0700 (PDT) From: Xu Wang To: qemu-devel@nongnu.org Date: Mon, 15 Jul 2013 05:42:30 -0400 Message-Id: <1373881356-3294-2-git-send-email-cngesaint@gmail.com> X-Mailer: git-send-email 1.8.1.4 In-Reply-To: <1373881356-3294-1-git-send-email-cngesaint@gmail.com> References: <1373881356-3294-1-git-send-email-cngesaint@gmail.com> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:400e:c01::233 Cc: kwolf@redhat.com, famz@redhat.com, stefanha@gmail.com, wdongxu@linux.vnet.ibm.com, Xu Wang , xiawenc@linux.vnet.ibm.com Subject: [Qemu-devel] [PATCH V3 1/7] block/qemu-img: Refine and export infinite loop checking in collect_image_info_list() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org If there is a loop exists in the backing file chain, many problems could be caused by it, such as no response and segment fault during system boot. Hence stopping backing file loop appear is very necessary. This patch refine and export loop checking function from collect_image_ info_list() to block.c and build a independent function named bdrv_ backing_file_loop_check(). Signed-off-by: Xu Wang --- block.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/block/block.h | 4 +++ qemu-img.c | 29 +++++---------- 3 files changed, 110 insertions(+), 20 deletions(-) diff --git a/block.c b/block.c index 183fec8..c1d060d 100644 --- a/block.c +++ b/block.c @@ -4433,6 +4433,103 @@ 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; +} + +/** + * Check backing file chain if there is a loop in it and build list of + * ImageInfo if needed. + * + * @filename: topmost image filename, absolute or relative path is OK. + * @fmt: topmost image format (may be NULL to autodetect) + * @backing_file: if this value is set, @filename inode (-1 if it doesn't + * exist) will insert into hash table directly. Loop check + * starts from it. Absolute or relative path is OK for it. + * @backing_format: format of backing file + * + * Returns: true for backing file loop or error happened, false for no loop. + */ +bool bdrv_backing_file_loop_check(const char *filename, const char *fmt, + const char *backing_file, + const char *backing_format) { + GHashTable *inodes; + BlockDriverState *bs; + BlockDriver *drv; + struct stat sbuf; + long inode = 0; + int ret; + char fbuf[1024]; + + inodes = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL); + + if (backing_file) { + /* Check if file exists. */ + if (access(filename, F_OK)) { + inode = -1; + } else { + if (stat(filename, &sbuf) == -1) { + error_report("Get file %s stat failed.", filename); + goto err; + } + inode = (long)sbuf.st_ino; + } + + filename = backing_file; + fmt = backing_format; + g_hash_table_insert(inodes, (gpointer)&inode, NULL); + } + + while (filename && (filename[0] != '\0')) { + if (stat(filename, &sbuf) == -1) { + error_report("Get file %s stat failed.", filename); + goto err; + } + inode = (long)sbuf.st_ino; + + if (g_hash_table_lookup_extended(inodes, &inode, NULL, NULL)) { + error_report("Backing file '%s' creates an infinite loop.", + filename); + goto err; + } + g_hash_table_insert(inodes, (gpointer)&inode, NULL); + + bs = bdrv_new("image"); + + if (fmt) { + drv = bdrv_find_format(fmt); + if (!drv) { + error_report("Unknown file format '%s'", fmt); + bdrv_delete(bs); + goto err; + } + } else { + drv = NULL; + } + + ret = bdrv_open(bs, filename, NULL, + BDRV_O_CACHE_WB | BDRV_O_NO_BACKING, drv); + if (ret < 0) { + error_report("Could not open '%s': %s", filename, strerror(-ret)); + bdrv_delete(bs); + goto err; + } + + bdrv_get_backing_filename(bs, fbuf, sizeof(fbuf)); + filename = fbuf; + fmt = NULL; + + bdrv_delete(bs); + } + g_hash_table_destroy(inodes); + return false; + +err: + g_hash_table_destroy(inodes); + return true; +} + 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 dd8eca1..3dc29bb 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -333,6 +333,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_file_loop_check(const char *filename, const char *fmt, + const char *backing_file, + const char *backing_format); + 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 f8c97d3..19cac5e 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1620,11 +1620,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 * @@ -1642,24 +1637,19 @@ 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; - filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL); + /* check if loop exists and build ImageInfoList */ + if (chain && + bdrv_backing_file_loop_check(filename, fmt, NULL, NULL)) { + goto err; + } 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); - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING, false, false); if (!bs) { @@ -1692,12 +1682,11 @@ static ImageInfoList *collect_image_info_list(const char *filename, } } } - g_hash_table_destroy(filenames); + return head; err: qapi_free_ImageInfoList(head); - g_hash_table_destroy(filenames); return NULL; }