Patchwork [22/26] FVD: add impl of interface bdrv_update()

login
register
mail settings
Submitter Chunqiang Tang
Date Feb. 25, 2011, 10:38 p.m.
Message ID <1298673486-3573-22-git-send-email-ctang@us.ibm.com>
Download mbox | patch
Permalink /patch/84611/
State New
Headers show

Comments

Chunqiang Tang - Feb. 25, 2011, 10:38 p.m.
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 <ctang@us.ibm.com>
---
 block/fvd-update.c |  274 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 272 insertions(+), 2 deletions(-)

Patch

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}
 };