From patchwork Fri Feb 25 22:38:02 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chunqiang Tang X-Patchwork-Id: 84611 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id C908DB7103 for ; Sat, 26 Feb 2011 10:52:07 +1100 (EST) Received: from localhost ([127.0.0.1]:51732 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Pt6oR-00073y-BP for incoming@patchwork.ozlabs.org; Fri, 25 Feb 2011 18:11:03 -0500 Received: from [140.186.70.92] (port=49155 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Pt6SH-00065V-CZ for qemu-devel@nongnu.org; Fri, 25 Feb 2011 17:48:15 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Pt6S5-0004kF-W3 for qemu-devel@nongnu.org; Fri, 25 Feb 2011 17:48:09 -0500 Received: from e4.ny.us.ibm.com ([32.97.182.144]:52279) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Pt6S5-0004k9-N0 for qemu-devel@nongnu.org; Fri, 25 Feb 2011 17:47:57 -0500 Received: from d01dlp01.pok.ibm.com (d01dlp01.pok.ibm.com [9.56.224.56]) by e4.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p1PMSsxo006682 for ; Fri, 25 Feb 2011 17:28:59 -0500 Received: from d01relay07.pok.ibm.com (d01relay07.pok.ibm.com [9.56.227.147]) by d01dlp01.pok.ibm.com (Postfix) with ESMTP id CB5E638C8038 for ; Fri, 25 Feb 2011 17:47:56 -0500 (EST) Received: from d01av03.pok.ibm.com (d01av03.pok.ibm.com [9.56.224.217]) by d01relay07.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p1PMltCN2289742 for ; Fri, 25 Feb 2011 17:47:55 -0500 Received: from d01av03.pok.ibm.com (loopback [127.0.0.1]) by d01av03.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p1PMltkN020982 for ; Fri, 25 Feb 2011 19:47:55 -0300 Received: from localhost.localdomain ([9.59.229.24]) by d01av03.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p1PMlp9K020693; Fri, 25 Feb 2011 19:47:55 -0300 From: Chunqiang Tang To: qemu-devel@nongnu.org Date: Fri, 25 Feb 2011 17:38:02 -0500 Message-Id: <1298673486-3573-22-git-send-email-ctang@us.ibm.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1298673486-3573-1-git-send-email-ctang@us.ibm.com> References: <1298673486-3573-1-git-send-email-ctang@us.ibm.com> X-Content-Scanned: Fidelis XPS MAILER X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 32.97.182.144 Cc: Chunqiang Tang Subject: [Qemu-devel] [PATCH 22/26] FVD: add impl of interface bdrv_update() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch is part of the Fast Virtual Disk (FVD) proposal. See http://wiki.qemu.org/Features/FVD. This patch adds FVD's implementation of the bdrv_update() interface. Signed-off-by: Chunqiang Tang --- block/fvd-update.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 272 insertions(+), 2 deletions(-) diff --git a/block/fvd-update.c b/block/fvd-update.c index 2498618..4ef4969 100644 --- a/block/fvd-update.c +++ b/block/fvd-update.c @@ -1,5 +1,5 @@ /* - * QEMU Fast Virtual Disk Format bdrv_update + * QEMU Fast Virtual Disk Format Misc Functions of BlockDriver Interface * * Copyright IBM, Corp. 2010 * @@ -13,9 +13,279 @@ static int fvd_update(BlockDriverState * bs, QEMUOptionParameter * options) { - return -ENOTSUP; + BDRVFvdState *s = bs->opaque; + FvdHeader header; + int ret; + + read_fvd_header(s, &header); + + while (options && options->name) { + if (!strcmp(options->name, BLOCK_OPT_SIZE)) { + if (header.table_offset > 0) { + fprintf(stderr, "Cannot resize a compact FVD image.\n"); + return -EINVAL; + } + if (options->value.n < header.virtual_disk_size) { + printf("Warning: image's new size %" PRId64 + " is smaller than the original size %" PRId64 + ". Some image data will be truncated.\n", + options->value.n, header.virtual_disk_size); + } + header.virtual_disk_size = options->value.n; + printf("Image resized to %" PRId64 " bytes.\n", options->value.n); + } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { + if (strlen(options->value.s) > 1023) { + fprintf(stderr, "Error: the new base image name is longer " + "than 1023, which is not allowed.\n"); + return -EINVAL; + } + memset(header.base_img, 0, 1024); + pstrcpy(header.base_img, 1024, options->value.s); + printf("Backing file updated to '%s'.\n", options->value.s); + } else if (!strcmp(options->name, "data_file")) { + if (strlen(options->value.s) > 1023) { + fprintf(stderr, "Error: the new data file name is longer " + "than 1023, which is not allowed.\n"); + return -EINVAL; + } + + memset(header.data_file, 0, 1024); + pstrcpy(header.data_file, 1024, options->value.s); + printf("Data file updated to '%s'.\n", options->value.s); + } else if (!strcmp(options->name, "need_zero_init")) { + header.need_zero_init = options->value.n; + if (header.need_zero_init) { + printf("need_zero_init is turned on.\n"); + } else { + printf("need_zero_init is turned off.\n"); + } + } else if (!strcmp(options->name, "copy_on_read")) { + header.copy_on_read = options->value.n; + if (header.copy_on_read) { + printf("Copy on read is enabled for this disk.\n"); + } else { + printf("Copy on read is disabled for this disk.\n"); + } + } else if (!strcmp(options->name, "clean_shutdown")) { + header.clean_shutdown = options->value.n; + if (header.clean_shutdown) { + printf("clean_shutdown is manually set to true\n"); + } else { + printf("clean_shutdown is manually set to false\n"); + } + } else if (!strcmp(options->name, "journal_buf_size")) { + header.journal_buf_size = options->value.n; + printf("journal_buf_size is updated to %"PRIu64" bytes.\n", + header.journal_buf_size); + } else if (!strcmp(options->name, "journal_clean_buf_period")) { + header.journal_clean_buf_period = options->value.n; + printf("journal_clean_buf_period is updated to %"PRIu64 + " milliseconds.\n", + header.journal_clean_buf_period); + } else if (!strcmp(options->name,"max_outstanding_copy_on_read_data")) { + header.max_outstanding_copy_on_read_data = options->value.n; + if (header.max_outstanding_copy_on_read_data <= 0) { + fprintf(stderr, "Error: max_outstanding_copy_on_read_data " + "must be positive.\n"); + return -EINVAL; + } + printf("max_outstanding_copy_on_read_data updated to %" PRId64 + ".\n", header.max_outstanding_copy_on_read_data); + } else if (!strcmp(options->name, "init_data_region")) { + if (options->value.n && !s->data_region_prepared) { + init_data_region(s); + } + } else if (!strcmp(options->name, "prefetch_start_delay")) { + if (options->value.n <= 0) { + header.prefetch_start_delay = -1; + } else { + header.prefetch_start_delay = options->value.n; + } + if (header.prefetch_start_delay > 0) { + printf("Prefetch starting delay updated to %" PRId64 + " seconds.\n", header.prefetch_start_delay); + } else { + printf("Prefetch starting delay updated to %" PRId64 + " seconds. " + "Because of the negative value, prefetching is " + "disabled for this image.\n", + header.prefetch_start_delay); + } + } else if (!strcmp(options->name, "num_prefetch_slots")) { + header.num_prefetch_slots = options->value.n; + if (header.num_prefetch_slots < 1) { + fprintf(stderr, "Error: num_prefetch_slots " + "%d is not a positive integer.\n", + header.num_prefetch_slots); + return -EINVAL; + } + printf("num_prefetch_slots updated to %d.\n", + header.num_prefetch_slots); + } else if (!strcmp(options->name, "bytes_per_prefetch")) { + header.bytes_per_prefetch = options->value.n; + if (header.bytes_per_prefetch < DEF_PAGE_SIZE) { + fprintf(stderr, "Error: bytes_per_prefetch cannot be smaller " + "than %d.\n", DEF_PAGE_SIZE); + return -EINVAL; + } + printf("bytes_per_prefetch updated to %" PRIu64 ".\n", + header.bytes_per_prefetch); + } else if (!strcmp(options->name, "prefetch_min_read_throughput")) { + header.prefetch_min_read_throughput = options->value.n; + printf("prefetch_min_read_throughput updated to %" + PRIu64 " KB/s\n", header.prefetch_min_read_throughput); + } else if (!strcmp(options->name, "prefetch_min_write_throughput")) { + header.prefetch_min_write_throughput = options->value.n; + printf("prefetch_min_write_throughput updated to %" + PRIu64 "KB/s\n", header.prefetch_min_write_throughput); + } else if (!strcmp(options->name, + "prefetch_read_throughput_measure_time")) { + header.prefetch_read_throughput_measure_time = options->value.n; + printf("prefetch_read_throughput_measure_time updated to %" PRIu64 + " ms\n", header.prefetch_read_throughput_measure_time); + } else if (!strcmp(options->name, + "prefetch_write_throughput_measure_time")) { + header.prefetch_write_throughput_measure_time = options->value.n; + printf("prefetch_write_throughput_measure_time updated to %" PRIu64 + " ms\n", header.prefetch_write_throughput_measure_time); + } else if (!strcmp(options->name, + "prefetch_over_threshold_throttle_time")) { + header.prefetch_throttle_time = options->value.n; + if (header.prefetch_throttle_time > 0) { + printf("prefetch_over_threshold_throttle_time updated to %" + PRIu64 "ms.\n", header.prefetch_throttle_time); + } else { + printf("prefetch_over_threshold_throttle_time updated to %" + PRIu64 "ms. It is not positive and hence no " + "throttling will be applied to prefetch.\n", + header.prefetch_throttle_time); + } + } else if (!strcmp(options->name, "storage_grow_unit")) { + header.storage_grow_unit = options->value.n; + if (header.storage_grow_unit < header.chunk_size) { + header.storage_grow_unit = header.chunk_size; + } + printf("storage_grow_unit updated to %" PRIu64 "\n", + header.storage_grow_unit); + } else if (!strcmp(options->name, "add_storage_cmd")) { + if (strlen(options->value.s) > 1023) { + fprintf(stderr, "Error: add_storage_cmd is longer than 1023, " + "which is not allowed.\n"); + return -EINVAL; + } + pstrcpy(header.add_storage_cmd, 1024, options->value.s); + } else { + fprintf(stderr, "Error: unknown option '%s=%s'\n", + options->name, options->value.s); + return -EINVAL; + } + options++; + } + + if ((ret = update_fvd_header(s, &header))) { + return ret; + } + ret = bdrv_flush(s->fvd_metadata); + return ret; } static QEMUOptionParameter fvd_update_options[] = { + { + .name = BLOCK_OPT_SIZE, + .type = OPT_SIZE, + .help = "Virtual disk size"}, + { + .name = "storage_grow_unit", + .type = OPT_SIZE, + .help = "Storage grow unit"}, + { + .name = "add_storage_cmd", + .type = OPT_STRING, + .help = "Command to add storage when running out of space"}, + { + .name = BLOCK_OPT_BACKING_FILE, + .type = OPT_STRING, + .help = "File name of a backing image"}, + { + .name = BLOCK_OPT_BACKING_FMT, + .type = OPT_STRING, + .help = "Image format of the backing image"}, + { + .name = "data_file", + .type = OPT_STRING, + .help = "File name of a data file"}, + { + .name = "data_file_fmt", + .type = OPT_STRING, + .help = "Image format of the data file"}, + { + .name = "copy_on_read", + .type = OPT_FLAG, + .help = "copy_on_read=on|off"}, + { + .name = "prefetch_start_delay", + .type = OPT_NUMBER, + .help = "Delay in seconds before starting whole image prefetching. "}, + { + .name = "journal_size", + .type = OPT_SIZE, + .help = "Journal size"}, + { + .name = "need_zero_init", + .type = OPT_FLAG, + .help = "compact_image=on|off"}, + { + .name = "max_outstanding_copy_on_read_data", + .type = OPT_SIZE, + .help = "copy_on_read is temporarily disabled when unsaved data exceed " + "this threshold (in bytes)"}, + { + .name = "init_data_region", + .type = OPT_FLAG, + .help = "if enabled the image file will be expanded to its full size"}, + { + .name = "journal_buf_size", + .type = OPT_SIZE, + .help = "size of in-memory journal buffer (in bytes)"}, + { + .name = "journal_clean_buf_period", + .type = OPT_NUMBER, + .help = "(milliseconds)"}, + { + .name = "num_prefetch_slots", + .type = OPT_NUMBER, + .help = "Number of concurrent prefetches allowed"}, + { + .name = "bytes_per_prefetch", + .type = OPT_NUMBER, + .help = "Data to read per prefetch"}, + { + .name = "prefetch_over_threshold_throttle_time", + .type = OPT_NUMBER, + .help = "(in milliseconds)"}, + { + .name = "prefetch_read_throughput_measure_time", + .type = OPT_NUMBER, + .help = "(in milliseconds)"}, + { + .name = "prefetch_write_throughput_measure_time", + .type = OPT_NUMBER, + .help = "(in milliseconds)"}, + { + .name = "prefetch_min_read_throughput", + .type = OPT_NUMBER, + .help = "(in KB/s)"}, + { + .name = "prefetch_max_read_throughput", + .type = OPT_NUMBER, + .help = "(in KB/s)"}, + { + .name = "prefetch_min_write_throughput", + .type = OPT_NUMBER, + .help = "(in KB/s)"}, + { + .name = "prefetch_max_write_throughput", + .type = OPT_NUMBER, + .help = "(in KB/s)"}, {NULL} };