]> git.proxmox.com Git - mirror_qemu.git/blobdiff - block.c
xen-block: scale sector based quantities correctly
[mirror_qemu.git] / block.c
diff --git a/block.c b/block.c
index c6786cd35b29f786336308730ab5038a51ad1604..3050854528838b06ccbdf2ce879cd94bbc5ca03a 100644 (file)
--- a/block.c
+++ b/block.c
@@ -2983,6 +2983,53 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
                              NULL, errp);
 }
 
+/* Return true if the NULL-terminated @list contains @str */
+static bool is_str_in_list(const char *str, const char *const *list)
+{
+    if (str && list) {
+        int i;
+        for (i = 0; list[i] != NULL; i++) {
+            if (!strcmp(str, list[i])) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+/*
+ * Check that every option set in @bs->options is also set in
+ * @new_opts.
+ *
+ * Options listed in the common_options list and in
+ * @bs->drv->mutable_opts are skipped.
+ *
+ * Return 0 on success, otherwise return -EINVAL and set @errp.
+ */
+static int bdrv_reset_options_allowed(BlockDriverState *bs,
+                                      const QDict *new_opts, Error **errp)
+{
+    const QDictEntry *e;
+    /* These options are common to all block drivers and are handled
+     * in bdrv_reopen_prepare() so they can be left out of @new_opts */
+    const char *const common_options[] = {
+        "node-name", "discard", "cache.direct", "cache.no-flush",
+        "read-only", "auto-read-only", "detect-zeroes", NULL
+    };
+
+    for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
+        if (!qdict_haskey(new_opts, e->key) &&
+            !is_str_in_list(e->key, common_options) &&
+            !is_str_in_list(e->key, bs->drv->mutable_opts)) {
+            error_setg(errp, "Option '%s' cannot be reset "
+                       "to its default value", e->key);
+            return -EINVAL;
+        }
+    }
+
+    return 0;
+}
+
 /*
  * Returns true if @child can be reached recursively from @bs
  */
@@ -3207,7 +3254,7 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
  * All affected nodes must be drained between bdrv_reopen_queue() and
  * bdrv_reopen_multiple().
  */
-int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp)
+int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
 {
     int ret = -1;
     BlockReopenQueueEntry *bs_entry, *next;
@@ -3300,7 +3347,7 @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
 
     bdrv_subtree_drained_begin(bs);
     queue = bdrv_reopen_queue(NULL, bs, opts, true);
-    ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, errp);
+    ret = bdrv_reopen_multiple(queue, errp);
     bdrv_subtree_drained_end(bs);
 
     return ret;
@@ -3546,6 +3593,17 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
     }
 
     if (drv->bdrv_reopen_prepare) {
+        /*
+         * If a driver-specific option is missing, it means that we
+         * should reset it to its default value.
+         * But not all options allow that, so we need to check it first.
+         */
+        ret = bdrv_reset_options_allowed(reopen_state->bs,
+                                         reopen_state->options, errp);
+        if (ret) {
+            goto error;
+        }
+
         ret = drv->bdrv_reopen_prepare(reopen_state, queue, &local_err);
         if (ret) {
             if (local_err != NULL) {
@@ -4160,14 +4218,15 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs)
 /*
  * Return true if at least one of the backing links between @bs and
  * @base is frozen. @errp is set if that's the case.
+ * @base must be reachable from @bs, or NULL.
  */
 bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
                                   Error **errp)
 {
     BlockDriverState *i;
 
-    for (i = bs; i != base && i->backing; i = backing_bs(i)) {
-        if (i->backing->frozen) {
+    for (i = bs; i != base; i = backing_bs(i)) {
+        if (i->backing && i->backing->frozen) {
             error_setg(errp, "Cannot change '%s' link from '%s' to '%s'",
                        i->backing->name, i->node_name,
                        backing_bs(i)->node_name);
@@ -4182,6 +4241,7 @@ bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
  * Freeze all backing links between @bs and @base.
  * If any of the links is already frozen the operation is aborted and
  * none of the links are modified.
+ * @base must be reachable from @bs, or NULL.
  * Returns 0 on success. On failure returns < 0 and sets @errp.
  */
 int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
@@ -4193,8 +4253,10 @@ int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
         return -EPERM;
     }
 
-    for (i = bs; i != base && i->backing; i = backing_bs(i)) {
-        i->backing->frozen = true;
+    for (i = bs; i != base; i = backing_bs(i)) {
+        if (i->backing) {
+            i->backing->frozen = true;
+        }
     }
 
     return 0;
@@ -4203,14 +4265,17 @@ int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
 /*
  * Unfreeze all backing links between @bs and @base. The caller must
  * ensure that all links are frozen before using this function.
+ * @base must be reachable from @bs, or NULL.
  */
 void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base)
 {
     BlockDriverState *i;
 
-    for (i = bs; i != base && i->backing; i = backing_bs(i)) {
-        assert(i->backing->frozen);
-        i->backing->frozen = false;
+    for (i = bs; i != base; i = backing_bs(i)) {
+        if (i->backing) {
+            assert(i->backing->frozen);
+            i->backing->frozen = false;
+        }
     }
 }
 
@@ -4292,11 +4357,10 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
     QLIST_FOREACH_SAFE(c, &top->parents, next_parent, next) {
         /* Check whether we are allowed to switch c from top to base */
         GSList *ignore_children = g_slist_prepend(NULL, c);
-        bdrv_check_update_perm(base, NULL, c->perm, c->shared_perm,
-                               ignore_children, &local_err);
+        ret = bdrv_check_update_perm(base, NULL, c->perm, c->shared_perm,
+                                     ignore_children, &local_err);
         g_slist_free(ignore_children);
-        if (local_err) {
-            ret = -EPERM;
+        if (ret < 0) {
             error_report_err(local_err);
             goto exit;
         }