All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi
@ 2013-04-16 16:05 Pavel Hrdina
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error() Pavel Hrdina
                   ` (11 more replies)
  0 siblings, 12 replies; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-16 16:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: phrdina, armbru, lcapitulino

I'm sending patches for all commands in one patch series because the
savevm command depends on delvm command.

This patch series introduces new design of these commands:

* QMP vm-snapshot-save:
    - { 'command': 'vm-snapshot-save',
        'data': { 'name': 'str' },
        'returns': 'SnapshotInfo' }
    - vm-snapshot-save returns an error if there is an existing snapshot with
      the same name
    - you cannot provide an id for a new snapshot
    - all information about created snapshot will be returned

* QMP vm-snapshot-load
    - { 'command': 'vm-snapshot-load',
        'data': { '*name': 'str', '*id': 'str' },
        'returns': 'SnapshotInfo' }
    - one of the name or id must be provided
    - if both are provided they will match only the snapshot with the same name
      and id
    - returns SnapshotInfo only if the snapshot exists.

* QMP vm-snapshot-delete:
    - { 'command': 'vm-snapshot-delete',
        'data': { '*name': 'str', '*id': 'str' },
        'returns': 'SnapshotInfo' }
    - same rules as vm-snapshot-load

* HMP savevm:
    - args_type = "force:-f,name:s?",
    - if the name is not provided the HMP command will generates new one for QMP
      command
    - if there is already a snapshot with provided or generated name it will
      fails
    - there will be an optional -f parameter to force saving requested snapshot
      and it will internally use vm-snapshot-delete and then vm-snapshot-save
    - all information about created snapshot will be printed

* HMP loadvm:
    - args_type = "id:-i,name:s",
    - follow the same behavior as the QMP command
    - it load snapshot that match the provided name
    - if an id flag is provided, it load snapshot that match the name parameter
      as an id of snapshot

* HMP delvm:
    - args_type = "id:-i,name:s"
    - same rules as loadvm

Pavel Hrdina (11):
  qemu-img: introduce qemu_img_handle_error()
  block: update error reporting for bdrv_snapshot_delete() and related
    functions
  savevm: update bdrv_snapshot_find() to find snapshot by id or name
  qapi: Convert delvm
  block: update error reporting for bdrv_snapshot_goto() and related
    functions
  savevm: update error reporting for qemu_loadvm_state()
  qapi: Convert loadvm
  block: update error reporting for bdrv_snapshot_create() and related
    functions
  savevm: update error reporting off qemu_savevm_state() and related
    functions
  qapi: Convert savevm
  savevm: remove backward compatibility from bdrv_snapshot_find()

 block.c                   | 100 +++++++------
 block/qcow2-snapshot.c    |  71 ++++++---
 block/qcow2.h             |  16 +-
 block/rbd.c               |  50 ++++---
 block/sheepdog.c          |  61 ++++----
 hmp-commands.hx           |  48 +++---
 hmp.c                     | 119 +++++++++++++++
 hmp.h                     |   3 +
 include/block/block.h     |  17 ++-
 include/block/block_int.h |  17 ++-
 include/sysemu/sysemu.h   |  12 +-
 migration.c               |  15 +-
 monitor.c                 |  12 --
 qapi-schema.json          |  54 +++++++
 qemu-img.c                |  54 ++++---
 qmp-commands.hx           | 127 +++++++++++++++-
 savevm.c                  | 363 +++++++++++++++++++++++++---------------------
 vl.c                      |   7 +-
 18 files changed, 782 insertions(+), 364 deletions(-)

-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error()
  2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
@ 2013-04-16 16:05 ` Pavel Hrdina
  2013-04-16 16:46   ` Eric Blake
  2013-04-18 11:44   ` Kevin Wolf
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 02/11] block: update error reporting for bdrv_snapshot_delete() and related functions Pavel Hrdina
                   ` (10 subsequent siblings)
  11 siblings, 2 replies; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-16 16:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: phrdina, armbru, lcapitulino

Later in the patch series we will use this function few times.
This will avoid of duplicating the code.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
 qemu-img.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 31627b0..dbacdb7 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -322,6 +322,16 @@ static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
     return 0;
 }
 
+static int qemu_img_handle_error(const char *msg, Error *err)
+{
+    if (error_is_set(&err)) {
+        error_report("%s: %s", msg, error_get_pretty(err));
+        error_free(err);
+        return 1;
+    }
+    return 0;
+}
+
 static int img_create(int argc, char **argv)
 {
     int c;
@@ -400,13 +410,8 @@ static int img_create(int argc, char **argv)
 
     bdrv_img_create(filename, fmt, base_filename, base_fmt,
                     options, img_size, BDRV_O_FLAGS, &local_err, quiet);
-    if (error_is_set(&local_err)) {
-        error_report("%s", error_get_pretty(local_err));
-        error_free(local_err);
-        return 1;
-    }
 
-    return 0;
+    return qemu_img_handle_error("qemu-img create failed", local_err);
 }
 
 static void dump_json_image_check(ImageCheck *check, bool quiet)
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 02/11] block: update error reporting for bdrv_snapshot_delete() and related functions
  2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error() Pavel Hrdina
@ 2013-04-16 16:05 ` Pavel Hrdina
  2013-04-16 17:14   ` Eric Blake
  2013-04-18 12:55   ` Kevin Wolf
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 03/11] savevm: update bdrv_snapshot_find() to find snapshot by id or name Pavel Hrdina
                   ` (9 subsequent siblings)
  11 siblings, 2 replies; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-16 16:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: phrdina, armbru, lcapitulino


Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
 block.c                   | 22 ++++++++++++++--------
 block/qcow2-snapshot.c    | 21 +++++++++++++++------
 block/qcow2.h             |  4 +++-
 block/rbd.c               | 11 ++++++++---
 block/sheepdog.c          |  6 ++++--
 include/block/block.h     |  4 +++-
 include/block/block_int.h |  4 +++-
 qemu-img.c                |  9 ++++-----
 savevm.c                  | 26 ++++++++++----------------
 9 files changed, 64 insertions(+), 43 deletions(-)

diff --git a/block.c b/block.c
index 4ad663d..fb065e6 100644
--- a/block.c
+++ b/block.c
@@ -3391,16 +3391,22 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
     return -ENOTSUP;
 }
 
-int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+void bdrv_snapshot_delete(BlockDriverState *bs,
+                          const char *snapshot_id,
+                          Error **errp)
 {
     BlockDriver *drv = bs->drv;
-    if (!drv)
-        return -ENOMEDIUM;
-    if (drv->bdrv_snapshot_delete)
-        return drv->bdrv_snapshot_delete(bs, snapshot_id);
-    if (bs->file)
-        return bdrv_snapshot_delete(bs->file, snapshot_id);
-    return -ENOTSUP;
+
+    if (!drv) {
+        error_setg(errp, "device '%s' has no medium", bdrv_get_device_name(bs));
+    } else if (drv->bdrv_snapshot_delete) {
+        drv->bdrv_snapshot_delete(bs, snapshot_id, errp);
+    } else if (bs->file) {
+        bdrv_snapshot_delete(bs->file, snapshot_id, errp);
+    } else {
+        error_setg(errp, "snapshots are not supported on device '%s'",
+                   bdrv_get_device_name(bs));
+    }
 }
 
 int bdrv_snapshot_list(BlockDriverState *bs,
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 992a5c8..2ebeadc 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -530,7 +530,9 @@ fail:
     return ret;
 }
 
-int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+void qcow2_snapshot_delete(BlockDriverState *bs,
+                           const char *snapshot_id,
+                           Error **errp)
 {
     BDRVQcowState *s = bs->opaque;
     QCowSnapshot sn;
@@ -539,7 +541,9 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
     /* Search the snapshot */
     snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
     if (snapshot_index < 0) {
-        return -ENOENT;
+        error_setg(errp, "qcow2: failed to find snapshot '%s' by id or name",
+                   snapshot_id);
+        return;
     }
     sn = s->snapshots[snapshot_index];
 
@@ -550,7 +554,9 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
     s->nb_snapshots--;
     ret = qcow2_write_snapshots(bs);
     if (ret < 0) {
-        return ret;
+        error_setg_errno(errp, -ret, "qcow2: failed to remove snapshot '%s' "
+                         "from snapshot list", sn.name);
+        return;
     }
 
     /*
@@ -567,14 +573,18 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
     ret = qcow2_update_snapshot_refcount(bs, sn.l1_table_offset,
                                          sn.l1_size, -1);
     if (ret < 0) {
-        return ret;
+        error_setg_errno(errp, -ret,
+                         "qcow2: failed to update snapshot refcount");
+        return;
     }
     qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t));
 
     /* must update the copied flag on the current cluster offsets */
     ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
     if (ret < 0) {
-        return ret;
+        error_setg_errno(errp, -ret,
+                         "qcow2: failed to update snapshot refcount");
+        return;
     }
 
 #ifdef DEBUG_ALLOC
@@ -583,7 +593,6 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
         qcow2_check_refcounts(bs, &result, 0);
     }
 #endif
-    return 0;
 }
 
 int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
diff --git a/block/qcow2.h b/block/qcow2.h
index 9421843..dbd332d 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -384,7 +384,9 @@ int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
 /* qcow2-snapshot.c functions */
 int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
 int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
-int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
+void qcow2_snapshot_delete(BlockDriverState *bs,
+                           const char *snapshot_id,
+                           Error **errp);
 int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
 int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name);
 
diff --git a/block/rbd.c b/block/rbd.c
index 141b488..c10edbf 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -871,14 +871,19 @@ static int qemu_rbd_snap_create(BlockDriverState *bs,
     return 0;
 }
 
-static int qemu_rbd_snap_remove(BlockDriverState *bs,
-                                const char *snapshot_name)
+static void qemu_rbd_snap_remove(BlockDriverState *bs,
+                                 const char *snapshot_name,
+                                 Error **errp)
 {
     BDRVRBDState *s = bs->opaque;
     int r;
 
     r = rbd_snap_remove(s->image, snapshot_name);
-    return r;
+    if (r < 0) {
+        error_setg_errno(errp, -r, "rbd: failed to remove snapshot '%s' on "
+                         "device '%s'", snapshot_name,
+                         bdrv_get_device_name(bs));
+    }
 }
 
 static int qemu_rbd_snap_rollback(BlockDriverState *bs,
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 1c5b532..270fa64 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1908,10 +1908,12 @@ out:
     return ret;
 }
 
-static int sd_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+static void sd_snapshot_delete(BlockDriverState *bs,
+                               const char *snapshot_id,
+                               Error **errp)
 {
     /* FIXME: Delete specified snapshot id.  */
-    return 0;
+    return;
 }
 
 static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
diff --git a/include/block/block.h b/include/block/block.h
index ebd9512..db8c6aa 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -337,7 +337,9 @@ int bdrv_snapshot_create(BlockDriverState *bs,
                          QEMUSnapshotInfo *sn_info);
 int bdrv_snapshot_goto(BlockDriverState *bs,
                        const char *snapshot_id);
-int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
+void bdrv_snapshot_delete(BlockDriverState *bs,
+                          const char *snapshot_id,
+                          Error **errp);
 int bdrv_snapshot_list(BlockDriverState *bs,
                        QEMUSnapshotInfo **psn_info);
 int bdrv_snapshot_load_tmp(BlockDriverState *bs,
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 458cde3..53c52bb 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -157,7 +157,9 @@ struct BlockDriver {
                                 QEMUSnapshotInfo *sn_info);
     int (*bdrv_snapshot_goto)(BlockDriverState *bs,
                               const char *snapshot_id);
-    int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id);
+    void (*bdrv_snapshot_delete)(BlockDriverState *bs,
+                                 const char *snapshot_id,
+                                 Error **errp);
     int (*bdrv_snapshot_list)(BlockDriverState *bs,
                               QEMUSnapshotInfo **psn_info);
     int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,
diff --git a/qemu-img.c b/qemu-img.c
index dbacdb7..4828fe4 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1936,6 +1936,7 @@ static int img_snapshot(int argc, char **argv)
 {
     BlockDriverState *bs;
     QEMUSnapshotInfo sn;
+    Error *local_err = NULL;
     char *filename, *snapshot_name = NULL;
     int c, ret = 0, bdrv_oflags;
     int action = 0;
@@ -2033,11 +2034,9 @@ static int img_snapshot(int argc, char **argv)
         break;
 
     case SNAPSHOT_DELETE:
-        ret = bdrv_snapshot_delete(bs, snapshot_name);
-        if (ret) {
-            error_report("Could not delete snapshot '%s': %d (%s)",
-                snapshot_name, ret, strerror(-ret));
-        }
+        bdrv_snapshot_delete(bs, snapshot_name, &local_err);
+        ret = qemu_img_handle_error("qemu-img snapshot delete failed",
+                                    local_err);
         break;
     }
 
diff --git a/savevm.c b/savevm.c
index 53515cb..6af84fd 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2225,18 +2225,17 @@ static int del_existing_snapshots(Monitor *mon, const char *name)
 {
     BlockDriverState *bs;
     QEMUSnapshotInfo sn1, *snapshot = &sn1;
-    int ret;
+    Error *local_err = NULL;
 
     bs = NULL;
     while ((bs = bdrv_next(bs))) {
         if (bdrv_can_snapshot(bs) &&
             bdrv_snapshot_find(bs, snapshot, name) >= 0)
         {
-            ret = bdrv_snapshot_delete(bs, name);
-            if (ret < 0) {
-                monitor_printf(mon,
-                               "Error while deleting snapshot on '%s'\n",
-                               bdrv_get_device_name(bs));
+            bdrv_snapshot_delete(bs, name, &local_err);
+            if (error_is_set(&local_err)) {
+                monitor_printf(mon, "%s\n", error_get_pretty(local_err));
+                error_free(local_err);
                 return -1;
             }
         }
@@ -2450,7 +2449,7 @@ int load_vmstate(const char *name)
 void do_delvm(Monitor *mon, const QDict *qdict)
 {
     BlockDriverState *bs, *bs1;
-    int ret;
+    Error *local_err = NULL;
     const char *name = qdict_get_str(qdict, "name");
 
     bs = bdrv_snapshots();
@@ -2462,15 +2461,10 @@ void do_delvm(Monitor *mon, const QDict *qdict)
     bs1 = NULL;
     while ((bs1 = bdrv_next(bs1))) {
         if (bdrv_can_snapshot(bs1)) {
-            ret = bdrv_snapshot_delete(bs1, name);
-            if (ret < 0) {
-                if (ret == -ENOTSUP)
-                    monitor_printf(mon,
-                                   "Snapshots not supported on device '%s'\n",
-                                   bdrv_get_device_name(bs1));
-                else
-                    monitor_printf(mon, "Error %d while deleting snapshot on "
-                                   "'%s'\n", ret, bdrv_get_device_name(bs1));
+            bdrv_snapshot_delete(bs1, name, &local_err);
+            if (error_is_set(&local_err)) {
+                monitor_printf(mon, "%s\n", error_get_pretty(local_err));
+                error_free(local_err);
             }
         }
     }
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 03/11] savevm: update bdrv_snapshot_find() to find snapshot by id or name
  2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error() Pavel Hrdina
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 02/11] block: update error reporting for bdrv_snapshot_delete() and related functions Pavel Hrdina
@ 2013-04-16 16:05 ` Pavel Hrdina
  2013-04-16 17:34   ` Eric Blake
  2013-04-18 13:17   ` Kevin Wolf
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 04/11] qapi: Convert delvm Pavel Hrdina
                   ` (8 subsequent siblings)
  11 siblings, 2 replies; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-16 16:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: phrdina, armbru, lcapitulino

Finding snapshot by a name which could also be an id isn't best way
how to do it. There will be rewrite of savevm, loadvm and delvm to
improve the behavior of these commands. The savevm and loadvm will
have their own patch series.

Now bdrv_snapshot_find takes more parameters. The name parameter will
be matched only against the name of the snapshot and the same applies
to id parameter.

There is one exception. If you set the last parameter, the name parameter
will be matched against the name or the id of a snapshot. This exception
is only for backward compatibility for other commands and it will be
dropped after all commands will be rewritten.

We only need to know if that snapshot exists or not. We don't care
about any error message. If snapshot exists it returns 1 otherwise
it returns 0.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
 savevm.c | 73 ++++++++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 50 insertions(+), 23 deletions(-)

diff --git a/savevm.c b/savevm.c
index 6af84fd..96a2340 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2197,25 +2197,55 @@ out:
 }
 
 static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
-                              const char *name)
+                              const char *name, const char *id, bool old_match)
 {
     QEMUSnapshotInfo *sn_tab, *sn;
-    int nb_sns, i, ret;
+    int nb_sns, i, found = 0;
+
+    if (!name && !id) {
+        return found;
+    }
 
-    ret = -ENOENT;
     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
-    if (nb_sns < 0)
-        return ret;
+    if (nb_sns < 0) {
+        return found;
+    }
+
     for(i = 0; i < nb_sns; i++) {
         sn = &sn_tab[i];
-        if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
-            *sn_info = *sn;
-            ret = 0;
-            break;
+        if (name && id) {
+            if (!strcmp(sn->id_str, id) && !strcmp(sn->name, name)) {
+                *sn_info = *sn;
+                found = 1;
+                break;
+            }
+        } else if (name) {
+            /* for compatibility for old bdrv_snapshot_find call
+             * will be removed */
+            if (old_match) {
+                if (!strcmp(sn->id_str, id) || !strcmp(sn->name, name)) {
+                    *sn_info = *sn;
+                    found = 1;
+                    break;
+                }
+            } else {
+                if (!strcmp(sn->name, name)) {
+                    *sn_info = *sn;
+                    found = 1;
+                    break;
+                }
+            }
+        } else if (id) {
+            if (!strcmp(sn->id_str, id)) {
+                *sn_info = *sn;
+                found = 1;
+                break;
+            }
         }
     }
+
     g_free(sn_tab);
-    return ret;
+    return found;
 }
 
 /*
@@ -2229,8 +2259,8 @@ static int del_existing_snapshots(Monitor *mon, const char *name)
 
     bs = NULL;
     while ((bs = bdrv_next(bs))) {
-        if (bdrv_can_snapshot(bs) &&
-            bdrv_snapshot_find(bs, snapshot, name) >= 0)
+        if (bdrv_can_snapshot(bs)
+                && bdrv_snapshot_find(bs, snapshot, name, name, true))
         {
             bdrv_snapshot_delete(bs, name, &local_err);
             if (error_is_set(&local_err)) {
@@ -2289,8 +2319,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
     sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
 
     if (name) {
-        ret = bdrv_snapshot_find(bs, old_sn, name);
-        if (ret >= 0) {
+        if (bdrv_snapshot_find(bs, old_sn, name, name, true)) {
             pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
             pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
         } else {
@@ -2380,9 +2409,8 @@ int load_vmstate(const char *name)
     }
 
     /* Don't even try to load empty VM states */
-    ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
-    if (ret < 0) {
-        return ret;
+    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, name, true)) {
+        return -ENOENT;
     } else if (sn.vm_state_size == 0) {
         error_report("This is a disk-only snapshot. Revert to it offline "
             "using qemu-img.");
@@ -2404,11 +2432,10 @@ int load_vmstate(const char *name)
             return -ENOTSUP;
         }
 
-        ret = bdrv_snapshot_find(bs, &sn, name);
-        if (ret < 0) {
+        if (!bdrv_snapshot_find(bs, &sn, name, name, true)) {
             error_report("Device '%s' does not have the requested snapshot '%s'",
                            bdrv_get_device_name(bs), name);
-            return ret;
+            return -ENOENT;
         }
     }
 
@@ -2474,7 +2501,7 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
 {
     BlockDriverState *bs, *bs1;
     QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s;
-    int nb_sns, i, ret, available;
+    int nb_sns, i, available;
     int total;
     int *available_snapshots;
     char buf[256];
@@ -2505,8 +2532,8 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
 
         while ((bs1 = bdrv_next(bs1))) {
             if (bdrv_can_snapshot(bs1) && bs1 != bs) {
-                ret = bdrv_snapshot_find(bs1, sn_info, sn->id_str);
-                if (ret < 0) {
+                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str,
+                                        true)) {
                     available = 0;
                     break;
                 }
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 04/11] qapi: Convert delvm
  2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
                   ` (2 preceding siblings ...)
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 03/11] savevm: update bdrv_snapshot_find() to find snapshot by id or name Pavel Hrdina
@ 2013-04-16 16:05 ` Pavel Hrdina
  2013-04-16 19:39   ` Eric Blake
  2013-04-18 13:28   ` Kevin Wolf
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 05/11] block: update error reporting for bdrv_snapshot_goto() and related functions Pavel Hrdina
                   ` (7 subsequent siblings)
  11 siblings, 2 replies; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-16 16:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: phrdina, armbru, lcapitulino

QMP command vm-snapshot-delete no takes two parameters name and id. They are
optional, but one of the name or id must be provided. If both are provided they
will match only the snapshot with the same name and id. The command returns
SnapshotInfo only if the snapshot exists, if snapshot doesn't exist it returns
nothing. If something goes wrong, it returns an error message.

HMP command delvm now uses the new vm-snapshot-delete, but behave slightly
different. The delvm takes one optional flag -i and one parameter name. If you
provide only the name parameter, it will match only snapshots with that name.
If you also provide the flag, it will match only snapshots with name as id.
Information about successfully deleted snapshot will be printed, if there is no
snapshot with that name or id, the appropriate message will be printed. If
something goes wrong, an error message will be printed.

These improves behavior of the command to be more strict on selecting snapshots
because actual behavior is wrong. Now if you want to delete snapshot with name '2'
but there is no snapshot with that name it could delete snapshot with id '2' and
that isn't what you want.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
 hmp-commands.hx         | 14 ++++++++------
 hmp.c                   | 35 ++++++++++++++++++++++++++++++++++
 hmp.h                   |  1 +
 include/sysemu/sysemu.h |  1 -
 qapi-schema.json        | 17 +++++++++++++++++
 qmp-commands.hx         | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-
 savevm.c                | 49 +++++++++++++++++++++++++++++++++++-------------
 7 files changed, 146 insertions(+), 21 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index df44906..d1701ce 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -339,16 +339,18 @@ ETEXI
 
     {
         .name       = "delvm",
-        .args_type  = "name:s",
-        .params     = "tag|id",
-        .help       = "delete a VM snapshot from its tag or id",
-        .mhandler.cmd = do_delvm,
+        .args_type  = "id:-i,name:s",
+        .params     = "[-i] tag|[id]",
+        .help       = "delete a VM snapshot from its tag or id if -i flag is provided",
+        .mhandler.cmd = hmp_vm_snapshot_delete,
     },
 
 STEXI
-@item delvm @var{tag}|@var{id}
+@item delvm [-i] @var{tag}|[@var{id}]
 @findex delvm
-Delete the snapshot identified by @var{tag} or @var{id}.
+Delete a snapshot identified by @var{tag}. If flag -i is provided, delete
+a snapshot indentified by @var{id}.
+
 ETEXI
 
     {
diff --git a/hmp.c b/hmp.c
index 4fb76ec..2c754b3 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1425,3 +1425,38 @@ void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
     qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err);
     hmp_handle_error(mon, &local_err);
 }
+
+void hmp_vm_snapshot_delete(Monitor *mon, const QDict *qdict)
+{
+    const char *name = qdict_get_try_str(qdict, "name");
+    const bool id = qdict_get_try_bool(qdict, "id", false);
+    Error *local_err = NULL;
+    SnapshotInfo *info;
+
+    if (id) {
+        info = qmp_vm_snapshot_delete(false, NULL, true, name, &local_err);
+    } else {
+        info = qmp_vm_snapshot_delete(true, name, false, NULL, &local_err);
+    }
+
+    if (info) {
+        char buf[256];
+        QEMUSnapshotInfo sn = {
+            .vm_state_size = info->vm_state_size,
+            .date_sec = info->date_sec,
+            .date_nsec = info->date_nsec,
+            .vm_clock_nsec = info->vm_clock_sec * 1000000000 +
+                             info->vm_clock_nsec,
+        };
+        pstrcpy(sn.id_str, sizeof(sn.id_str), info->id);
+        pstrcpy(sn.name, sizeof(sn.name), info->name);
+        monitor_printf(mon, "Deleted snapshot info:\n");
+        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), &sn));
+    } else if (!error_is_set(&local_err)) {
+        monitor_printf(mon, "Snapshot '%s' not found.\n", name);
+    }
+
+    qapi_free_SnapshotInfo(info);
+    hmp_handle_error(mon, &local_err);
+}
diff --git a/hmp.h b/hmp.h
index 95fe76e..b0667b3 100644
--- a/hmp.h
+++ b/hmp.h
@@ -85,5 +85,6 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
 void hmp_chardev_add(Monitor *mon, const QDict *qdict);
 void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
+void hmp_vm_snapshot_delete(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 6578782..f46f9d2 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -67,7 +67,6 @@ void qemu_add_machine_init_done_notifier(Notifier *notify);
 
 void do_savevm(Monitor *mon, const QDict *qdict);
 int load_vmstate(const char *name);
-void do_delvm(Monitor *mon, const QDict *qdict);
 void do_info_snapshots(Monitor *mon, const QDict *qdict);
 
 void qemu_announce_self(void);
diff --git a/qapi-schema.json b/qapi-schema.json
index 751d3c2..641f3ac 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3505,3 +3505,20 @@
     '*asl_compiler_rev':  'uint32',
     '*file':              'str',
     '*data':              'str' }}
+
+##
+# @vm-snapshot-delete:
+#
+# Delete a snapshot identified by name or id or both. One of the name or id
+# is required. It will returns SnapshotInfo of successfully deleted snapshot.
+#
+# @name: tag of an existing snapshot
+#
+# @id: id of an existing snapshot
+#
+# Returns: SnapshotInfo on success
+#
+# Since: 1.5
+##
+{ 'command': 'vm-snapshot-delete', 'data': {'*name': 'str', '*id': 'str'},
+  'returns': 'SnapshotInfo' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4d65422..86f399d 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1419,7 +1419,55 @@ Example:
 
 -> { "execute": "add_client", "arguments": { "protocol": "vnc",
                                              "fdname": "myclient" } }
-<- { "return": {} }
+<- {
+      "return": {
+         "id": "1",
+         "name": "my_snapshot",
+         "date-sec": 1364480534,
+         "date-nsec": 978215000,
+         "vm-clock-sec": 5,
+         "vm-clock-nsec": 153620449,
+        "vm-state-size": 5709953
+      }
+   }
+
+EQMP
+    {
+        .name       = "vm-snapshot-delete",
+        .args_type  = "name:s?,id:s?",
+        .params     = "[tag] [id]",
+        .help       = "delete a VM snapshot from its tag or id",
+        .mhandler.cmd_new = qmp_marshal_input_vm_snapshot_delete
+    },
+
+SQMP
+vm-snapshot-delete
+------
+
+Delete a snapshot identified by name or id or both. One of the name or id
+is required. It will returns SnapshotInfo of successfully deleted snapshot.
+
+Arguments:
+
+- "name": tag of an existing snapshot (json-string, optional)
+
+- "id": id of an existing snapshot (json-string, optional)
+
+Example:
+
+-> { "execute": "vm-snapshot-delete", "arguments": { "name": "my_snapshot" } }
+<- {
+      "return": {
+         "id": "1",
+         "name": "my_snapshot",
+         "date-sec": 1364480534,
+         "date-nsec": 978215000,
+         "vm-clock-sec": 5,
+         "vm-clock-nsec": 153620449,
+         "vm-state-size": 5709953
+      }
+   }
+
 
 EQMP
     {
diff --git a/savevm.c b/savevm.c
index 96a2340..4af7d2d 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2473,28 +2473,51 @@ int load_vmstate(const char *name)
     return 0;
 }
 
-void do_delvm(Monitor *mon, const QDict *qdict)
+SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
+                                     const bool has_id, const char *id,
+                                     Error **errp)
 {
-    BlockDriverState *bs, *bs1;
-    Error *local_err = NULL;
-    const char *name = qdict_get_str(qdict, "name");
+    BlockDriverState *bs;
+    SnapshotInfo *info = NULL;
+    QEMUSnapshotInfo sn;
+
+    if (!has_name && !has_id) {
+        error_setg(errp, "name or id must be provided");
+        return NULL;
+    }
 
     bs = bdrv_snapshots();
     if (!bs) {
-        monitor_printf(mon, "No block device supports snapshots\n");
-        return;
+        error_setg(errp, "no block device supports snapshots");
+        return NULL;
     }
 
-    bs1 = NULL;
-    while ((bs1 = bdrv_next(bs1))) {
-        if (bdrv_can_snapshot(bs1)) {
-            bdrv_snapshot_delete(bs1, name, &local_err);
-            if (error_is_set(&local_err)) {
-                monitor_printf(mon, "%s\n", error_get_pretty(local_err));
-                error_free(local_err);
+    if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
+        /* no need to set an error if snapshot doesn't exist */
+        return NULL;
+    }
+
+    info = g_malloc0(sizeof(SnapshotInfo));
+    info->id = g_strdup(sn.id_str);
+    info->name = g_strdup(sn.name);
+    info->date_nsec = sn.date_nsec;
+    info->date_sec = sn.date_sec;
+    info->vm_state_size = sn.vm_state_size;
+    info->vm_clock_nsec = sn.vm_clock_nsec % 1000000000;
+    info->vm_clock_sec = sn.vm_clock_nsec / 1000000000;
+
+    bs = NULL;
+    while ((bs = bdrv_next(bs))) {
+        if (bdrv_can_snapshot(bs)
+                && bdrv_snapshot_find(bs, &sn, name, id, false)) {
+            bdrv_snapshot_delete(bs, sn.name, errp);
+            if (error_is_set(errp)) {
+                return NULL;
             }
         }
     }
+
+    return info;
 }
 
 void do_info_snapshots(Monitor *mon, const QDict *qdict)
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 05/11] block: update error reporting for bdrv_snapshot_goto() and related functions
  2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
                   ` (3 preceding siblings ...)
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 04/11] qapi: Convert delvm Pavel Hrdina
@ 2013-04-16 16:05 ` Pavel Hrdina
  2013-04-16 20:48   ` Eric Blake
  2013-04-23 14:08   ` Kevin Wolf
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 06/11] savevm: update error reporting for qemu_loadvm_state() Pavel Hrdina
                   ` (6 subsequent siblings)
  11 siblings, 2 replies; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-16 16:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: phrdina, armbru, lcapitulino


Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
 block.c                   | 55 ++++++++++++++++++++++++++---------------------
 block/qcow2-snapshot.c    | 32 +++++++++++++++++++--------
 block/qcow2.h             |  8 +++++--
 block/rbd.c               | 19 +++++++++++-----
 block/sheepdog.c          | 33 ++++++++++++++++------------
 include/block/block.h     |  8 ++++---
 include/block/block_int.h |  8 ++++---
 qemu-img.c                | 20 ++++++++++-------
 savevm.c                  | 21 ++++++++++--------
 9 files changed, 127 insertions(+), 77 deletions(-)

diff --git a/block.c b/block.c
index fb065e6..a760a2f 100644
--- a/block.c
+++ b/block.c
@@ -3365,30 +3365,30 @@ int bdrv_snapshot_create(BlockDriverState *bs,
     return -ENOTSUP;
 }
 
-int bdrv_snapshot_goto(BlockDriverState *bs,
-                       const char *snapshot_id)
+void bdrv_snapshot_goto(BlockDriverState *bs,
+                        const char *snapshot_id,
+                        Error **errp)
 {
     BlockDriver *drv = bs->drv;
-    int ret, open_ret;
-
-    if (!drv)
-        return -ENOMEDIUM;
-    if (drv->bdrv_snapshot_goto)
-        return drv->bdrv_snapshot_goto(bs, snapshot_id);
+    int ret;
 
-    if (bs->file) {
+    if (!drv) {
+        error_setg(errp, "device '%s' has no medium", bdrv_get_device_name(bs));
+    } else if (drv->bdrv_snapshot_goto) {
+        drv->bdrv_snapshot_goto(bs, snapshot_id, errp);
+    } else if (bs->file) {
         drv->bdrv_close(bs);
-        ret = bdrv_snapshot_goto(bs->file, snapshot_id);
-        open_ret = drv->bdrv_open(bs, NULL, bs->open_flags);
-        if (open_ret < 0) {
+        bdrv_snapshot_goto(bs->file, snapshot_id, errp);
+        ret = drv->bdrv_open(bs, NULL, bs->open_flags);
+        if (ret < 0) {
             bdrv_delete(bs->file);
             bs->drv = NULL;
-            return open_ret;
+            error_setg(errp, "failed to open '%s'", bdrv_get_device_name(bs));
         }
-        return ret;
+    } else {
+        error_setg(errp, "snapshots are not supported on device '%s'",
+                           bdrv_get_device_name(bs));
     }
-
-    return -ENOTSUP;
 }
 
 void bdrv_snapshot_delete(BlockDriverState *bs,
@@ -3410,16 +3410,23 @@ void bdrv_snapshot_delete(BlockDriverState *bs,
 }
 
 int bdrv_snapshot_list(BlockDriverState *bs,
-                       QEMUSnapshotInfo **psn_info)
+                       QEMUSnapshotInfo **psn_info,
+                       Error **errp)
 {
     BlockDriver *drv = bs->drv;
-    if (!drv)
-        return -ENOMEDIUM;
-    if (drv->bdrv_snapshot_list)
-        return drv->bdrv_snapshot_list(bs, psn_info);
-    if (bs->file)
-        return bdrv_snapshot_list(bs->file, psn_info);
-    return -ENOTSUP;
+
+    if (!drv) {
+        error_setg(errp, "device '%s' has no medium", bdrv_get_device_name(bs));
+        return 0;
+    } else if (drv->bdrv_snapshot_list) {
+        return drv->bdrv_snapshot_list(bs, psn_info, errp);
+    } else if (bs->file) {
+        return bdrv_snapshot_list(bs->file, psn_info, errp);
+    } else {
+        error_setg(errp, "snapshots are not supported on device '%s'",
+                   bdrv_get_device_name(bs));
+        return 0;
+    }
 }
 
 int bdrv_snapshot_load_tmp(BlockDriverState *bs,
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 2ebeadc..4a69b88 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -417,7 +417,9 @@ fail:
 }
 
 /* copy the snapshot 'snapshot_name' into the current disk image */
-int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
+void qcow2_snapshot_goto(BlockDriverState *bs,
+                         const char *snapshot_id,
+                         Error **errp)
 {
     BDRVQcowState *s = bs->opaque;
     QCowSnapshot *sn;
@@ -429,14 +431,15 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     /* Search the snapshot */
     snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
     if (snapshot_index < 0) {
-        return -ENOENT;
+        error_setg(errp, "qcow2: failed to find snapshot '%s' by id or name",
+                   snapshot_id);
+        return;
     }
     sn = &s->snapshots[snapshot_index];
 
     if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
-        error_report("qcow2: Loading snapshots with different disk "
-            "size is not implemented");
-        ret = -ENOTSUP;
+        error_setg(errp, "qcow2: loading snapshots with different disk size "
+                   "is not implemented");
         goto fail;
     }
 
@@ -447,6 +450,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
      */
     ret = qcow2_grow_l1_table(bs, sn->l1_size, true);
     if (ret < 0) {
+        error_setg_errno(errp, -ret, "fqcow2: ailed to grow L1 table");
         goto fail;
     }
 
@@ -465,18 +469,23 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
 
     ret = bdrv_pread(bs->file, sn->l1_table_offset, sn_l1_table, sn_l1_bytes);
     if (ret < 0) {
+        error_setg_errno(errp, -ret,
+                         "qcow2: failed to load data into L1 table");
         goto fail;
     }
 
     ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset,
                                          sn->l1_size, 1);
     if (ret < 0) {
+        error_setg_errno(errp, -ret,
+                         "qcow2: failed to update snapshot refcount");
         goto fail;
     }
 
     ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, sn_l1_table,
                            cur_l1_bytes);
     if (ret < 0) {
+        error_setg_errno(errp, -ret, "qcow2: failed to save L1 table");
         goto fail;
     }
 
@@ -502,6 +511,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     }
 
     if (ret < 0) {
+        error_setg_errno(errp, -ret, "qcow2: failed to sync L1 table");
         goto fail;
     }
 
@@ -514,6 +524,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
      */
     ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
     if (ret < 0) {
+        error_setg_errno(errp, -ret,
+                         "qcow2: failed to update snapshot refcount");
         goto fail;
     }
 
@@ -523,11 +535,10 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
         qcow2_check_refcounts(bs, &result, 0);
     }
 #endif
-    return 0;
+    return;
 
 fail:
     g_free(sn_l1_table);
-    return ret;
 }
 
 void qcow2_snapshot_delete(BlockDriverState *bs,
@@ -595,7 +606,9 @@ void qcow2_snapshot_delete(BlockDriverState *bs,
 #endif
 }
 
-int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
+int qcow2_snapshot_list(BlockDriverState *bs,
+                        QEMUSnapshotInfo **psn_tab,
+                        Error **errp)
 {
     BDRVQcowState *s = bs->opaque;
     QEMUSnapshotInfo *sn_tab, *sn_info;
@@ -604,7 +617,8 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 
     if (!s->nb_snapshots) {
         *psn_tab = NULL;
-        return s->nb_snapshots;
+        error_setg(errp, "qcow2: there is no snapshot available");
+        return 0;
     }
 
     sn_tab = g_malloc0(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
diff --git a/block/qcow2.h b/block/qcow2.h
index dbd332d..ae62953 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -383,11 +383,15 @@ int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
 
 /* qcow2-snapshot.c functions */
 int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
-int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
+void qcow2_snapshot_goto(BlockDriverState *bs,
+                         const char *snapshot_id,
+                         Error **errp);
 void qcow2_snapshot_delete(BlockDriverState *bs,
                            const char *snapshot_id,
                            Error **errp);
-int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
+int qcow2_snapshot_list(BlockDriverState *bs,
+                        QEMUSnapshotInfo **psn_tab,
+                        Error **errp);
 int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name);
 
 void qcow2_free_snapshots(BlockDriverState *bs);
diff --git a/block/rbd.c b/block/rbd.c
index c10edbf..9259621 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -886,18 +886,22 @@ static void qemu_rbd_snap_remove(BlockDriverState *bs,
     }
 }
 
-static int qemu_rbd_snap_rollback(BlockDriverState *bs,
-                                  const char *snapshot_name)
+static void qemu_rbd_snap_rollback(BlockDriverState *bs,
+                                   const char *snapshot_name,
+                                   Error **errp)
 {
     BDRVRBDState *s = bs->opaque;
     int r;
 
     r = rbd_snap_rollback(s->image, snapshot_name);
-    return r;
+    if (r < 0) {
+        error_setg_errno(errp, -r, "rbd: failed to rollback snapshot");
+    }
 }
 
 static int qemu_rbd_snap_list(BlockDriverState *bs,
-                              QEMUSnapshotInfo **psn_tab)
+                              QEMUSnapshotInfo **psn_tab,
+                              Error **errp)
 {
     BDRVRBDState *s = bs->opaque;
     QEMUSnapshotInfo *sn_info, *sn_tab = NULL;
@@ -913,7 +917,12 @@ static int qemu_rbd_snap_list(BlockDriverState *bs,
         }
     } while (snap_count == -ERANGE);
 
-    if (snap_count <= 0) {
+    if (snap_count < 0) {
+        error_setg_errno(errp, -snap_count, "rbd: failed to find snapshots");
+        snap_count = 0;
+    }
+
+    if (snap_count == 0) {
         goto done;
     }
 
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 270fa64..3d44575 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1838,7 +1838,9 @@ cleanup:
     return ret;
 }
 
-static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
+static void sd_snapshot_goto(BlockDriverState *bs,
+                             const char *snapshot_id,
+                             Error **errp)
 {
     BDRVSheepdogState *s = bs->opaque;
     BDRVSheepdogState *old_s;
@@ -1863,12 +1865,14 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
 
     ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1);
     if (ret) {
-        error_report("Failed to find_vdi_name");
+        error_setg_errno(errp, -ret, "sd: failed to find VDI snapshot '%s'",
+                         vdi);
         goto out;
     }
 
     fd = connect_to_sdog(s);
     if (fd < 0) {
+        error_setg_errno(errp, -fd, "sd: failed to connect to sdog");
         ret = fd;
         goto out;
     }
@@ -1880,14 +1884,15 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     closesocket(fd);
 
     if (ret) {
+        error_setg_errno(errp, -ret, "sd: failed to open VDI snapshot '%s'",
+                         vdi);
         goto out;
     }
 
     memcpy(&s->inode, buf, sizeof(s->inode));
 
     if (!s->inode.vm_state_size) {
-        error_report("Invalid snapshot");
-        ret = -ENOENT;
+        error_setg(errp, "sd: invalid snapshot '%s'", snapshot_id);
         goto out;
     }
 
@@ -1896,16 +1901,12 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     g_free(buf);
     g_free(old_s);
 
-    return 0;
+    return;
 out:
     /* recover bdrv_sd_state */
     memcpy(s, old_s, sizeof(BDRVSheepdogState));
     g_free(buf);
     g_free(old_s);
-
-    error_report("failed to open. recover old bdrv_sd_state.");
-
-    return ret;
 }
 
 static void sd_snapshot_delete(BlockDriverState *bs,
@@ -1916,11 +1917,13 @@ static void sd_snapshot_delete(BlockDriverState *bs,
     return;
 }
 
-static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
+static int sd_snapshot_list(BlockDriverState *bs,
+                            QEMUSnapshotInfo **psn_tab,
+                            Error **errp)
 {
     BDRVSheepdogState *s = bs->opaque;
     SheepdogReq req;
-    int fd, nr = 1024, ret, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long);
+    int fd, nr = 1024, ret = 0, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long);
     QEMUSnapshotInfo *sn_tab = NULL;
     unsigned wlen, rlen;
     int found = 0;
@@ -1934,7 +1937,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 
     fd = connect_to_sdog(s);
     if (fd < 0) {
-        ret = fd;
+        error_setg_errno(errp, -fd, "sd: failed to connect to sdog");
         goto out;
     }
 
@@ -1950,6 +1953,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 
     closesocket(fd);
     if (ret) {
+        error_setg_errno(errp, -ret, "sd: failed to read VDIs");
         goto out;
     }
 
@@ -1961,7 +1965,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 
     fd = connect_to_sdog(s);
     if (fd < 0) {
-        ret = fd;
+        error_setg_errno(errp, -fd, "sd: failed to connect to sdog");
         goto out;
     }
 
@@ -2001,7 +2005,8 @@ out:
     g_free(vdi_inuse);
 
     if (ret < 0) {
-        return ret;
+        error_setg_errno(errp, -ret, "sd: failed to read VDI object");
+        return 0;
     }
 
     return found;
diff --git a/include/block/block.h b/include/block/block.h
index db8c6aa..33d498b 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -335,13 +335,15 @@ int bdrv_is_snapshot(BlockDriverState *bs);
 BlockDriverState *bdrv_snapshots(void);
 int bdrv_snapshot_create(BlockDriverState *bs,
                          QEMUSnapshotInfo *sn_info);
-int bdrv_snapshot_goto(BlockDriverState *bs,
-                       const char *snapshot_id);
+void bdrv_snapshot_goto(BlockDriverState *bs,
+                        const char *snapshot_id,
+                        Error **errp);
 void bdrv_snapshot_delete(BlockDriverState *bs,
                           const char *snapshot_id,
                           Error **errp);
 int bdrv_snapshot_list(BlockDriverState *bs,
-                       QEMUSnapshotInfo **psn_info);
+                       QEMUSnapshotInfo **psn_info,
+                       Error **errp);
 int bdrv_snapshot_load_tmp(BlockDriverState *bs,
                            const char *snapshot_name);
 char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 53c52bb..c56d923 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -155,13 +155,15 @@ struct BlockDriver {
 
     int (*bdrv_snapshot_create)(BlockDriverState *bs,
                                 QEMUSnapshotInfo *sn_info);
-    int (*bdrv_snapshot_goto)(BlockDriverState *bs,
-                              const char *snapshot_id);
+    void (*bdrv_snapshot_goto)(BlockDriverState *bs,
+                               const char *snapshot_id,
+                               Error **errp);
     void (*bdrv_snapshot_delete)(BlockDriverState *bs,
                                  const char *snapshot_id,
                                  Error **errp);
     int (*bdrv_snapshot_list)(BlockDriverState *bs,
-                              QEMUSnapshotInfo **psn_info);
+                              QEMUSnapshotInfo **psn_info,
+                              Error **errp);
     int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,
                                   const char *snapshot_name);
     int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
diff --git a/qemu-img.c b/qemu-img.c
index 4828fe4..06cd8af 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1563,10 +1563,13 @@ static void dump_snapshots(BlockDriverState *bs)
     QEMUSnapshotInfo *sn_tab, *sn;
     int nb_sns, i;
     char buf[256];
+    Error *local_err = NULL;
 
-    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
-    if (nb_sns <= 0)
+    nb_sns = bdrv_snapshot_list(bs, &sn_tab, &local_err);
+    if (qemu_img_handle_error("qemu-img dump snapshots failed", local_err)
+            || nb_sns == 0) {
         return;
+    }
     printf("Snapshot list:\n");
     printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
     for(i = 0; i < nb_sns; i++) {
@@ -1598,7 +1601,10 @@ static void collect_snapshots(BlockDriverState *bs , ImageInfo *info)
     int i, sn_count;
     QEMUSnapshotInfo *sn_tab = NULL;
     SnapshotInfoList *info_list, *cur_item = NULL;
-    sn_count = bdrv_snapshot_list(bs, &sn_tab);
+    Error *local_err = NULL;
+    sn_count = bdrv_snapshot_list(bs, &sn_tab, &local_err);
+
+    qemu_img_handle_error("qemu-img collect snapshots failed", local_err);
 
     for (i = 0; i < sn_count; i++) {
         info->has_snapshots = true;
@@ -2026,11 +2032,9 @@ static int img_snapshot(int argc, char **argv)
         break;
 
     case SNAPSHOT_APPLY:
-        ret = bdrv_snapshot_goto(bs, snapshot_name);
-        if (ret) {
-            error_report("Could not apply snapshot '%s': %d (%s)",
-                snapshot_name, ret, strerror(-ret));
-        }
+        bdrv_snapshot_goto(bs, snapshot_name, &local_err);
+        ret = qemu_img_handle_error("qemu-img snapshot apply failed",
+                                    local_err);
         break;
 
     case SNAPSHOT_DELETE:
diff --git a/savevm.c b/savevm.c
index 4af7d2d..ca4a42e 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2206,7 +2206,7 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
         return found;
     }
 
-    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+    nb_sns = bdrv_snapshot_list(bs, &sn_tab, NULL);
     if (nb_sns < 0) {
         return found;
     }
@@ -2401,6 +2401,7 @@ int load_vmstate(const char *name)
     QEMUSnapshotInfo sn;
     QEMUFile *f;
     int ret;
+    Error *local_err;
 
     bs_vm_state = bdrv_snapshots();
     if (!bs_vm_state) {
@@ -2445,11 +2446,11 @@ int load_vmstate(const char *name)
     bs = NULL;
     while ((bs = bdrv_next(bs))) {
         if (bdrv_can_snapshot(bs)) {
-            ret = bdrv_snapshot_goto(bs, name);
-            if (ret < 0) {
-                error_report("Error %d while activating snapshot '%s' on '%s'",
-                             ret, name, bdrv_get_device_name(bs));
-                return ret;
+            bdrv_snapshot_goto(bs, name, &local_err);
+            if (error_is_set(&local_err)) {
+                error_report("%s", error_get_pretty(local_err));
+                error_free(local_err);
+                return -1;
             }
         }
     }
@@ -2528,6 +2529,7 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
     int total;
     int *available_snapshots;
     char buf[256];
+    Error *local_err = NULL;
 
     bs = bdrv_snapshots();
     if (!bs) {
@@ -2535,9 +2537,10 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
         return;
     }
 
-    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
-    if (nb_sns < 0) {
-        monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
+    nb_sns = bdrv_snapshot_list(bs, &sn_tab, &local_err);
+    if (error_is_set(&local_err)) {
+        monitor_printf(mon, "%s\n", error_get_pretty(local_err));
+        error_free(local_err);
         return;
     }
 
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 06/11] savevm: update error reporting for qemu_loadvm_state()
  2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
                   ` (4 preceding siblings ...)
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 05/11] block: update error reporting for bdrv_snapshot_goto() and related functions Pavel Hrdina
@ 2013-04-16 16:05 ` Pavel Hrdina
  2013-04-16 21:42   ` Eric Blake
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 07/11] qapi: Convert loadvm Pavel Hrdina
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-16 16:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: phrdina, armbru, lcapitulino


Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
 include/sysemu/sysemu.h |  2 +-
 migration.c             |  9 +++----
 savevm.c                | 64 ++++++++++++++++++++++++-------------------------
 3 files changed, 37 insertions(+), 38 deletions(-)

diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index f46f9d2..70c6927 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -78,7 +78,7 @@ int qemu_savevm_state_iterate(QEMUFile *f);
 void qemu_savevm_state_complete(QEMUFile *f);
 void qemu_savevm_state_cancel(void);
 uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size);
-int qemu_loadvm_state(QEMUFile *f);
+void qemu_loadvm_state(QEMUFile *f, Error **errp);
 
 /* SLIRP */
 void do_info_slirp(Monitor *mon);
diff --git a/migration.c b/migration.c
index 3b4b467..fd8c869 100644
--- a/migration.c
+++ b/migration.c
@@ -93,12 +93,13 @@ void qemu_start_incoming_migration(const char *uri, Error **errp)
 static void process_incoming_migration_co(void *opaque)
 {
     QEMUFile *f = opaque;
-    int ret;
+    Error *local_err = NULL;
 
-    ret = qemu_loadvm_state(f);
+    qemu_loadvm_state(f, &local_err);
     qemu_fclose(f);
-    if (ret < 0) {
-        fprintf(stderr, "load of migration failed\n");
+    if (error_is_set(&local_err)) {
+        fprintf(stderr, "%s\n", error_get_pretty(local_err));
+        error_free(local_err);
         exit(0);
     }
     qemu_announce_self();
diff --git a/savevm.c b/savevm.c
index ca4a42e..0419e0d 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2077,7 +2077,7 @@ typedef struct LoadStateEntry {
     int version_id;
 } LoadStateEntry;
 
-int qemu_loadvm_state(QEMUFile *f)
+void qemu_loadvm_state(QEMUFile *f, Error **errp)
 {
     QLIST_HEAD(, LoadStateEntry) loadvm_handlers =
         QLIST_HEAD_INITIALIZER(loadvm_handlers);
@@ -2086,21 +2086,25 @@ int qemu_loadvm_state(QEMUFile *f)
     unsigned int v;
     int ret;
 
-    if (qemu_savevm_state_blocked(NULL)) {
-        return -EINVAL;
+    if (qemu_savevm_state_blocked(errp)) {
+        return;
     }
 
     v = qemu_get_be32(f);
-    if (v != QEMU_VM_FILE_MAGIC)
-        return -EINVAL;
+    if (v != QEMU_VM_FILE_MAGIC) {
+        error_setg(errp, "unknown vmstate file magic");
+        return;
+    }
 
     v = qemu_get_be32(f);
     if (v == QEMU_VM_FILE_VERSION_COMPAT) {
-        fprintf(stderr, "SaveVM v2 format is obsolete and don't work anymore\n");
-        return -ENOTSUP;
+        error_setg(errp, "saveVM v2 format is obsolete and don't work anymore");
+        return;
+    }
+    if (v != QEMU_VM_FILE_VERSION) {
+        error_setg(errp, "unknown vmstate file version");
+        return;
     }
-    if (v != QEMU_VM_FILE_VERSION)
-        return -ENOTSUP;
 
     while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
         uint32_t instance_id, version_id, section_id;
@@ -2122,16 +2126,15 @@ int qemu_loadvm_state(QEMUFile *f)
             /* Find savevm section */
             se = find_se(idstr, instance_id);
             if (se == NULL) {
-                fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id);
-                ret = -EINVAL;
+                error_setg(errp, "unknown savevm section or instance '%s' %d",
+                           idstr, instance_id);
                 goto out;
             }
 
             /* Validate version */
             if (version_id > se->version_id) {
-                fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n",
-                        version_id, idstr, se->version_id);
-                ret = -EINVAL;
+                error_setg(errp, "unsupported version %d for '%s' v%d",
+                           version_id, idstr, se->version_id);
                 goto out;
             }
 
@@ -2145,8 +2148,8 @@ int qemu_loadvm_state(QEMUFile *f)
 
             ret = vmstate_load(f, le->se, le->version_id);
             if (ret < 0) {
-                fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
-                        instance_id, idstr);
+                error_setg(errp, "error while loading state for instance "
+                           "0x%x of device '%s'", instance_id, idstr);
                 goto out;
             }
             break;
@@ -2160,40 +2163,35 @@ int qemu_loadvm_state(QEMUFile *f)
                 }
             }
             if (le == NULL) {
-                fprintf(stderr, "Unknown savevm section %d\n", section_id);
-                ret = -EINVAL;
+                error_setg(errp, "unknown savevm section %d", section_id);
                 goto out;
             }
 
             ret = vmstate_load(f, le->se, le->version_id);
             if (ret < 0) {
-                fprintf(stderr, "qemu: warning: error while loading state section id %d\n",
+                error_setg(errp, "error while loading state section id %d",
                         section_id);
                 goto out;
             }
             break;
         default:
-            fprintf(stderr, "Unknown savevm section type %d\n", section_type);
-            ret = -EINVAL;
+            error_setg(errp, "unknown savevm section type %d", section_type);
             goto out;
         }
     }
 
     cpu_synchronize_all_post_init();
 
-    ret = 0;
+    ret = qemu_file_get_error(f);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "failed to load vmstate");
+    }
 
 out:
     QLIST_FOREACH_SAFE(le, &loadvm_handlers, entry, new_le) {
         QLIST_REMOVE(le, entry);
         g_free(le);
     }
-
-    if (ret == 0) {
-        ret = qemu_file_get_error(f);
-    }
-
-    return ret;
 }
 
 static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
@@ -2400,7 +2398,6 @@ int load_vmstate(const char *name)
     BlockDriverState *bs, *bs_vm_state;
     QEMUSnapshotInfo sn;
     QEMUFile *f;
-    int ret;
     Error *local_err;
 
     bs_vm_state = bdrv_snapshots();
@@ -2463,12 +2460,13 @@ int load_vmstate(const char *name)
     }
 
     qemu_system_reset(VMRESET_SILENT);
-    ret = qemu_loadvm_state(f);
+    qemu_loadvm_state(f, &local_err);
 
     qemu_fclose(f);
-    if (ret < 0) {
-        error_report("Error %d while loading VM state", ret);
-        return ret;
+    if (error_is_set(&local_err)) {
+        error_report("%s", error_get_pretty(local_err));
+        error_free(local_err);
+        return -1;
     }
 
     return 0;
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 07/11] qapi: Convert loadvm
  2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
                   ` (5 preceding siblings ...)
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 06/11] savevm: update error reporting for qemu_loadvm_state() Pavel Hrdina
@ 2013-04-16 16:05 ` Pavel Hrdina
  2013-04-16 23:43   ` Eric Blake
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 08/11] block: update error reporting for bdrv_snapshot_create() and related functions Pavel Hrdina
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-16 16:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: phrdina, armbru, lcapitulino

QMP command vm-snapshot-load and HMP command loadvm behave similar to
vm-snapshot-delete and delvm. The only different is that they will load
the snapshot instead of deleting it.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
 hmp-commands.hx         | 16 +++++-----
 hmp.c                   | 35 ++++++++++++++++++++++
 hmp.h                   |  1 +
 include/sysemu/sysemu.h |  1 -
 monitor.c               | 12 --------
 qapi-schema.json        | 18 +++++++++++
 qmp-commands.hx         | 38 ++++++++++++++++++++++++
 savevm.c                | 79 ++++++++++++++++++++++++++++++-------------------
 vl.c                    |  7 ++++-
 9 files changed, 156 insertions(+), 51 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index d1701ce..e80410b 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -324,17 +324,19 @@ ETEXI
 
     {
         .name       = "loadvm",
-        .args_type  = "name:s",
-        .params     = "tag|id",
-        .help       = "restore a VM snapshot from its tag or id",
-        .mhandler.cmd = do_loadvm,
+        .args_type  = "id:-i,name:s",
+        .params     = "[-i] tag|[id]",
+        .help       = "restore a VM snapshot from its tag or id if -i flag is provided",
+        .mhandler.cmd = hmp_vm_snapshot_load,
     },
 
 STEXI
-@item loadvm @var{tag}|@var{id}
+@item loadvm [-i] @var{tag}|[@var{id}]
 @findex loadvm
-Set the whole virtual machine to the snapshot identified by the tag
-@var{tag} or the unique snapshot ID @var{id}.
+Set the whole virtual machine to the snapshot identified by the tag @var{tag}.
+If flag -i is provided, snapshot identified by @var{id} will be loaded. It must
+be a snapshot of a whole VM.
+
 ETEXI
 
     {
diff --git a/hmp.c b/hmp.c
index 2c754b3..516bb09 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1460,3 +1460,38 @@ void hmp_vm_snapshot_delete(Monitor *mon, const QDict *qdict)
     qapi_free_SnapshotInfo(info);
     hmp_handle_error(mon, &local_err);
 }
+
+void hmp_vm_snapshot_load(Monitor *mon, const QDict *qdict)
+{
+    const char *name = qdict_get_try_str(qdict, "name");
+    const bool id = qdict_get_try_bool(qdict, "id", false);
+    Error *local_err = NULL;
+    SnapshotInfo *info = NULL;
+
+    if (id) {
+        info = qmp_vm_snapshot_load(false, NULL, true, name, &local_err);
+    } else {
+        info = qmp_vm_snapshot_load(true, name, false, NULL, &local_err);
+    }
+
+    if (info) {
+        char buf[256];
+        QEMUSnapshotInfo sn = {
+            .vm_state_size = info->vm_state_size,
+            .date_sec = info->date_sec,
+            .date_nsec = info->date_nsec,
+            .vm_clock_nsec = info->vm_clock_sec * 1000000000 +
+                             info->vm_clock_nsec,
+        };
+        pstrcpy(sn.id_str, sizeof(sn.id_str), info->id);
+        pstrcpy(sn.name, sizeof(sn.name), info->name);
+        monitor_printf(mon, "Loaded snapshot's info:\n");
+        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), &sn));
+    } else if (!error_is_set(&local_err)) {
+        monitor_printf(mon, "Snapshot '%s' not found.\n", name);
+    }
+
+    qapi_free_SnapshotInfo(info);
+    hmp_handle_error(mon, &local_err);
+}
diff --git a/hmp.h b/hmp.h
index b0667b3..a65cbf2 100644
--- a/hmp.h
+++ b/hmp.h
@@ -86,5 +86,6 @@ void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
 void hmp_chardev_add(Monitor *mon, const QDict *qdict);
 void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
 void hmp_vm_snapshot_delete(Monitor *mon, const QDict *qdict);
+void hmp_vm_snapshot_load(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 70c6927..913f49f 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -66,7 +66,6 @@ void qemu_remove_exit_notifier(Notifier *notify);
 void qemu_add_machine_init_done_notifier(Notifier *notify);
 
 void do_savevm(Monitor *mon, const QDict *qdict);
-int load_vmstate(const char *name);
 void do_info_snapshots(Monitor *mon, const QDict *qdict);
 
 void qemu_announce_self(void);
diff --git a/monitor.c b/monitor.c
index 332abe7..02c20ef 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2093,18 +2093,6 @@ void qmp_closefd(const char *fdname, Error **errp)
     error_set(errp, QERR_FD_NOT_FOUND, fdname);
 }
 
-static void do_loadvm(Monitor *mon, const QDict *qdict)
-{
-    int saved_vm_running  = runstate_is_running();
-    const char *name = qdict_get_str(qdict, "name");
-
-    vm_stop(RUN_STATE_RESTORE_VM);
-
-    if (load_vmstate(name) == 0 && saved_vm_running) {
-        vm_start();
-    }
-}
-
 int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
 {
     mon_fd_t *monfd;
diff --git a/qapi-schema.json b/qapi-schema.json
index 641f3ac..d19b410 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3522,3 +3522,21 @@
 ##
 { 'command': 'vm-snapshot-delete', 'data': {'*name': 'str', '*id': 'str'},
   'returns': 'SnapshotInfo' }
+
+##
+# @vm-snapshot-load:
+#
+# Set the whole virtual machine to the snapshot identified by the tag
+# or the unique snapshot id or both. It must be a snapshot of a whole VM and
+# at least one of the name or id parameter must be specified.
+#
+# @name: tag of existing snapshot
+#
+# @id: id of existing snapshot
+#
+# Returns: SnapshotInfo on success
+#
+# Since: 1.5
+##
+{ 'command': 'vm-snapshot-load', 'data': {'*name': 'str', '*id': 'str'},
+  'returns': 'SnapshotInfo' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 86f399d..f2d5da8 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1471,6 +1471,44 @@ Example:
 
 EQMP
     {
+        .name       = "vm-snapshot-load",
+        .args_type  = "name:s?,id:s?",
+        .params     = "[name] [id]",
+        .help       = "restore a VM snapshot from its tag or id",
+        .mhandler.cmd_new = qmp_marshal_input_vm_snapshot_load
+    },
+
+SQMP
+vm-snapshot-load
+------
+
+Set the whole virtual machine to the snapshot identified by the tag
+or the unique snapshot id or both. It must be a snapshot of a whole VM and
+at least one of the name or id parameter must be specified.
+
+Arguments:
+
+- "name": tag of existing snapshot (json-string, optional)
+
+- "id": id of existing snapshot (json-string, optional)
+
+Example:
+
+-> { "execute": "vm-snapshot-load", "arguments": { "name": "my_snapshot" } }
+<- {
+      "return": {
+         "id": "1",
+         "name": "my_snapshot",
+         "date-sec": 1364480534,
+         "date-nsec": 978215000,
+         "vm-clock-sec": 5,
+         "vm-clock-nsec": 153620449,
+         "vm-state-size": 5709953
+      }
+   }
+
+EQMP
+    {
         .name       = "qmp_capabilities",
         .args_type  = "",
         .params     = "",
diff --git a/savevm.c b/savevm.c
index 0419e0d..1258f5f 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2393,26 +2393,35 @@ void qmp_xen_save_devices_state(const char *filename, Error **errp)
         vm_start();
 }
 
-int load_vmstate(const char *name)
+SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
+                                   bool has_id, const char *id, Error **errp)
 {
     BlockDriverState *bs, *bs_vm_state;
     QEMUSnapshotInfo sn;
     QEMUFile *f;
-    Error *local_err;
+    SnapshotInfo *info = NULL;
+    int saved_vm_running;
+
+    if (!has_name && !has_id) {
+        error_setg(errp, "name or id must be specified");
+        return NULL;
+    }
 
     bs_vm_state = bdrv_snapshots();
     if (!bs_vm_state) {
-        error_report("No block device supports snapshots");
-        return -ENOTSUP;
+        error_setg(errp, "no block device supports snapshots");
+        return NULL;
     }
 
     /* Don't even try to load empty VM states */
-    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, name, true)) {
-        return -ENOENT;
-    } else if (sn.vm_state_size == 0) {
-        error_report("This is a disk-only snapshot. Revert to it offline "
-            "using qemu-img.");
-        return -EINVAL;
+    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id, false)) {
+        return NULL;
+    }
+
+    if (sn.vm_state_size == 0) {
+        error_setg(errp, "this is a disk-only snapshot, revert to it offline "
+            "using qemu-img");
+        return NULL;
     }
 
     /* Verify if there is any device that doesn't support snapshots and is
@@ -2425,29 +2434,28 @@ int load_vmstate(const char *name)
         }
 
         if (!bdrv_can_snapshot(bs)) {
-            error_report("Device '%s' is writable but does not support snapshots.",
-                               bdrv_get_device_name(bs));
-            return -ENOTSUP;
+            error_setg(errp, "device '%s' is writable but does not support "
+                       "snapshots", bdrv_get_device_name(bs));
+            return NULL;
         }
 
-        if (!bdrv_snapshot_find(bs, &sn, name, name, true)) {
-            error_report("Device '%s' does not have the requested snapshot '%s'",
-                           bdrv_get_device_name(bs), name);
-            return -ENOENT;
+        if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
+            return NULL;
         }
     }
 
+    saved_vm_running = runstate_is_running();
+    vm_stop(RUN_STATE_RESTORE_VM);
+
     /* Flush all IO requests so they don't interfere with the new state.  */
     bdrv_drain_all();
 
     bs = NULL;
     while ((bs = bdrv_next(bs))) {
         if (bdrv_can_snapshot(bs)) {
-            bdrv_snapshot_goto(bs, name, &local_err);
-            if (error_is_set(&local_err)) {
-                error_report("%s", error_get_pretty(local_err));
-                error_free(local_err);
-                return -1;
+            bdrv_snapshot_goto(bs, sn.name, errp);
+            if (error_is_set(errp)) {
+                return NULL;
             }
         }
     }
@@ -2455,21 +2463,32 @@ int load_vmstate(const char *name)
     /* restore the VM state */
     f = qemu_fopen_bdrv(bs_vm_state, 0);
     if (!f) {
-        error_report("Could not open VM state file");
-        return -EINVAL;
+        error_setg(errp, "could not open VM state file");
+        return NULL;
     }
 
     qemu_system_reset(VMRESET_SILENT);
-    qemu_loadvm_state(f, &local_err);
+    qemu_loadvm_state(f, errp);
 
     qemu_fclose(f);
-    if (error_is_set(&local_err)) {
-        error_report("%s", error_get_pretty(local_err));
-        error_free(local_err);
-        return -1;
+    if (error_is_set(errp)) {
+        return NULL;
     }
 
-    return 0;
+    if (saved_vm_running) {
+        vm_start();
+    }
+
+    info = g_malloc0(sizeof(SnapshotInfo));
+    info->id = g_strdup(sn.id_str);
+    info->name = g_strdup(sn.name);
+    info->date_nsec = sn.date_nsec;
+    info->date_sec = sn.date_sec;
+    info->vm_state_size = sn.vm_state_size;
+    info->vm_clock_nsec = sn.vm_clock_nsec % 1000000000;
+    info->vm_clock_sec = sn.vm_clock_nsec / 1000000000;
+
+    return info;
 }
 
 SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
diff --git a/vl.c b/vl.c
index 0598998..b0a5f01 100644
--- a/vl.c
+++ b/vl.c
@@ -4409,8 +4409,13 @@ int main(int argc, char **argv, char **envp)
 
     qemu_system_reset(VMRESET_SILENT);
     if (loadvm) {
-        if (load_vmstate(loadvm) < 0) {
+        Error *errp = NULL;
+        qmp_vm_snapshot_load(true, loadvm, false, NULL, &errp);
+
+        if (error_is_set(&errp)) {
             autostart = 0;
+            error_report("%s", error_get_pretty(errp));
+            error_free(errp);
         }
     }
 
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 08/11] block: update error reporting for bdrv_snapshot_create() and related functions
  2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
                   ` (6 preceding siblings ...)
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 07/11] qapi: Convert loadvm Pavel Hrdina
@ 2013-04-16 16:05 ` Pavel Hrdina
  2013-04-16 23:54   ` Eric Blake
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 09/11] savevm: update error reporting off qemu_savevm_state() " Pavel Hrdina
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-16 16:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: phrdina, armbru, lcapitulino


Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
 block.c                   | 23 ++++++++++++++---------
 block/qcow2-snapshot.c    | 18 ++++++++++++------
 block/qcow2.h             |  4 +++-
 block/rbd.c               | 20 +++++++++++---------
 block/sheepdog.c          | 22 +++++++++++-----------
 include/block/block.h     |  5 +++--
 include/block/block_int.h |  5 +++--
 qemu-img.c                |  8 +++-----
 savevm.c                  |  9 +++++----
 9 files changed, 65 insertions(+), 49 deletions(-)

diff --git a/block.c b/block.c
index a760a2f..7cf24f5 100644
--- a/block.c
+++ b/block.c
@@ -3352,17 +3352,22 @@ BlockDriverState *bdrv_snapshots(void)
     return NULL;
 }
 
-int bdrv_snapshot_create(BlockDriverState *bs,
-                         QEMUSnapshotInfo *sn_info)
+void bdrv_snapshot_create(BlockDriverState *bs,
+                          QEMUSnapshotInfo *sn_info,
+                          Error **errp)
 {
     BlockDriver *drv = bs->drv;
-    if (!drv)
-        return -ENOMEDIUM;
-    if (drv->bdrv_snapshot_create)
-        return drv->bdrv_snapshot_create(bs, sn_info);
-    if (bs->file)
-        return bdrv_snapshot_create(bs->file, sn_info);
-    return -ENOTSUP;
+
+    if (!drv) {
+        error_setg(errp, "device '%s' has no medium", bdrv_get_device_name(bs));
+    } else if (drv->bdrv_snapshot_create) {
+        drv->bdrv_snapshot_create(bs, sn_info, errp);
+    } else if (bs->file) {
+        bdrv_snapshot_create(bs->file, sn_info, errp);
+    } else {
+        error_setg(errp, "snapshots are not supported on device '%s'",
+                           bdrv_get_device_name(bs));
+    }
 }
 
 void bdrv_snapshot_goto(BlockDriverState *bs,
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 4a69b88..bb6a35d 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -315,7 +315,9 @@ static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
 }
 
 /* if no id is provided, a new one is constructed */
-int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
+void qcow2_snapshot_create(BlockDriverState *bs,
+                           QEMUSnapshotInfo *sn_info,
+                           Error **errp)
 {
     BDRVQcowState *s = bs->opaque;
     QCowSnapshot *new_snapshot_list = NULL;
@@ -334,7 +336,8 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
 
     /* Check that the ID is unique */
     if (find_snapshot_by_id(bs, sn_info->id_str) >= 0) {
-        return -EEXIST;
+        error_setg(errp, "qcow2: parameter 'id' has to be unique ID");
+        return;
     }
 
     /* Populate sn with passed data */
@@ -350,7 +353,8 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     /* Allocate the L1 table of the snapshot and copy the current one there. */
     l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
     if (l1_table_offset < 0) {
-        ret = l1_table_offset;
+        error_setg_errno(errp, -l1_table_offset,
+                         "qcow2: failed to allocate L1 table");
         goto fail;
     }
 
@@ -365,6 +369,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table,
                       s->l1_size * sizeof(uint64_t));
     if (ret < 0) {
+        error_setg_errno(errp, -ret, "qcow2: failed to save L1 table");
         goto fail;
     }
 
@@ -378,6 +383,8 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
      */
     ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
     if (ret < 0) {
+        error_setg_errno(errp, -ret,
+                         "qcow2: failed to update snapshot refcount");
         goto fail;
     }
 
@@ -395,6 +402,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     if (ret < 0) {
         g_free(s->snapshots);
         s->snapshots = old_snapshot_list;
+        error_setg_errno(errp, -ret, "qcow2: failed to write new snapshot");
         goto fail;
     }
 
@@ -406,14 +414,12 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
       qcow2_check_refcounts(bs, &result, 0);
     }
 #endif
-    return 0;
+    return;
 
 fail:
     g_free(sn->id_str);
     g_free(sn->name);
     g_free(l1_table);
-
-    return ret;
 }
 
 /* copy the snapshot 'snapshot_name' into the current disk image */
diff --git a/block/qcow2.h b/block/qcow2.h
index ae62953..c194cff 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -382,7 +382,9 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
 int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
 
 /* qcow2-snapshot.c functions */
-int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
+void qcow2_snapshot_create(BlockDriverState *bs,
+                           QEMUSnapshotInfo *sn_info,
+                           Error **errp);
 void qcow2_snapshot_goto(BlockDriverState *bs,
                          const char *snapshot_id,
                          Error **errp);
diff --git a/block/rbd.c b/block/rbd.c
index 9259621..1f073fe 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -839,14 +839,16 @@ static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset)
     return 0;
 }
 
-static int qemu_rbd_snap_create(BlockDriverState *bs,
-                                QEMUSnapshotInfo *sn_info)
+static void qemu_rbd_snap_create(BlockDriverState *bs,
+                                 QEMUSnapshotInfo *sn_info,
+                                 Error **errp)
 {
     BDRVRBDState *s = bs->opaque;
     int r;
 
     if (sn_info->name[0] == '\0') {
-        return -EINVAL; /* we need a name for rbd snapshots */
+        error_setg(errp, "rbd: parameter 'name' cannot be empty");
+        return;
     }
 
     /*
@@ -855,20 +857,20 @@ static int qemu_rbd_snap_create(BlockDriverState *bs,
      */
     if (sn_info->id_str[0] != '\0' &&
         strcmp(sn_info->id_str, sn_info->name) != 0) {
-        return -EINVAL;
+        error_setg(errp, "rbd: ID and name have to be equal");
+        return;
     }
 
     if (strlen(sn_info->name) >= sizeof(sn_info->id_str)) {
-        return -ERANGE;
+        error_setg(errp, "rbd: parameter 'name' has to be shorter than %zd "
+                   "chars", sizeof(sn_info->id_str));
+        return;
     }
 
     r = rbd_snap_create(s->image, sn_info->name);
     if (r < 0) {
-        error_report("failed to create snap: %s", strerror(-r));
-        return r;
+        error_setg_errno(errp, -r, "rbd: failed to create snapshot");
     }
-
-    return 0;
 }
 
 static void qemu_rbd_snap_remove(BlockDriverState *bs,
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 3d44575..996441d 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1767,7 +1767,9 @@ static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs)
     return acb->ret;
 }
 
-static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
+static void sd_snapshot_create(BlockDriverState *bs,
+                               QEMUSnapshotInfo *sn_info,
+                               Error **errp)
 {
     BDRVSheepdogState *s = bs->opaque;
     int ret, fd;
@@ -1780,10 +1782,10 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
             s->name, sn_info->vm_state_size, s->is_snapshot);
 
     if (s->is_snapshot) {
-        error_report("You can't create a snapshot of a snapshot VDI, "
-                     "%s (%" PRIu32 ").", s->name, s->inode.vdi_id);
-
-        return -EINVAL;
+        error_setg(errp, "sd: you can't create a snapshot '%s' of a snapshot "
+                "VDI %s (%" PRIu32 ")", sn_info->name, s->name,
+                s->inode.vdi_id);
+        return;
     }
 
     dprintf("%s %s\n", sn_info->name, sn_info->id_str);
@@ -1800,22 +1802,21 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     /* refresh inode. */
     fd = connect_to_sdog(s);
     if (fd < 0) {
-        ret = fd;
+        error_setg_errno(errp, -fd, "sd: failed to connect to sdog");
         goto cleanup;
     }
 
     ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
                        s->inode.nr_copies, datalen, 0, false, s->cache_flags);
     if (ret < 0) {
-        error_report("failed to write snapshot's inode.");
+        error_setg_errno(errp, -ret, "sd: failed to write snapshot's inode");
         goto cleanup;
     }
 
     ret = do_sd_create(s, s->name, s->inode.vdi_size, s->inode.vdi_id, &new_vid,
                        1);
     if (ret < 0) {
-        error_report("failed to create inode for snapshot. %s",
-                     strerror(errno));
+        error_setg_errno(errp, -ret, "sd: failed to create inode for snapshot");
         goto cleanup;
     }
 
@@ -1825,7 +1826,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
                       s->inode.nr_copies, datalen, 0, s->cache_flags);
 
     if (ret < 0) {
-        error_report("failed to read new inode info. %s", strerror(errno));
+        error_setg_errno(errp, -ret, "sd: failed to read new inode info");
         goto cleanup;
     }
 
@@ -1835,7 +1836,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
 
 cleanup:
     closesocket(fd);
-    return ret;
 }
 
 static void sd_snapshot_goto(BlockDriverState *bs,
diff --git a/include/block/block.h b/include/block/block.h
index 33d498b..fb5a864 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -333,8 +333,9 @@ BlockStats *bdrv_query_stats(const BlockDriverState *bs);
 int bdrv_can_snapshot(BlockDriverState *bs);
 int bdrv_is_snapshot(BlockDriverState *bs);
 BlockDriverState *bdrv_snapshots(void);
-int bdrv_snapshot_create(BlockDriverState *bs,
-                         QEMUSnapshotInfo *sn_info);
+void bdrv_snapshot_create(BlockDriverState *bs,
+                          QEMUSnapshotInfo *sn_info,
+                          Error **errp);
 void bdrv_snapshot_goto(BlockDriverState *bs,
                         const char *snapshot_id,
                         Error **errp);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index c56d923..9903874 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -153,8 +153,9 @@ struct BlockDriver {
     int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
                                  const uint8_t *buf, int nb_sectors);
 
-    int (*bdrv_snapshot_create)(BlockDriverState *bs,
-                                QEMUSnapshotInfo *sn_info);
+    void (*bdrv_snapshot_create)(BlockDriverState *bs,
+                                 QEMUSnapshotInfo *sn_info,
+                                 Error **errp);
     void (*bdrv_snapshot_goto)(BlockDriverState *bs,
                                const char *snapshot_id,
                                Error **errp);
diff --git a/qemu-img.c b/qemu-img.c
index 06cd8af..2e420f3 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -2024,11 +2024,9 @@ static int img_snapshot(int argc, char **argv)
         sn.date_sec = tv.tv_sec;
         sn.date_nsec = tv.tv_usec * 1000;
 
-        ret = bdrv_snapshot_create(bs, &sn);
-        if (ret) {
-            error_report("Could not create snapshot '%s': %d (%s)",
-                snapshot_name, ret, strerror(-ret));
-        }
+        bdrv_snapshot_create(bs, &sn, &local_err);
+        ret = qemu_img_handle_error("qemu-img snapshot create failed",
+                                    local_err);
         break;
 
     case SNAPSHOT_APPLY:
diff --git a/savevm.c b/savevm.c
index 1258f5f..a8e7d60 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2283,6 +2283,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
     qemu_timeval tv;
     struct tm tm;
     const char *name = qdict_get_try_str(qdict, "name");
+    Error *local_err = NULL;
 
     /* Verify if there is a device that doesn't support snapshots and is writable */
     bs = NULL;
@@ -2355,10 +2356,10 @@ void do_savevm(Monitor *mon, const QDict *qdict)
         if (bdrv_can_snapshot(bs1)) {
             /* Write VM state size only to the image that contains the state */
             sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
-            ret = bdrv_snapshot_create(bs1, sn);
-            if (ret < 0) {
-                monitor_printf(mon, "Error while creating snapshot on '%s'\n",
-                               bdrv_get_device_name(bs1));
+            bdrv_snapshot_create(bs1, sn, &local_err);
+            if (error_is_set(&local_err)) {
+                monitor_printf(mon, "'%s'\n", error_get_pretty(local_err));
+                error_free(local_err);
             }
         }
     }
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 09/11] savevm: update error reporting off qemu_savevm_state() and related functions
  2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
                   ` (7 preceding siblings ...)
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 08/11] block: update error reporting for bdrv_snapshot_create() and related functions Pavel Hrdina
@ 2013-04-16 16:05 ` Pavel Hrdina
  2013-04-17  0:02   ` Eric Blake
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 10/11] qapi: Convert savevm Pavel Hrdina
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-16 16:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: phrdina, armbru, lcapitulino


Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
 include/sysemu/sysemu.h |  7 ++++---
 migration.c             |  6 +++---
 savevm.c                | 38 +++++++++++++++++++-------------------
 3 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 913f49f..0e3f30a 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -72,9 +72,10 @@ void qemu_announce_self(void);
 
 bool qemu_savevm_state_blocked(Error **errp);
 void qemu_savevm_state_begin(QEMUFile *f,
-                             const MigrationParams *params);
-int qemu_savevm_state_iterate(QEMUFile *f);
-void qemu_savevm_state_complete(QEMUFile *f);
+                             const MigrationParams *params,
+                             Error **errp);
+int qemu_savevm_state_iterate(QEMUFile *f, Error **errp);
+void qemu_savevm_state_complete(QEMUFile *f, Error **errp);
 void qemu_savevm_state_cancel(void);
 uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size);
 void qemu_loadvm_state(QEMUFile *f, Error **errp);
diff --git a/migration.c b/migration.c
index fd8c869..d115262 100644
--- a/migration.c
+++ b/migration.c
@@ -506,7 +506,7 @@ static void *migration_thread(void *opaque)
     bool old_vm_running = false;
 
     DPRINTF("beginning savevm\n");
-    qemu_savevm_state_begin(s->file, &s->params);
+    qemu_savevm_state_begin(s->file, &s->params, NULL);
 
     while (s->state == MIG_STATE_ACTIVE) {
         int64_t current_time;
@@ -517,7 +517,7 @@ static void *migration_thread(void *opaque)
             pending_size = qemu_savevm_state_pending(s->file, max_size);
             DPRINTF("pending size %lu max %lu\n", pending_size, max_size);
             if (pending_size && pending_size >= max_size) {
-                qemu_savevm_state_iterate(s->file);
+                qemu_savevm_state_iterate(s->file, NULL);
             } else {
                 DPRINTF("done iterating\n");
                 qemu_mutex_lock_iothread();
@@ -526,7 +526,7 @@ static void *migration_thread(void *opaque)
                 old_vm_running = runstate_is_running();
                 vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
                 qemu_file_set_rate_limit(s->file, INT_MAX);
-                qemu_savevm_state_complete(s->file);
+                qemu_savevm_state_complete(s->file, NULL);
                 qemu_mutex_unlock_iothread();
                 if (!qemu_file_get_error(s->file)) {
                     migrate_finish_set_state(s, MIG_STATE_COMPLETED);
diff --git a/savevm.c b/savevm.c
index a8e7d60..8736eb4 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1728,7 +1728,8 @@ bool qemu_savevm_state_blocked(Error **errp)
 }
 
 void qemu_savevm_state_begin(QEMUFile *f,
-                             const MigrationParams *params)
+                             const MigrationParams *params,
+                             Error **errp)
 {
     SaveStateEntry *se;
     int ret;
@@ -1769,6 +1770,7 @@ void qemu_savevm_state_begin(QEMUFile *f,
         ret = se->ops->save_live_setup(f, se->opaque);
         if (ret < 0) {
             qemu_file_set_error(f, ret);
+            error_setg_errno(errp, -ret, "failed to begin vmstate save");
             break;
         }
     }
@@ -1780,7 +1782,7 @@ void qemu_savevm_state_begin(QEMUFile *f,
  *   0 : We haven't finished, caller have to go again
  *   1 : We have finished, we can go to complete phase
  */
-int qemu_savevm_state_iterate(QEMUFile *f)
+int qemu_savevm_state_iterate(QEMUFile *f, Error **errp)
 {
     SaveStateEntry *se;
     int ret = 1;
@@ -1807,6 +1809,7 @@ int qemu_savevm_state_iterate(QEMUFile *f)
 
         if (ret < 0) {
             qemu_file_set_error(f, ret);
+            error_setg_errno(errp, -ret, "failed to iterate vmstate save");
         }
         if (ret <= 0) {
             /* Do not proceed to the next vmstate before this one reported
@@ -1819,7 +1822,7 @@ int qemu_savevm_state_iterate(QEMUFile *f)
     return ret;
 }
 
-void qemu_savevm_state_complete(QEMUFile *f)
+void qemu_savevm_state_complete(QEMUFile *f, Error **errp)
 {
     SaveStateEntry *se;
     int ret;
@@ -1844,6 +1847,7 @@ void qemu_savevm_state_complete(QEMUFile *f)
         trace_savevm_section_end(se->section_id);
         if (ret < 0) {
             qemu_file_set_error(f, ret);
+            error_setg_errno(errp, -ret, "failed to complete vmstate save");
             return;
         }
     }
@@ -1905,37 +1909,33 @@ void qemu_savevm_state_cancel(void)
     }
 }
 
-static int qemu_savevm_state(QEMUFile *f)
+static void qemu_savevm_state(QEMUFile *f, Error **errp)
 {
-    int ret;
     MigrationParams params = {
         .blk = 0,
         .shared = 0
     };
 
-    if (qemu_savevm_state_blocked(NULL)) {
-        return -EINVAL;
+    if (qemu_savevm_state_blocked(errp)) {
+        return;
     }
 
     qemu_mutex_unlock_iothread();
-    qemu_savevm_state_begin(f, &params);
+    qemu_savevm_state_begin(f, &params, errp);
     qemu_mutex_lock_iothread();
 
     while (qemu_file_get_error(f) == 0) {
-        if (qemu_savevm_state_iterate(f) > 0) {
+        if (qemu_savevm_state_iterate(f, errp) > 0) {
             break;
         }
     }
 
-    ret = qemu_file_get_error(f);
-    if (ret == 0) {
-        qemu_savevm_state_complete(f);
-        ret = qemu_file_get_error(f);
+    if (!qemu_file_get_error(f)) {
+        qemu_savevm_state_complete(f, errp);
     }
-    if (ret != 0) {
+    if (qemu_file_get_error(f)) {
         qemu_savevm_state_cancel();
     }
-    return ret;
 }
 
 static int qemu_save_device_state(QEMUFile *f)
@@ -2276,7 +2276,6 @@ void do_savevm(Monitor *mon, const QDict *qdict)
 {
     BlockDriverState *bs, *bs1;
     QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
-    int ret;
     QEMUFile *f;
     int saved_vm_running;
     uint64_t vm_state_size;
@@ -2341,11 +2340,12 @@ void do_savevm(Monitor *mon, const QDict *qdict)
         monitor_printf(mon, "Could not open VM state file\n");
         goto the_end;
     }
-    ret = qemu_savevm_state(f);
+    qemu_savevm_state(f, &local_err);
     vm_state_size = qemu_ftell(f);
     qemu_fclose(f);
-    if (ret < 0) {
-        monitor_printf(mon, "Error %d while writing VM\n", ret);
+    if (error_is_set(&local_err)) {
+        monitor_printf(mon, "%s\n", error_get_pretty(local_err));
+        error_free(local_err);
         goto the_end;
     }
 
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 10/11] qapi: Convert savevm
  2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
                   ` (8 preceding siblings ...)
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 09/11] savevm: update error reporting off qemu_savevm_state() " Pavel Hrdina
@ 2013-04-16 16:05 ` Pavel Hrdina
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find() Pavel Hrdina
  2013-04-16 16:33 ` [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Eric Blake
  11 siblings, 0 replies; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-16 16:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: phrdina, armbru, lcapitulino

QMP command vm-snapshot-save now takes one parameter name and the name is
mandatory. The command returns SnapshotInfo on success, otherwise it returns
an error message. If there is a snapshot with the same name it also returns
an error message and if you want to overwrite that snapshot, you will have to
at first call vm-snapshot-delete.

HMP command savevm now has one optional parameter name and one flag -f.
If the name parameter isn't provided the HMP command will create new one for
internally used vm-snapshot-save. You can also specify the -f flag for overwrite
existing snapshot which will internally use vm-snapshot-delete before
vm-snapshot-save, otherwise it will print an error message if there is already
a snapshot with the same name. If something else goes wrong, an error message
will be printed.

These improves behavior of the command to let you select only the name of the
snapshot you want to create. This will ensure that if you want snapshot with
the name '2', it will not rewrite or fail if there is any snapshot with id '2'.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
 hmp-commands.hx         | 18 +++++------
 hmp.c                   | 49 +++++++++++++++++++++++++++++
 hmp.h                   |  1 +
 include/sysemu/sysemu.h |  1 -
 qapi-schema.json        | 19 +++++++++++
 qmp-commands.hx         | 39 +++++++++++++++++++++++
 savevm.c                | 83 +++++++++++++++++--------------------------------
 7 files changed, 145 insertions(+), 65 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index e80410b..638f1d7 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -307,19 +307,19 @@ ETEXI
 
     {
         .name       = "savevm",
-        .args_type  = "name:s?",
-        .params     = "[tag|id]",
-        .help       = "save a VM snapshot. If no tag or id are provided, a new snapshot is created",
-        .mhandler.cmd = do_savevm,
+        .args_type  = "force:-f,name:s?",
+        .params     = "[-f] [tag]",
+        .help       = "save a VM snapshot, to replace existing snapshot use force flag",
+        .mhandler.cmd = hmp_vm_snapshot_save,
     },
 
 STEXI
-@item savevm [@var{tag}|@var{id}]
+@item savevm [@var{-f}] [@var{tag}]
 @findex savevm
-Create a snapshot of the whole virtual machine. If @var{tag} is
-provided, it is used as human readable identifier. If there is already
-a snapshot with the same tag or ID, it is replaced. More info at
-@ref{vm_snapshots}.
+Create a snapshot of the whole virtual machine. Parameter "name" is optional.
+If @var{tag} is provided, it is used as human readable identifier. If there is
+already a snapshot with the same @var{tag} or @var{id}, @var{-f} flag needs to
+be specified. More info at @ref{vm_snapshots}.
 ETEXI
 
     {
diff --git a/hmp.c b/hmp.c
index 516bb09..401cdfc 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1495,3 +1495,52 @@ void hmp_vm_snapshot_load(Monitor *mon, const QDict *qdict)
     qapi_free_SnapshotInfo(info);
     hmp_handle_error(mon, &local_err);
 }
+
+void hmp_vm_snapshot_save(Monitor *mon, const QDict *qdict)
+{
+    const char *name = qdict_get_try_str(qdict, "name");
+    bool force = qdict_get_try_bool(qdict, "force", 0);
+    Error *local_err = NULL;
+    SnapshotInfo *info = NULL;
+    qemu_timeval tv;
+    struct tm tm;
+    char tmp_name[256];
+
+    if (!name) {
+        localtime_r((const time_t *)&tv.tv_sec, &tm);
+        strftime(tmp_name, sizeof(tmp_name), "vm-%Y%m%d%H%M%S", &tm);
+        name = tmp_name;
+    }
+
+    if (force) {
+        info = qmp_vm_snapshot_delete(true, name, false, NULL, &local_err);
+        // we don't need print info about deleted snapshot
+        // it still needs to be freed
+        qapi_free_SnapshotInfo(info);
+        if (error_is_set(&local_err)) {
+            hmp_handle_error(mon, &local_err);
+            return;
+        }
+    }
+
+    info = qmp_vm_snapshot_save(name, &local_err);
+
+    if (info) {
+        char buf[256];
+        QEMUSnapshotInfo sn = {
+            .vm_state_size = info->vm_state_size,
+            .date_sec = info->date_sec,
+            .date_nsec = info->date_nsec,
+            .vm_clock_nsec = info->vm_clock_sec * 1000000000 +
+                             info->vm_clock_nsec,
+        };
+        pstrcpy(sn.id_str, sizeof(sn.id_str), info->id);
+        pstrcpy(sn.name, sizeof(sn.name), info->name);
+        monitor_printf(mon, "Created snapshot's info:\n");
+        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), &sn));
+    }
+
+    qapi_free_SnapshotInfo(info);
+    hmp_handle_error(mon, &local_err);
+}
diff --git a/hmp.h b/hmp.h
index a65cbf2..77e1715 100644
--- a/hmp.h
+++ b/hmp.h
@@ -87,5 +87,6 @@ void hmp_chardev_add(Monitor *mon, const QDict *qdict);
 void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
 void hmp_vm_snapshot_delete(Monitor *mon, const QDict *qdict);
 void hmp_vm_snapshot_load(Monitor *mon, const QDict *qdict);
+void hmp_vm_snapshot_save(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 0e3f30a..25cd310 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -65,7 +65,6 @@ void qemu_remove_exit_notifier(Notifier *notify);
 
 void qemu_add_machine_init_done_notifier(Notifier *notify);
 
-void do_savevm(Monitor *mon, const QDict *qdict);
 void do_info_snapshots(Monitor *mon, const QDict *qdict);
 
 void qemu_announce_self(void);
diff --git a/qapi-schema.json b/qapi-schema.json
index d19b410..350d2bc 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3540,3 +3540,22 @@
 ##
 { 'command': 'vm-snapshot-load', 'data': {'*name': 'str', '*id': 'str'},
   'returns': 'SnapshotInfo' }
+
+##
+# @vm-snapshot-save:
+#
+# Create a snapshot of the whole virtual machine. Provided tag as @name,
+# it is used as human readable identifier. If there is already a snapshot
+# with the same @name it returns an error.
+#
+# The VM is automatically stopped and resumed and saving a snapshot can take
+# a long time.
+#
+# @name: tag of new snapshot or tag|id of existing snapshot
+#
+# Returns: SnapshotInfo on success
+#
+# Since: 1.5
+##
+{ 'command': 'vm-snapshot-save', 'data': {'name': 'str'},
+  'returns': 'SnapshotInfo' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index f2d5da8..1b098fd 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1509,6 +1509,45 @@ Example:
 
 EQMP
     {
+        .name       = "vm-snapshot-save",
+        .args_type  = "name:s",
+        .params     = "name",
+        .help       = "save a VM snapshot",
+        .mhandler.cmd_new = qmp_marshal_input_vm_snapshot_save
+    },
+
+SQMP
+vm-snapshot-save
+------
+
+Create a snapshot of the whole virtual machine. Provided tag as name,
+it is used as human readable identifier. If there is already a snapshot
+with the same name it returns an error.
+
+The VM is automatically stopped and resumed and saving a snapshot can take
+a long time.
+
+Arguments:
+
+- "name": tag of new snapshot or tag of existing snapshot (json-string)
+
+Example:
+
+-> { "execute": "vm-snapshot-save", "arguments": { "name": "my_snapshot" } }
+<- {
+      "return": {
+         "id": "1",
+         "name": "my_snapshot",
+         "date-sec": 1364480534,
+         "date-nsec": 978215000,
+         "vm-clock-sec": 5,
+         "vm-clock-nsec": 153620449,
+         "vm-state-size": 5709953
+      }
+   }
+
+EQMP
+    {
         .name       = "qmp_capabilities",
         .args_type  = "",
         .params     = "",
diff --git a/savevm.c b/savevm.c
index 8736eb4..66753da 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2246,45 +2246,19 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
     return found;
 }
 
-/*
- * Deletes snapshots of a given name in all opened images.
- */
-static int del_existing_snapshots(Monitor *mon, const char *name)
-{
-    BlockDriverState *bs;
-    QEMUSnapshotInfo sn1, *snapshot = &sn1;
-    Error *local_err = NULL;
-
-    bs = NULL;
-    while ((bs = bdrv_next(bs))) {
-        if (bdrv_can_snapshot(bs)
-                && bdrv_snapshot_find(bs, snapshot, name, name, true))
-        {
-            bdrv_snapshot_delete(bs, name, &local_err);
-            if (error_is_set(&local_err)) {
-                monitor_printf(mon, "%s\n", error_get_pretty(local_err));
-                error_free(local_err);
-                return -1;
-            }
-        }
-    }
-
-    return 0;
-}
-
-void do_savevm(Monitor *mon, const QDict *qdict)
+SnapshotInfo *qmp_vm_snapshot_save(const char *name, Error **errp)
 {
     BlockDriverState *bs, *bs1;
     QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
+    SnapshotInfo *info = NULL;
     QEMUFile *f;
     int saved_vm_running;
     uint64_t vm_state_size;
     qemu_timeval tv;
-    struct tm tm;
-    const char *name = qdict_get_try_str(qdict, "name");
     Error *local_err = NULL;
 
-    /* Verify if there is a device that doesn't support snapshots and is writable */
+    /* Verify if there is a device that doesn't support snapshots and is
+     * writable */
     bs = NULL;
     while ((bs = bdrv_next(bs))) {
 
@@ -2293,16 +2267,16 @@ void do_savevm(Monitor *mon, const QDict *qdict)
         }
 
         if (!bdrv_can_snapshot(bs)) {
-            monitor_printf(mon, "Device '%s' is writable but does not support snapshots.\n",
-                               bdrv_get_device_name(bs));
-            return;
+            error_setg(errp, "device '%s' is writable but does not support "
+                       "snapshots", bdrv_get_device_name(bs));
+            return NULL;
         }
     }
 
     bs = bdrv_snapshots();
     if (!bs) {
-        monitor_printf(mon, "No block device can accept snapshots\n");
-        return;
+        error_setg(errp, "no block device can accept snapshots");
+        return NULL;
     }
 
     saved_vm_running = runstate_is_running();
@@ -2316,36 +2290,24 @@ void do_savevm(Monitor *mon, const QDict *qdict)
     sn->date_nsec = tv.tv_usec * 1000;
     sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
 
-    if (name) {
-        if (bdrv_snapshot_find(bs, old_sn, name, name, true)) {
-            pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
-            pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
-        } else {
-            pstrcpy(sn->name, sizeof(sn->name), name);
-        }
-    } else {
-        /* cast below needed for OpenBSD where tv_sec is still 'long' */
-        localtime_r((const time_t *)&tv.tv_sec, &tm);
-        strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", &tm);
-    }
-
-    /* Delete old snapshots of the same name */
-    if (name && del_existing_snapshots(mon, name) < 0) {
+    if (bdrv_snapshot_find(bs, old_sn, name, NULL, false)) {
+        error_setg(errp, "snapshot '%s' exists", name);
         goto the_end;
+    } else {
+        pstrcpy(sn->name, sizeof(sn->name), name);
     }
 
     /* save the VM state */
     f = qemu_fopen_bdrv(bs, 1);
     if (!f) {
-        monitor_printf(mon, "Could not open VM state file\n");
+        error_setg(errp, "failed to open '%s' file", bdrv_get_device_name(bs));
         goto the_end;
     }
     qemu_savevm_state(f, &local_err);
     vm_state_size = qemu_ftell(f);
     qemu_fclose(f);
     if (error_is_set(&local_err)) {
-        monitor_printf(mon, "%s\n", error_get_pretty(local_err));
-        error_free(local_err);
+        error_propagate(errp, local_err);
         goto the_end;
     }
 
@@ -2358,15 +2320,26 @@ void do_savevm(Monitor *mon, const QDict *qdict)
             sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
             bdrv_snapshot_create(bs1, sn, &local_err);
             if (error_is_set(&local_err)) {
-                monitor_printf(mon, "'%s'\n", error_get_pretty(local_err));
-                error_free(local_err);
+                error_propagate(errp, local_err);
+                goto the_end;
             }
         }
     }
 
+    info = g_malloc0(sizeof(SnapshotInfo));
+    info->id = g_strdup(sn->id_str);
+    info->name = g_strdup(sn->name);
+    info->date_nsec = sn->date_nsec;
+    info->date_sec = sn->date_sec;
+    info->vm_state_size = vm_state_size;
+    info->vm_clock_nsec = sn->vm_clock_nsec % 1000000000;
+    info->vm_clock_sec = sn->vm_clock_nsec / 1000000000;
+
  the_end:
     if (saved_vm_running)
         vm_start();
+
+    return info;
 }
 
 void qmp_xen_save_devices_state(const char *filename, Error **errp)
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
                   ` (9 preceding siblings ...)
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 10/11] qapi: Convert savevm Pavel Hrdina
@ 2013-04-16 16:05 ` Pavel Hrdina
  2013-04-17  2:53   ` Wenchao Xia
  2013-04-16 16:33 ` [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Eric Blake
  11 siblings, 1 reply; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-16 16:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: phrdina, armbru, lcapitulino


Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
 savevm.c | 33 +++++++++++----------------------
 1 file changed, 11 insertions(+), 22 deletions(-)

diff --git a/savevm.c b/savevm.c
index 66753da..bc829a5 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2195,7 +2195,7 @@ out:
 }
 
 static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
-                              const char *name, const char *id, bool old_match)
+                              const char *name, const char *id)
 {
     QEMUSnapshotInfo *sn_tab, *sn;
     int nb_sns, i, found = 0;
@@ -2218,20 +2218,10 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
                 break;
             }
         } else if (name) {
-            /* for compatibility for old bdrv_snapshot_find call
-             * will be removed */
-            if (old_match) {
-                if (!strcmp(sn->id_str, id) || !strcmp(sn->name, name)) {
-                    *sn_info = *sn;
-                    found = 1;
-                    break;
-                }
-            } else {
-                if (!strcmp(sn->name, name)) {
-                    *sn_info = *sn;
-                    found = 1;
-                    break;
-                }
+            if (!strcmp(sn->name, name)) {
+                *sn_info = *sn;
+                found = 1;
+                break;
             }
         } else if (id) {
             if (!strcmp(sn->id_str, id)) {
@@ -2290,7 +2280,7 @@ SnapshotInfo *qmp_vm_snapshot_save(const char *name, Error **errp)
     sn->date_nsec = tv.tv_usec * 1000;
     sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
 
-    if (bdrv_snapshot_find(bs, old_sn, name, NULL, false)) {
+    if (bdrv_snapshot_find(bs, old_sn, name, NULL)) {
         error_setg(errp, "snapshot '%s' exists", name);
         goto the_end;
     } else {
@@ -2388,7 +2378,7 @@ SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
     }
 
     /* Don't even try to load empty VM states */
-    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id, false)) {
+    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id)) {
         return NULL;
     }
 
@@ -2413,7 +2403,7 @@ SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
             return NULL;
         }
 
-        if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
+        if (!bdrv_snapshot_find(bs, &sn, name, id)) {
             return NULL;
         }
     }
@@ -2484,7 +2474,7 @@ SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
         return NULL;
     }
 
-    if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
+    if (!bdrv_snapshot_find(bs, &sn, name, id)) {
         /* no need to set an error if snapshot doesn't exist */
         return NULL;
     }
@@ -2501,7 +2491,7 @@ SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
     bs = NULL;
     while ((bs = bdrv_next(bs))) {
         if (bdrv_can_snapshot(bs)
-                && bdrv_snapshot_find(bs, &sn, name, id, false)) {
+                && bdrv_snapshot_find(bs, &sn, name, id)) {
             bdrv_snapshot_delete(bs, sn.name, errp);
             if (error_is_set(errp)) {
                 return NULL;
@@ -2549,8 +2539,7 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
 
         while ((bs1 = bdrv_next(bs1))) {
             if (bdrv_can_snapshot(bs1) && bs1 != bs) {
-                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str,
-                                        true)) {
+                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str)) {
                     available = 0;
                     break;
                 }
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi
  2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
                   ` (10 preceding siblings ...)
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find() Pavel Hrdina
@ 2013-04-16 16:33 ` Eric Blake
  11 siblings, 0 replies; 48+ messages in thread
From: Eric Blake @ 2013-04-16 16:33 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 4814 bytes --]

On 04/16/2013 10:05 AM, Pavel Hrdina wrote:

s/covert/convert/ in the subject, if you send a v2 (but doesn't affect
git, so depending on how review goes, you may get lucky :)

> I'm sending patches for all commands in one patch series because the
> savevm command depends on delvm command.
> 
> This patch series introduces new design of these commands:
> 
> * QMP vm-snapshot-save:
>     - { 'command': 'vm-snapshot-save',
>         'data': { 'name': 'str' },
>         'returns': 'SnapshotInfo' }
>     - vm-snapshot-save returns an error if there is an existing snapshot with
>       the same name
>     - you cannot provide an id for a new snapshot
>     - all information about created snapshot will be returned

Looks good.

> 
> * QMP vm-snapshot-load
>     - { 'command': 'vm-snapshot-load',
>         'data': { '*name': 'str', '*id': 'str' },
>         'returns': 'SnapshotInfo' }
>     - one of the name or id must be provided
>     - if both are provided they will match only the snapshot with the same name
>       and id
>     - returns SnapshotInfo only if the snapshot exists.

A return value is not strictly necessary, if we guarantee an error on
all cases where nothing was loaded.  On the other hand, by returning a
value, the caller can learn which 'name' or 'id' was populated if the
user omitted an input parameter, in case the caller plans to do some
sanity checking on what actually got loaded.  I don't care either way
(libvirt will just be looking for non-error return, rather than parsing
the return value).

> 
> * QMP vm-snapshot-delete:
>     - { 'command': 'vm-snapshot-delete',
>         'data': { '*name': 'str', '*id': 'str' },
>         'returns': 'SnapshotInfo' }
>     - same rules as vm-snapshot-load

Same comment about 'returns':{} being sufficient (libvirt will just be
looking for non-error return).

> 
> * HMP savevm:
>     - args_type = "force:-f,name:s?",
>     - if the name is not provided the HMP command will generates new one for QMP
>       command
>     - if there is already a snapshot with provided or generated name it will
>       fails
>     - there will be an optional -f parameter to force saving requested snapshot
>       and it will internally use vm-snapshot-delete and then vm-snapshot-save
>     - all information about created snapshot will be printed

Looks good.

> 
> * HMP loadvm:
>     - args_type = "id:-i,name:s",
>     - follow the same behavior as the QMP command

Not quite.  You are only providing one name, so what you are really
doing is: if -i is present, supply that name as the QMP id argument.  If
-i is not present, first try the name as the QMP name argument, and on
failure try again with the same name as the QMP id argument.

>     - it load snapshot that match the provided name
>     - if an id flag is provided, it load snapshot that match the name parameter
>       as an id of snapshot

The args_type looks reasonable.

> 
> * HMP delvm:
>     - args_type = "id:-i,name:s"
>     - same rules as loadvm

Again, looks reasonable.

> 
> Pavel Hrdina (11):
>   qemu-img: introduce qemu_img_handle_error()
>   block: update error reporting for bdrv_snapshot_delete() and related
>     functions
>   savevm: update bdrv_snapshot_find() to find snapshot by id or name
>   qapi: Convert delvm
>   block: update error reporting for bdrv_snapshot_goto() and related
>     functions
>   savevm: update error reporting for qemu_loadvm_state()
>   qapi: Convert loadvm
>   block: update error reporting for bdrv_snapshot_create() and related
>     functions
>   savevm: update error reporting off qemu_savevm_state() and related
>     functions
>   qapi: Convert savevm
>   savevm: remove backward compatibility from bdrv_snapshot_find()
> 
>  block.c                   | 100 +++++++------
>  block/qcow2-snapshot.c    |  71 ++++++---
>  block/qcow2.h             |  16 +-
>  block/rbd.c               |  50 ++++---
>  block/sheepdog.c          |  61 ++++----
>  hmp-commands.hx           |  48 +++---
>  hmp.c                     | 119 +++++++++++++++
>  hmp.h                     |   3 +
>  include/block/block.h     |  17 ++-
>  include/block/block_int.h |  17 ++-
>  include/sysemu/sysemu.h   |  12 +-
>  migration.c               |  15 +-
>  monitor.c                 |  12 --
>  qapi-schema.json          |  54 +++++++
>  qemu-img.c                |  54 ++++---
>  qmp-commands.hx           | 127 +++++++++++++++-
>  savevm.c                  | 363 +++++++++++++++++++++++++---------------------
>  vl.c                      |   7 +-
>  18 files changed, 782 insertions(+), 364 deletions(-)
> 

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error()
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error() Pavel Hrdina
@ 2013-04-16 16:46   ` Eric Blake
  2013-04-18 11:44   ` Kevin Wolf
  1 sibling, 0 replies; 48+ messages in thread
From: Eric Blake @ 2013-04-16 16:46 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 497 bytes --]

On 04/16/2013 10:05 AM, Pavel Hrdina wrote:
> Later in the patch series we will use this function few times.

s/few/a few/

> This will avoid of duplicating the code.

s/of//

> 
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  qemu-img.c | 17 +++++++++++------
>  1 file changed, 11 insertions(+), 6 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 02/11] block: update error reporting for bdrv_snapshot_delete() and related functions
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 02/11] block: update error reporting for bdrv_snapshot_delete() and related functions Pavel Hrdina
@ 2013-04-16 17:14   ` Eric Blake
  2013-04-18 12:55   ` Kevin Wolf
  1 sibling, 0 replies; 48+ messages in thread
From: Eric Blake @ 2013-04-16 17:14 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 2334 bytes --]

On 04/16/2013 10:05 AM, Pavel Hrdina wrote:
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  block.c                   | 22 ++++++++++++++--------
>  block/qcow2-snapshot.c    | 21 +++++++++++++++------
>  block/qcow2.h             |  4 +++-
>  block/rbd.c               | 11 ++++++++---
>  block/sheepdog.c          |  6 ++++--
>  include/block/block.h     |  4 +++-
>  include/block/block_int.h |  4 +++-
>  qemu-img.c                |  9 ++++-----
>  savevm.c                  | 26 ++++++++++----------------
>  9 files changed, 64 insertions(+), 43 deletions(-)
> 

> @@ -539,7 +541,9 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
>      /* Search the snapshot */
>      snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
>      if (snapshot_index < 0) {
> -        return -ENOENT;
> +        error_setg(errp, "qcow2: failed to find snapshot '%s' by id or name",
> +                   snapshot_id);
> +        return;

I haven't looked if you changed this later in the series to have
find_snapshot_by_id_or_name take an errp parameter, at which point you
could refactor the error reporting to that point in the stack.  That
might be a nice followup, but this patch is okay as-is.

> +++ b/block/sheepdog.c
> @@ -1908,10 +1908,12 @@ out:
>      return ret;
>  }
>  
> -static int sd_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
> +static void sd_snapshot_delete(BlockDriverState *bs,
> +                               const char *snapshot_id,
> +                               Error **errp)
>  {
>      /* FIXME: Delete specified snapshot id.  */
> -    return 0;
> +    return;

No semantic change; but a trailing return; in a void function is not
necessary, and an empty body would suffice.  On the other hand, claiming
success when we didn't delete anything feels wrong.  Should we change
this function to call error_setg() and warn the user that deletion is
not supported at this time?  If so, that's probably better done as a
separate commit.

As my findings are best addressed in other patches, I'm okay with this
patch as-is, and you can use:

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 03/11] savevm: update bdrv_snapshot_find() to find snapshot by id or name
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 03/11] savevm: update bdrv_snapshot_find() to find snapshot by id or name Pavel Hrdina
@ 2013-04-16 17:34   ` Eric Blake
  2013-04-18 13:17   ` Kevin Wolf
  1 sibling, 0 replies; 48+ messages in thread
From: Eric Blake @ 2013-04-16 17:34 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 5890 bytes --]

On 04/16/2013 10:05 AM, Pavel Hrdina wrote:
> Finding snapshot by a name which could also be an id isn't best way
> how to do it. There will be rewrite of savevm, loadvm and delvm to
> improve the behavior of these commands. The savevm and loadvm will
> have their own patch series.
> 
> Now bdrv_snapshot_find takes more parameters. The name parameter will
> be matched only against the name of the snapshot and the same applies
> to id parameter.
> 
> There is one exception. If you set the last parameter, the name parameter
> will be matched against the name or the id of a snapshot. This exception
> is only for backward compatibility for other commands and it will be
> dropped after all commands will be rewritten.

Fair enough, even if it is a bit of churn on the signature and callers.

> 
> We only need to know if that snapshot exists or not. We don't care
> about any error message. If snapshot exists it returns 1 otherwise
> it returns 0.

If you are only returning a yes/no result, bool is better than int.

> 
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  savevm.c | 73 ++++++++++++++++++++++++++++++++++++++++++++--------------------
>  1 file changed, 50 insertions(+), 23 deletions(-)
> 
> diff --git a/savevm.c b/savevm.c
> index 6af84fd..96a2340 100644
> --- a/savevm.c
> +++ b/savevm.c
> @@ -2197,25 +2197,55 @@ out:
>  }
>  
>  static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,

Return bool...

> -                              const char *name)
> +                              const char *name, const char *id, bool old_match)
>  {
>      QEMUSnapshotInfo *sn_tab, *sn;
> -    int nb_sns, i, ret;
> +    int nb_sns, i, found = 0;

... and initialize 'bool found = false'.

> +
> +    if (!name && !id) {
> +        return found;
> +    }

It may be appropriate to do assert(name || id), if you want to guarantee
that all callers supply at least one of the two arguments (and that the
QMP code where both arguments are optional does its own sanity checking
that the user supplied an argument.

>  
> -    ret = -ENOENT;
>      nb_sns = bdrv_snapshot_list(bs, &sn_tab);
> -    if (nb_sns < 0)
> -        return ret;
> +    if (nb_sns < 0) {
> +        return found;

Calling the return value 'found' makes the code read awkwardly when
reporting failure; maybe keeping it named 'ret' is better after all.

> +    }
> +
>      for(i = 0; i < nb_sns; i++) {

As long as you are touching this code, you could insert the space after
'for'.

>          sn = &sn_tab[i];
> -        if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
> -            *sn_info = *sn;
> -            ret = 0;
> -            break;
> +        if (name && id) {
> +            if (!strcmp(sn->id_str, id) && !strcmp(sn->name, name)) {
> +                *sn_info = *sn;
> +                found = 1;
> +                break;
> +            }
> +        } else if (name) {
> +            /* for compatibility for old bdrv_snapshot_find call
> +             * will be removed */
> +            if (old_match) {
> +                if (!strcmp(sn->id_str, id) || !strcmp(sn->name, name)) {
> +                    *sn_info = *sn;
> +                    found = 1;
> +                    break;
> +                }
> +            } else {
> +                if (!strcmp(sn->name, name)) {
> +                    *sn_info = *sn;
> +                    found = 1;
> +                    break;
> +                }
> +            }
> +        } else if (id) {
> +            if (!strcmp(sn->id_str, id)) {
> +                *sn_info = *sn;
> +                found = 1;
> +                break;
> +            }

Note that this says that if both name and id are specified, then that
takes priority, no matter what was specified for old_match.

>          }
>      }
> +
>      g_free(sn_tab);
> -    return ret;
> +    return found;
>  }
>  
>  /*
> @@ -2229,8 +2259,8 @@ static int del_existing_snapshots(Monitor *mon, const char *name)
>  
>      bs = NULL;
>      while ((bs = bdrv_next(bs))) {
> -        if (bdrv_can_snapshot(bs) &&
> -            bdrv_snapshot_find(bs, snapshot, name) >= 0)
> +        if (bdrv_can_snapshot(bs)
> +                && bdrv_snapshot_find(bs, snapshot, name, name, true))

Needless style change.  The old style was sufficient, with:

    if (bdrv_can_snapshot(bs) &&
        bdrv_snapshot_find(bs, snapshot, name, name, true))

Except that bdrv_snapshot_find(bs, snapshot, name, name, anything)
results in a lookup that requires sn->id_str and sn->name be the same
string, which is not what you intended.

You really want to be using bdrv_snapshot_find(bs, snapshot, NULL, name,
true), if you want the old_match parameter to make a difference.

...
> @@ -2474,7 +2501,7 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
>  {
>      BlockDriverState *bs, *bs1;
>      QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s;
> -    int nb_sns, i, ret, available;
> +    int nb_sns, i, available;
>      int total;
>      int *available_snapshots;
>      char buf[256];
> @@ -2505,8 +2532,8 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
>  
>          while ((bs1 = bdrv_next(bs1))) {
>              if (bdrv_can_snapshot(bs1) && bs1 != bs) {
> -                ret = bdrv_snapshot_find(bs1, sn_info, sn->id_str);
> -                if (ret < 0) {
> +                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str,
> +                                        true)) {

This was the only conversion that passed both id and name that looked
correct.  All the other conversions to 'name, name, true' need fixing.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 04/11] qapi: Convert delvm
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 04/11] qapi: Convert delvm Pavel Hrdina
@ 2013-04-16 19:39   ` Eric Blake
  2013-04-18 13:28   ` Kevin Wolf
  1 sibling, 0 replies; 48+ messages in thread
From: Eric Blake @ 2013-04-16 19:39 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 12724 bytes --]

On 04/16/2013 10:05 AM, Pavel Hrdina wrote:
> QMP command vm-snapshot-delete no takes two parameters name and id. They are

s/no//
s/parameters/parameters:/

> optional, but one of the name or id must be provided. If both are provided they
> will match only the snapshot with the same name and id. The command returns
> SnapshotInfo only if the snapshot exists, if snapshot doesn't exist it returns
> nothing. If something goes wrong, it returns an error message.

I would prefer returning an error message if the snapshot doesn't exist.
 The QMP code generator is not set up for a top-level optional return.
I guess I'll see what you implemented below...

> 
> HMP command delvm now uses the new vm-snapshot-delete, but behave slightly
> different. The delvm takes one optional flag -i and one parameter name. If you
> provide only the name parameter, it will match only snapshots with that name.
> If you also provide the flag, it will match only snapshots with name as id.
> Information about successfully deleted snapshot will be printed, if there is no
> snapshot with that name or id, the appropriate message will be printed. If
> something goes wrong, an error message will be printed.
> 
> These improves behavior of the command to be more strict on selecting snapshots
> because actual behavior is wrong. Now if you want to delete snapshot with name '2'
> but there is no snapshot with that name it could delete snapshot with id '2' and
> that isn't what you want.

If I understand correctly, your goal is that 'delvm 2' will never delete
id '2' after this patch (unless id '2' happened to also be tag '2'); to
get the old behavior of being able to delete the (possibly anonymous) id
2, you have to use 'delvm -i 2'.

Yes, I can live with this explicit change in semantics.

> 
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  hmp-commands.hx         | 14 ++++++++------
>  hmp.c                   | 35 ++++++++++++++++++++++++++++++++++
>  hmp.h                   |  1 +
>  include/sysemu/sysemu.h |  1 -
>  qapi-schema.json        | 17 +++++++++++++++++
>  qmp-commands.hx         | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  savevm.c                | 49 +++++++++++++++++++++++++++++++++++-------------
>  7 files changed, 146 insertions(+), 21 deletions(-)
> 
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index df44906..d1701ce 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -339,16 +339,18 @@ ETEXI
>  
>      {
>          .name       = "delvm",
> -        .args_type  = "name:s",
> -        .params     = "tag|id",
> -        .help       = "delete a VM snapshot from its tag or id",
> -        .mhandler.cmd = do_delvm,
> +        .args_type  = "id:-i,name:s",
> +        .params     = "[-i] tag|[id]",

The 'tag|[id]' looks odd.  Would it be any better written as merely:
 [-i] name

> +        .help       = "delete a VM snapshot from its tag or id if -i flag is provided",

Maybe:
 delete a VM snapshot by tag name, or with -i by its id
but I'm not sure if my attempt was any better.

> +        .mhandler.cmd = hmp_vm_snapshot_delete,
>      },
>  
>  STEXI
> -@item delvm @var{tag}|@var{id}
> +@item delvm [-i] @var{tag}|[@var{id}]

This line should match whatever .params string we settle on above.

>  @findex delvm
> -Delete the snapshot identified by @var{tag} or @var{id}.
> +Delete a snapshot identified by @var{tag}. If flag -i is provided, delete
> +a snapshot indentified by @var{id}.

s/indentified/identified/

> +
>  ETEXI
>  
>      {
> diff --git a/hmp.c b/hmp.c
> index 4fb76ec..2c754b3 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -1425,3 +1425,38 @@ void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
>      qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err);
>      hmp_handle_error(mon, &local_err);
>  }
> +
> +void hmp_vm_snapshot_delete(Monitor *mon, const QDict *qdict)
> +{
> +    const char *name = qdict_get_try_str(qdict, "name");
> +    const bool id = qdict_get_try_bool(qdict, "id", false);
> +    Error *local_err = NULL;
> +    SnapshotInfo *info;
> +
> +    if (id) {
> +        info = qmp_vm_snapshot_delete(false, NULL, true, name, &local_err);
> +    } else {
> +        info = qmp_vm_snapshot_delete(true, name, false, NULL, &local_err);
> +    }
> +
> +    if (info) {
> +        char buf[256];
> +        QEMUSnapshotInfo sn = {
> +            .vm_state_size = info->vm_state_size,
> +            .date_sec = info->date_sec,
> +            .date_nsec = info->date_nsec,
> +            .vm_clock_nsec = info->vm_clock_sec * 1000000000 +
> +                             info->vm_clock_nsec,
> +        };
> +        pstrcpy(sn.id_str, sizeof(sn.id_str), info->id);
> +        pstrcpy(sn.name, sizeof(sn.name), info->name);
> +        monitor_printf(mon, "Deleted snapshot info:\n");
> +        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
> +        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), &sn));

I like the idea of printing details about what just got deleted.

> +    } else if (!error_is_set(&local_err)) {

If info is NULL, but error_is_set returns false, we have a problem.
This code should not be reachable, since QMP doesn't have a way to
return optional information.  That is, QMP should have already reported
a lookup error into local_err, and it should be sufficient to do:

if (info) {
...
} else {
    monitor_printf(mon, "%s\n", error_get_pretty(local_err));
    error_free(local_err);
}

> +        monitor_printf(mon, "Snapshot '%s' not found.\n", name);
> +    }

Hmm.  If I have:

id 1 name 2
id 2 name 3
id 4 no name

Existing behavior says 'delvm 1' deletes 'id 1 name 2'; 'delvm 2' is
ambiguous whether it deletes 'id 1 name 2' or 'id 2 name 3' (and if I
recall correctly, the behavior was different between qemu-img vs. HMP),
and 'delvm 4' is the only way to delete the no-name snapshot 'id 4'.

Your approach says 'delvm 1' is an error, 'delvm 2' deletes 'id 1 name
2', and 'delvm -i 2' deletes 'id 2 name 3'; and the only way to delete
the no-name snapshot is to use 'delvm -i 4'.

My idea of trying id as a fallback if name lookup fails would mean
'delvm 1' deletes 'id 1 name 2', 'delvm 2' deletes 'id 1 name 2', and
'delvm -i 2' deletes 'id 2 name 3'; and that deleting the no-name
snapshot can be done with the simpler 'delvm 4'.

I guess either approach works, as long as we document it.  My comments
on 0/11 about having a fallback to id when name lookup fails may not be
necessary after all, if we go with your approach.  My approach is more
like existing code, in that it is possible to delete no-name snapshots
without having to pass any extra options; but your way is a bit nicer in
that deleting by id is generally not what you want to do without being
explicit.

Anyone else have an opinion on which semantic we should use if name
lookup fails but -i was not specified?

> +++ b/qapi-schema.json
> @@ -3505,3 +3505,20 @@
>      '*asl_compiler_rev':  'uint32',
>      '*file':              'str',
>      '*data':              'str' }}
> +
> +##
> +# @vm-snapshot-delete:
> +#
> +# Delete a snapshot identified by name or id or both. One of the name or id
> +# is required. It will returns SnapshotInfo of successfully deleted snapshot.
> +#
> +# @name: tag of an existing snapshot
> +#
> +# @id: id of an existing snapshot

Mark these with #optional.

> +#
> +# Returns: SnapshotInfo on success

This implies that failure to find a matching consistent snapshot to
delete must be a failure (since there is no way to mark an optional return).

> +#
> +# Since: 1.5
> +##
> +{ 'command': 'vm-snapshot-delete', 'data': {'*name': 'str', '*id': 'str'},
> +  'returns': 'SnapshotInfo' }

Or, if you really want to make an optional return, the current
convention is that you have to wrap it in a type that has an optional
member.  Something like

{ 'type': 'SnapshotReturn', 'data': { '*snapshot' : 'SnapshotInfo' } }
{ 'command': 'vm-snapshot-delte',
  'data': { '*name': 'str', '*id': 'str' },
  'returns': 'SnapshotReturn' }

where the result of a successful delete would be:

{ 'snapshot' : { 'name':'...', ... } }

and the result of a failed lookup but non-error (that sounds weird, just
typing it) would be:

{ }

See ChardevReturn/chardev-add for an example of optional return value;
but for that function, an optional return really made sense.  But if you
agree that an optional return doesn't make sense here, and that we only
succeed if we return something, then you get the nicer:

{ 'name':'...', ... }

with no extra layer to unwrap as your return value.

Oh, that points out another thing - since the qcow2 file supports
snapshots with no tag, you probably need a (separate) patch to
qapi-schema.json to change type SnapshotInfo to have '*name', with a
note that name is absent on anonymous snapshots (but that it will be
present on any snapshot created via QMP).

> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index 4d65422..86f399d 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -1419,7 +1419,55 @@ Example:
>  
>  -> { "execute": "add_client", "arguments": { "protocol": "vnc",
>                                               "fdname": "myclient" } }
> -<- { "return": {} }
> +<- {
> +      "return": {
> +         "id": "1",
> +         "name": "my_snapshot",
> +         "date-sec": 1364480534,
> +         "date-nsec": 978215000,
> +         "vm-clock-sec": 5,
> +         "vm-clock-nsec": 153620449,
> +        "vm-state-size": 5709953
> +      }
> +   }

Huh?  Why are you munging the 'add_client' example?

> +++ b/savevm.c

>  
> -    bs1 = NULL;
> -    while ((bs1 = bdrv_next(bs1))) {
> -        if (bdrv_can_snapshot(bs1)) {
> -            bdrv_snapshot_delete(bs1, name, &local_err);
> -            if (error_is_set(&local_err)) {
> -                monitor_printf(mon, "%s\n", error_get_pretty(local_err));
> -                error_free(local_err);
> +    if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
> +        /* no need to set an error if snapshot doesn't exist */
> +        return NULL;

Won't work.  My understanding is that you cannot return NULL without
setting an error.  While it may do what you want for HMP, it doesn't
jive with the way that QMP works, which is that a NULL return means that
it will assume the error is set, and try to deference it to build up the
error return, since QMP must always return something.  If you are going
to succeed with no data, you still have to return {}.

Maybe I'm not familiar enough with QMP, and you can get away with this
after all.  On the other hand, I'd much rather have error reporting here
anyways, since libvirt will be using QMP, and hiding the error to only
occur in HMP means that libvirt, and any other QMP client, would have to
reinvent the error reporting themselves, if they get an empty return.

> +    }
> +
> +    info = g_malloc0(sizeof(SnapshotInfo));
> +    info->id = g_strdup(sn.id_str);
> +    info->name = g_strdup(sn.name);
> +    info->date_nsec = sn.date_nsec;
> +    info->date_sec = sn.date_sec;
> +    info->vm_state_size = sn.vm_state_size;
> +    info->vm_clock_nsec = sn.vm_clock_nsec % 1000000000;
> +    info->vm_clock_sec = sn.vm_clock_nsec / 1000000000;
> +
> +    bs = NULL;
> +    while ((bs = bdrv_next(bs))) {
> +        if (bdrv_can_snapshot(bs)
> +                && bdrv_snapshot_find(bs, &sn, name, id, false)) {

Style - most of qemu puts && at the end of one line break, and starts
the next line flush with the first character after ( of the line above,
as in:

    if (bdrv_can_snapshot(bs) &&
        bdrv_snapshot_find(bs...)) {

> +            bdrv_snapshot_delete(bs, sn.name, errp);
> +            if (error_is_set(errp)) {
> +                return NULL;
>              }

Yuck - this means that a failure to delete partway through leaks info,
as well as leaving a partial snapshot in the remaining files not
visited.  Fix the memory leak no matter what.  And maybe we should
reconsider what happens if we have a partial failure during delete - is
it best to plow on as far as possible?  How should we indicate it back
to the caller that we found the snapshot they requested, but didn't
finish deleting it?

>          }
>      }
> +
> +    return info;
>  }
>  
>  void do_info_snapshots(Monitor *mon, const QDict *qdict)
> 

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 05/11] block: update error reporting for bdrv_snapshot_goto() and related functions
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 05/11] block: update error reporting for bdrv_snapshot_goto() and related functions Pavel Hrdina
@ 2013-04-16 20:48   ` Eric Blake
  2013-04-23 14:08   ` Kevin Wolf
  1 sibling, 0 replies; 48+ messages in thread
From: Eric Blake @ 2013-04-16 20:48 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 7939 bytes --]

On 04/16/2013 10:05 AM, Pavel Hrdina wrote:
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  block.c                   | 55 ++++++++++++++++++++++++++---------------------
>  block/qcow2-snapshot.c    | 32 +++++++++++++++++++--------
>  block/qcow2.h             |  8 +++++--
>  block/rbd.c               | 19 +++++++++++-----
>  block/sheepdog.c          | 33 ++++++++++++++++------------
>  include/block/block.h     |  8 ++++---
>  include/block/block_int.h |  8 ++++---
>  qemu-img.c                | 20 ++++++++++-------
>  savevm.c                  | 21 ++++++++++--------
>  9 files changed, 127 insertions(+), 77 deletions(-)
> 

> +    } else if (bs->file) {
>          drv->bdrv_close(bs);
> -        ret = bdrv_snapshot_goto(bs->file, snapshot_id);
> -        open_ret = drv->bdrv_open(bs, NULL, bs->open_flags);
> -        if (open_ret < 0) {
> +        bdrv_snapshot_goto(bs->file, snapshot_id, errp);
> +        ret = drv->bdrv_open(bs, NULL, bs->open_flags);
> +        if (ret < 0) {
>              bdrv_delete(bs->file);
>              bs->drv = NULL;
> -            return open_ret;
> +            error_setg(errp, "failed to open '%s'", bdrv_get_device_name(bs));

Do we still want to try bdrv_open() if bdrv_snapshot_goto() set errp?
For that matter, if bdrv_snapshot_goto() _did_ set errp, does
error_setg() allow you to overwrite errors, or are you violating
constraints?

This is another case of partial failure; I'm wondering if we need to
eventually tidy this code up to use transaction semantics, so that a
loadvm is all-or-none, rather than risking partial failure.

> @@ -3410,16 +3410,23 @@ void bdrv_snapshot_delete(BlockDriverState *bs,
>  }
>  
>  int bdrv_snapshot_list(BlockDriverState *bs,
> -                       QEMUSnapshotInfo **psn_info)
> +                       QEMUSnapshotInfo **psn_info,
> +                       Error **errp)
>  {
>      BlockDriver *drv = bs->drv;
> -    if (!drv)
> -        return -ENOMEDIUM;
> -    if (drv->bdrv_snapshot_list)
> -        return drv->bdrv_snapshot_list(bs, psn_info);
> -    if (bs->file)
> -        return bdrv_snapshot_list(bs->file, psn_info);
> -    return -ENOTSUP;
> +
> +    if (!drv) {
> +        error_setg(errp, "device '%s' has no medium", bdrv_get_device_name(bs));
> +        return 0;
> +    } else if (drv->bdrv_snapshot_list) {
> +        return drv->bdrv_snapshot_list(bs, psn_info, errp);
> +    } else if (bs->file) {
> +        return bdrv_snapshot_list(bs->file, psn_info, errp);
> +    } else {
> +        error_setg(errp, "snapshots are not supported on device '%s'",
> +                   bdrv_get_device_name(bs));
> +        return 0;

Why 0 for error?  Don't you want to reserve 0 for 'snapshots are
supported, but none exist', and use -1 for error instead?  Or are we
safe treating no medium and no support in the same was as supported but
the list is 0-length?

> @@ -447,6 +450,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
>       */
>      ret = qcow2_grow_l1_table(bs, sn->l1_size, true);
>      if (ret < 0) {
> +        error_setg_errno(errp, -ret, "fqcow2: ailed to grow L1 table");

s/ailed/failed/

> @@ -595,7 +606,9 @@ void qcow2_snapshot_delete(BlockDriverState *bs,
>  #endif
>  }
>  
> -int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
> +int qcow2_snapshot_list(BlockDriverState *bs,
> +                        QEMUSnapshotInfo **psn_tab,
> +                        Error **errp)
>  {
>      BDRVQcowState *s = bs->opaque;
>      QEMUSnapshotInfo *sn_tab, *sn_info;
> @@ -604,7 +617,8 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
>  
>      if (!s->nb_snapshots) {
>          *psn_tab = NULL;
> -        return s->nb_snapshots;
> +        error_setg(errp, "qcow2: there is no snapshot available");
> +        return 0;

Note that inside the 'if' block, s->nb_snapshots == 0, so there is no
change in the return value, but now you are declaring this an error
where it previously just left a NULL *psn_tab.  Does the caller care?

> @@ -913,7 +917,12 @@ static int qemu_rbd_snap_list(BlockDriverState *bs,
>          }
>      } while (snap_count == -ERANGE);
>  
> -    if (snap_count <= 0) {
> +    if (snap_count < 0) {
> +        error_setg_errno(errp, -snap_count, "rbd: failed to find snapshots");
> +        snap_count = 0;

This is changing the return value from negative to 0.  Does the caller care?

> +static int sd_snapshot_list(BlockDriverState *bs,
> +                            QEMUSnapshotInfo **psn_tab,
> +                            Error **errp)
>  {
>      BDRVSheepdogState *s = bs->opaque;
>      SheepdogReq req;
> -    int fd, nr = 1024, ret, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long);
> +    int fd, nr = 1024, ret = 0, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long);
>      QEMUSnapshotInfo *sn_tab = NULL;
>      unsigned wlen, rlen;
>      int found = 0;
> @@ -1934,7 +1937,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
>  
>      fd = connect_to_sdog(s);
>      if (fd < 0) {
> -        ret = fd;
> +        error_setg_errno(errp, -fd, "sd: failed to connect to sdog");
>          goto out;

Another case of changing the result from -1 to 0; does the caller care?

> @@ -2001,7 +2005,8 @@ out:
>      g_free(vdi_inuse);
>  
>      if (ret < 0) {
> -        return ret;
> +        error_setg_errno(errp, -ret, "sd: failed to read VDI object");
> +        return 0;

and again, in the same function.

> +++ b/include/block/block_int.h
> @@ -155,13 +155,15 @@ struct BlockDriver {
>  
>      int (*bdrv_snapshot_create)(BlockDriverState *bs,
>                                  QEMUSnapshotInfo *sn_info);
> -    int (*bdrv_snapshot_goto)(BlockDriverState *bs,
> -                              const char *snapshot_id);
> +    void (*bdrv_snapshot_goto)(BlockDriverState *bs,
> +                               const char *snapshot_id,
> +                               Error **errp);

It would be really nice if we documented the contracts of all these
callback functions.

> +++ b/qemu-img.c
> @@ -1563,10 +1563,13 @@ static void dump_snapshots(BlockDriverState *bs)
>      QEMUSnapshotInfo *sn_tab, *sn;
>      int nb_sns, i;
>      char buf[256];
> +    Error *local_err = NULL;
>  
> -    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
> -    if (nb_sns <= 0)
> +    nb_sns = bdrv_snapshot_list(bs, &sn_tab, &local_err);
> +    if (qemu_img_handle_error("qemu-img dump snapshots failed", local_err)
> +            || nb_sns == 0) {

Interesting - you are stating that if no error was reported in
local_err, then a return of 0 short-circuits.  I was asking about all
the places where you changed return semantics; if this is the only
caller, then when local_err is set you ignore nb_sns and therefore the
return value is irrelevant (and changing from -1 to 0 makes no
difference to this code doing a short-circuit).  But again, calling that
out as a contract, where we can verify that each implementation of the
callback function obeys the contract, would make me feel a bit better.

> +++ b/savevm.c
> @@ -2206,7 +2206,7 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
>          return found;
>      }
>  
> -    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
> +    nb_sns = bdrv_snapshot_list(bs, &sn_tab, NULL);
>      if (nb_sns < 0) {
>          return found;

Oops.  qemu-img wasn't the only caller.  Here, changing -1 to 0 on error
return means we fall through instead of returning 0 early.  Did you mean
for that to happen?  Calling with NULL says you don't care about error
reporting - is that right?

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 06/11] savevm: update error reporting for qemu_loadvm_state()
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 06/11] savevm: update error reporting for qemu_loadvm_state() Pavel Hrdina
@ 2013-04-16 21:42   ` Eric Blake
  0 siblings, 0 replies; 48+ messages in thread
From: Eric Blake @ 2013-04-16 21:42 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 1739 bytes --]

On 04/16/2013 10:05 AM, Pavel Hrdina wrote:
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  include/sysemu/sysemu.h |  2 +-
>  migration.c             |  9 +++----
>  savevm.c                | 64 ++++++++++++++++++++++++-------------------------
>  3 files changed, 37 insertions(+), 38 deletions(-)
> 

> +++ b/migration.c
> @@ -93,12 +93,13 @@ void qemu_start_incoming_migration(const char *uri, Error **errp)
>  static void process_incoming_migration_co(void *opaque)
>  {
>      QEMUFile *f = opaque;
> -    int ret;
> +    Error *local_err = NULL;
>  
> -    ret = qemu_loadvm_state(f);
> +    qemu_loadvm_state(f, &local_err);
>      qemu_fclose(f);
> -    if (ret < 0) {
> -        fprintf(stderr, "load of migration failed\n");
> +    if (error_is_set(&local_err)) {
> +        fprintf(stderr, "%s\n", error_get_pretty(local_err));
> +        error_free(local_err);
>          exit(0);

Pre-existing, but WHY are we exiting with successful status even when
incoming migration failed?  This feels SOOOO wrong.  Exiting non-zero
would at least give management apps like libvirt a reason to inspect the
output for the error message.

>      v = qemu_get_be32(f);
>      if (v == QEMU_VM_FILE_VERSION_COMPAT) {
> -        fprintf(stderr, "SaveVM v2 format is obsolete and don't work anymore\n");
> -        return -ENOTSUP;
> +        error_setg(errp, "saveVM v2 format is obsolete and don't work anymore");

As long as you are touching this, fix the grammar:

s/don't/doesn't/

As my findings were pre-existing problems:

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 07/11] qapi: Convert loadvm
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 07/11] qapi: Convert loadvm Pavel Hrdina
@ 2013-04-16 23:43   ` Eric Blake
  2013-04-18 10:34     ` Pavel Hrdina
  0 siblings, 1 reply; 48+ messages in thread
From: Eric Blake @ 2013-04-16 23:43 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: Wenchao Xia, lcapitulino, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 9203 bytes --]

On 04/16/2013 10:05 AM, Pavel Hrdina wrote:
> QMP command vm-snapshot-load and HMP command loadvm behave similar to
> vm-snapshot-delete and delvm. The only different is that they will load
> the snapshot instead of deleting it.
> 
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  hmp-commands.hx         | 16 +++++-----
>  hmp.c                   | 35 ++++++++++++++++++++++
>  hmp.h                   |  1 +
>  include/sysemu/sysemu.h |  1 -
>  monitor.c               | 12 --------
>  qapi-schema.json        | 18 +++++++++++
>  qmp-commands.hx         | 38 ++++++++++++++++++++++++
>  savevm.c                | 79 ++++++++++++++++++++++++++++++-------------------
>  vl.c                    |  7 ++++-
>  9 files changed, 156 insertions(+), 51 deletions(-)
> 
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index d1701ce..e80410b 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -324,17 +324,19 @@ ETEXI
>  
>      {
>          .name       = "loadvm",
> -        .args_type  = "name:s",
> -        .params     = "tag|id",
> -        .help       = "restore a VM snapshot from its tag or id",
> -        .mhandler.cmd = do_loadvm,
> +        .args_type  = "id:-i,name:s",
> +        .params     = "[-i] tag|[id]",
> +        .help       = "restore a VM snapshot from its tag or id if -i flag is provided",

Same comments as 4/11 about possibilities of making this look nicer
('name' seems nicer than 'tag|[id]').

>  }
> +
> +void hmp_vm_snapshot_load(Monitor *mon, const QDict *qdict)
> +{
> +    const char *name = qdict_get_try_str(qdict, "name");
> +    const bool id = qdict_get_try_bool(qdict, "id", false);
> +    Error *local_err = NULL;
> +    SnapshotInfo *info = NULL;
> +
> +    if (id) {
> +        info = qmp_vm_snapshot_load(false, NULL, true, name, &local_err);
> +    } else {
> +        info = qmp_vm_snapshot_load(true, name, false, NULL, &local_err);
> +    }

Could be written without if/else:
qmp_vm_snapshot_load(id, name, !id, name, &local_err);

but doesn't really bother me as written.

> +
> +    if (info) {
> +        char buf[256];

Fixed-size buffer...

> +        QEMUSnapshotInfo sn = {
> +            .vm_state_size = info->vm_state_size,
> +            .date_sec = info->date_sec,
> +            .date_nsec = info->date_nsec,
> +            .vm_clock_nsec = info->vm_clock_sec * 1000000000 +
> +                             info->vm_clock_nsec,
> +        };
> +        pstrcpy(sn.id_str, sizeof(sn.id_str), info->id);
> +        pstrcpy(sn.name, sizeof(sn.name), info->name);
> +        monitor_printf(mon, "Loaded snapshot's info:\n");
> +        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
> +        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), &sn));

...but potentially large amount of information to be placed in it.  I
would MUCH rather see this code using gstring, or even direct printing.
 I think you need to base this on top of the ideas here:

https://lists.gnu.org/archive/html/qemu-devel/2013-04/msg02540.html

These two series need to be coordinated to minimize churn and rebase
conflicts on cleanups such as removing buffer truncation from
bdrv_snapshot_dump.

Hmm, I probably should have mentioned this on 4/11 as well.

> +    } else if (!error_is_set(&local_err)) {

Same comments as 4/11, in that info == NULL should imply that local_err
is set.

> +++ b/qapi-schema.json
> @@ -3522,3 +3522,21 @@
>  ##
>  { 'command': 'vm-snapshot-delete', 'data': {'*name': 'str', '*id': 'str'},
>    'returns': 'SnapshotInfo' }
> +
> +##
> +# @vm-snapshot-load:
> +#
> +# Set the whole virtual machine to the snapshot identified by the tag
> +# or the unique snapshot id or both. It must be a snapshot of a whole VM and
> +# at least one of the name or id parameter must be specified.
> +#
> +# @name: tag of existing snapshot
> +#
> +# @id: id of existing snapshot

As in 4/11, mark these with #optional.

> +#
> +# Returns: SnapshotInfo on success
> +#
> +# Since: 1.5
> +##
> +{ 'command': 'vm-snapshot-load', 'data': {'*name': 'str', '*id': 'str'},
> +  'returns': 'SnapshotInfo' }

Same comments as 4/11 on return value design decisions.

> @@ -2393,26 +2393,35 @@ void qmp_xen_save_devices_state(const char *filename, Error **errp)
>          vm_start();
>  }
>  
> -int load_vmstate(const char *name)
> +SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
> +                                   bool has_id, const char *id, Error **errp)
>  {
>      BlockDriverState *bs, *bs_vm_state;
>      QEMUSnapshotInfo sn;
>      QEMUFile *f;
> -    Error *local_err;
> +    SnapshotInfo *info = NULL;
> +    int saved_vm_running;

This should be bool.  runstate_is_running() is currently typed as int,
but it defers to runstate_check() which is bool; fixing runstate_is* to
consistently use bool would be worthy of a separate cleanup patch.

> +
> +    if (!has_name && !has_id) {
> +        error_setg(errp, "name or id must be specified");
> +        return NULL;
> +    }
>  
>      bs_vm_state = bdrv_snapshots();
>      if (!bs_vm_state) {
> -        error_report("No block device supports snapshots");
> -        return -ENOTSUP;
> +        error_setg(errp, "no block device supports snapshots");
> +        return NULL;
>      }
>  
>      /* Don't even try to load empty VM states */
> -    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, name, true)) {
> -        return -ENOENT;
> -    } else if (sn.vm_state_size == 0) {
> -        error_report("This is a disk-only snapshot. Revert to it offline "
> -            "using qemu-img.");
> -        return -EINVAL;
> +    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id, false)) {

Oh, I didn't notice this before, but 4/11 has the same issue.  You are
not guaranteed that 'name' and 'id' are initialized correctly unless you
first check 'has_name' and 'has_id'.  And given my suggestion above of
possibly compressing things to:

qmp_vm_snapshot_load(id, name, !id, name, &local_err);

then it REALLY matters that you pass NULL for the parameters that are
not provided by the caller.  To be safe, you must use one of:

if (!has_name) {
    name = NULL;
}
if (!has_id) {
    id = NULL;
}
... bdrv_snapshot_find(bs_vm_state, &sn, name, id, false) ...

or:

bdrv_snapshot_find(bs_vm_state, &sn,
                   has_name ? name : NULL,
                   has_id ? id : NULL,
                   false)

unless you take on the bigger task of ensuring that ALL callers pass in
NULL when has_name is false (and the code generator for QMP currently
doesn't guarantee that).

> +        return NULL;
> +    }
> +
> +    if (sn.vm_state_size == 0) {
> +        error_setg(errp, "this is a disk-only snapshot, revert to it offline "
> +            "using qemu-img");

Indentation is off; a continuation should line up to the character after
the '(' of the line before.

> +        return NULL;
>      }
>  
>      /* Verify if there is any device that doesn't support snapshots and is
> @@ -2425,29 +2434,28 @@ int load_vmstate(const char *name)
>          }
>  
>          if (!bdrv_can_snapshot(bs)) {
> -            error_report("Device '%s' is writable but does not support snapshots.",
> -                               bdrv_get_device_name(bs));
> -            return -ENOTSUP;
> +            error_setg(errp, "device '%s' is writable but does not support "
> +                       "snapshots", bdrv_get_device_name(bs));
> +            return NULL;
>          }

Pre-existing, but why do we care?  Loading a snapshot doesn't require
writing, just reading.

>  
> -        if (!bdrv_snapshot_find(bs, &sn, name, name, true)) {
> -            error_report("Device '%s' does not have the requested snapshot '%s'",
> -                           bdrv_get_device_name(bs), name);
> -            return -ENOENT;
> +        if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
> +            return NULL;

Missing error report.

>          }
>      }
>  
> +    saved_vm_running = runstate_is_running();
> +    vm_stop(RUN_STATE_RESTORE_VM);
> +
>      /* Flush all IO requests so they don't interfere with the new state.  */
>      bdrv_drain_all();
>  
>      bs = NULL;
>      while ((bs = bdrv_next(bs))) {
>          if (bdrv_can_snapshot(bs)) {
> -            bdrv_snapshot_goto(bs, name, &local_err);
> -            if (error_is_set(&local_err)) {
> -                error_report("%s", error_get_pretty(local_err));
> -                error_free(local_err);
> -                return -1;
> +            bdrv_snapshot_goto(bs, sn.name, errp);
> +            if (error_is_set(errp)) {
> +                return NULL;

Pre-existing, but yet another case of partial failure, where it might be
nicer to let the caller know if we failed halfway through loading a
located snapshot, differently than complete failure where we didn't
change any state.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 08/11] block: update error reporting for bdrv_snapshot_create() and related functions
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 08/11] block: update error reporting for bdrv_snapshot_create() and related functions Pavel Hrdina
@ 2013-04-16 23:54   ` Eric Blake
  0 siblings, 0 replies; 48+ messages in thread
From: Eric Blake @ 2013-04-16 23:54 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 1446 bytes --]

On 04/16/2013 10:05 AM, Pavel Hrdina wrote:
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  block.c                   | 23 ++++++++++++++---------
>  block/qcow2-snapshot.c    | 18 ++++++++++++------
>  block/qcow2.h             |  4 +++-
>  block/rbd.c               | 20 +++++++++++---------
>  block/sheepdog.c          | 22 +++++++++++-----------
>  include/block/block.h     |  5 +++--
>  include/block/block_int.h |  5 +++--
>  qemu-img.c                |  8 +++-----
>  savevm.c                  |  9 +++++----
>  9 files changed, 65 insertions(+), 49 deletions(-)
> 

> @@ -855,20 +857,20 @@ static int qemu_rbd_snap_create(BlockDriverState *bs,
>       */
>      if (sn_info->id_str[0] != '\0' &&
>          strcmp(sn_info->id_str, sn_info->name) != 0) {
> -        return -EINVAL;
> +        error_setg(errp, "rbd: ID and name have to be equal");
> +        return;

Who generates sn_info->id_str in the first place?  Didn't you just say
that the QMP interface does NOT expose user control over id_str, and
that it gets populated as a side effect of creation?  That says that
this error condition is probably dead code, if the QMP command never
attempts to generate id_str itself.

At any rate, the conversion to errp looks reasonable.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 09/11] savevm: update error reporting off qemu_savevm_state() and related functions
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 09/11] savevm: update error reporting off qemu_savevm_state() " Pavel Hrdina
@ 2013-04-17  0:02   ` Eric Blake
  0 siblings, 0 replies; 48+ messages in thread
From: Eric Blake @ 2013-04-17  0:02 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 523 bytes --]

On 04/16/2013 10:05 AM, Pavel Hrdina wrote:

I think you meant s/off/of/ in the subject.

> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  include/sysemu/sysemu.h |  7 ++++---
>  migration.c             |  6 +++---
>  savevm.c                | 38 +++++++++++++++++++-------------------
>  3 files changed, 26 insertions(+), 25 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find() Pavel Hrdina
@ 2013-04-17  2:53   ` Wenchao Xia
  2013-04-17  7:52     ` Pavel Hrdina
  0 siblings, 1 reply; 48+ messages in thread
From: Wenchao Xia @ 2013-04-17  2:53 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

Hi, Pavel
  I have implemented it at
http://lists.nongnu.org/archive/html/qemu-devel/2013-04/msg02533.html
in patch 1,2. Could u check if it satisfy your requirement, if yes maybe
you can directly use them.

> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>   savevm.c | 33 +++++++++++----------------------
>   1 file changed, 11 insertions(+), 22 deletions(-)
> 
> diff --git a/savevm.c b/savevm.c
> index 66753da..bc829a5 100644
> --- a/savevm.c
> +++ b/savevm.c
> @@ -2195,7 +2195,7 @@ out:
>   }
> 
>   static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
> -                              const char *name, const char *id, bool old_match)
> +                              const char *name, const char *id)
>   {
>       QEMUSnapshotInfo *sn_tab, *sn;
>       int nb_sns, i, found = 0;
> @@ -2218,20 +2218,10 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
>                   break;
>               }
>           } else if (name) {
> -            /* for compatibility for old bdrv_snapshot_find call
> -             * will be removed */
> -            if (old_match) {
> -                if (!strcmp(sn->id_str, id) || !strcmp(sn->name, name)) {
> -                    *sn_info = *sn;
> -                    found = 1;
> -                    break;
> -                }
> -            } else {
> -                if (!strcmp(sn->name, name)) {
> -                    *sn_info = *sn;
> -                    found = 1;
> -                    break;
> -                }
> +            if (!strcmp(sn->name, name)) {
> +                *sn_info = *sn;
> +                found = 1;
> +                break;
>               }
>           } else if (id) {
>               if (!strcmp(sn->id_str, id)) {
> @@ -2290,7 +2280,7 @@ SnapshotInfo *qmp_vm_snapshot_save(const char *name, Error **errp)
>       sn->date_nsec = tv.tv_usec * 1000;
>       sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
> 
> -    if (bdrv_snapshot_find(bs, old_sn, name, NULL, false)) {
> +    if (bdrv_snapshot_find(bs, old_sn, name, NULL)) {
>           error_setg(errp, "snapshot '%s' exists", name);
>           goto the_end;
>       } else {
> @@ -2388,7 +2378,7 @@ SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
>       }
> 
>       /* Don't even try to load empty VM states */
> -    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id, false)) {
> +    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id)) {
>           return NULL;
>       }
> 
> @@ -2413,7 +2403,7 @@ SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
>               return NULL;
>           }
> 
> -        if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
> +        if (!bdrv_snapshot_find(bs, &sn, name, id)) {
>               return NULL;
>           }
>       }
> @@ -2484,7 +2474,7 @@ SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
>           return NULL;
>       }
> 
> -    if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
> +    if (!bdrv_snapshot_find(bs, &sn, name, id)) {
>           /* no need to set an error if snapshot doesn't exist */
>           return NULL;
>       }
> @@ -2501,7 +2491,7 @@ SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
>       bs = NULL;
>       while ((bs = bdrv_next(bs))) {
>           if (bdrv_can_snapshot(bs)
> -                && bdrv_snapshot_find(bs, &sn, name, id, false)) {
> +                && bdrv_snapshot_find(bs, &sn, name, id)) {
>               bdrv_snapshot_delete(bs, sn.name, errp);
>               if (error_is_set(errp)) {
>                   return NULL;
> @@ -2549,8 +2539,7 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
> 
>           while ((bs1 = bdrv_next(bs1))) {
>               if (bdrv_can_snapshot(bs1) && bs1 != bs) {
> -                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str,
> -                                        true)) {
> +                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str)) {
>                       available = 0;
>                       break;
>                   }
> 


-- 
Best Regards

Wenchao Xia

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-17  2:53   ` Wenchao Xia
@ 2013-04-17  7:52     ` Pavel Hrdina
  2013-04-17 10:19       ` Wenchao Xia
  0 siblings, 1 reply; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-17  7:52 UTC (permalink / raw)
  To: Wenchao Xia; +Cc: lcapitulino, qemu-devel, armbru

Hi Wenchao,

unfortunately no. According to new design of savevm, loadvm and delvm I
need also search for snapshots that have the specified name and id.

I'm also touching bdrv_snapshot_list where I'm adding an Error parameter
and changing the return value to be used only for getting a number of
snapshots. So in case that there is some error, the return value will be 0.

Pavel

On 17.4.2013 04:53, Wenchao Xia wrote:
> Hi, Pavel
>    I have implemented it at
> http://lists.nongnu.org/archive/html/qemu-devel/2013-04/msg02533.html
> in patch 1,2. Could u check if it satisfy your requirement, if yes maybe
> you can directly use them.
> 
>> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
>> ---
>>    savevm.c | 33 +++++++++++----------------------
>>    1 file changed, 11 insertions(+), 22 deletions(-)
>>
>> diff --git a/savevm.c b/savevm.c
>> index 66753da..bc829a5 100644
>> --- a/savevm.c
>> +++ b/savevm.c
>> @@ -2195,7 +2195,7 @@ out:
>>    }
>>
>>    static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
>> -                              const char *name, const char *id, bool old_match)
>> +                              const char *name, const char *id)
>>    {
>>        QEMUSnapshotInfo *sn_tab, *sn;
>>        int nb_sns, i, found = 0;
>> @@ -2218,20 +2218,10 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
>>                    break;
>>                }
>>            } else if (name) {
>> -            /* for compatibility for old bdrv_snapshot_find call
>> -             * will be removed */
>> -            if (old_match) {
>> -                if (!strcmp(sn->id_str, id) || !strcmp(sn->name, name)) {
>> -                    *sn_info = *sn;
>> -                    found = 1;
>> -                    break;
>> -                }
>> -            } else {
>> -                if (!strcmp(sn->name, name)) {
>> -                    *sn_info = *sn;
>> -                    found = 1;
>> -                    break;
>> -                }
>> +            if (!strcmp(sn->name, name)) {
>> +                *sn_info = *sn;
>> +                found = 1;
>> +                break;
>>                }
>>            } else if (id) {
>>                if (!strcmp(sn->id_str, id)) {
>> @@ -2290,7 +2280,7 @@ SnapshotInfo *qmp_vm_snapshot_save(const char *name, Error **errp)
>>        sn->date_nsec = tv.tv_usec * 1000;
>>        sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
>>
>> -    if (bdrv_snapshot_find(bs, old_sn, name, NULL, false)) {
>> +    if (bdrv_snapshot_find(bs, old_sn, name, NULL)) {
>>            error_setg(errp, "snapshot '%s' exists", name);
>>            goto the_end;
>>        } else {
>> @@ -2388,7 +2378,7 @@ SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
>>        }
>>
>>        /* Don't even try to load empty VM states */
>> -    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id, false)) {
>> +    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id)) {
>>            return NULL;
>>        }
>>
>> @@ -2413,7 +2403,7 @@ SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
>>                return NULL;
>>            }
>>
>> -        if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
>> +        if (!bdrv_snapshot_find(bs, &sn, name, id)) {
>>                return NULL;
>>            }
>>        }
>> @@ -2484,7 +2474,7 @@ SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
>>            return NULL;
>>        }
>>
>> -    if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
>> +    if (!bdrv_snapshot_find(bs, &sn, name, id)) {
>>            /* no need to set an error if snapshot doesn't exist */
>>            return NULL;
>>        }
>> @@ -2501,7 +2491,7 @@ SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
>>        bs = NULL;
>>        while ((bs = bdrv_next(bs))) {
>>            if (bdrv_can_snapshot(bs)
>> -                && bdrv_snapshot_find(bs, &sn, name, id, false)) {
>> +                && bdrv_snapshot_find(bs, &sn, name, id)) {
>>                bdrv_snapshot_delete(bs, sn.name, errp);
>>                if (error_is_set(errp)) {
>>                    return NULL;
>> @@ -2549,8 +2539,7 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
>>
>>            while ((bs1 = bdrv_next(bs1))) {
>>                if (bdrv_can_snapshot(bs1) && bs1 != bs) {
>> -                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str,
>> -                                        true)) {
>> +                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str)) {
>>                        available = 0;
>>                        break;
>>                    }
>>
> 
> 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-17  7:52     ` Pavel Hrdina
@ 2013-04-17 10:19       ` Wenchao Xia
  2013-04-17 10:51         ` Pavel Hrdina
  0 siblings, 1 reply; 48+ messages in thread
From: Wenchao Xia @ 2013-04-17 10:19 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: armbru, qemu-devel, lcapitulino

于 2013-4-17 15:52, Pavel Hrdina 写道:
> Hi Wenchao,
> 
> unfortunately no. According to new design of savevm, loadvm and delvm I
> need also search for snapshots that have the specified name and id.
> 
  It seems the logic in your function, is same with mine...

> I'm also touching bdrv_snapshot_list where I'm adding an Error parameter
  I looked it before, but it needs all call back in ./block support it,
so is it really necessary?

> and changing the return value to be used only for getting a number of
> snapshots. So in case that there is some error, the return value will be 0.
> 
> Pavel
> 
> On 17.4.2013 04:53, Wenchao Xia wrote:
>> Hi, Pavel
>>     I have implemented it at
>> http://lists.nongnu.org/archive/html/qemu-devel/2013-04/msg02533.html
>> in patch 1,2. Could u check if it satisfy your requirement, if yes maybe
>> you can directly use them.
>>
>>> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
>>> ---
>>>     savevm.c | 33 +++++++++++----------------------
>>>     1 file changed, 11 insertions(+), 22 deletions(-)
>>>
>>> diff --git a/savevm.c b/savevm.c
>>> index 66753da..bc829a5 100644
>>> --- a/savevm.c
>>> +++ b/savevm.c
>>> @@ -2195,7 +2195,7 @@ out:
>>>     }
>>>
>>>     static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
>>> -                              const char *name, const char *id, bool old_match)
>>> +                              const char *name, const char *id)
>>>     {
>>>         QEMUSnapshotInfo *sn_tab, *sn;
>>>         int nb_sns, i, found = 0;
>>> @@ -2218,20 +2218,10 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
>>>                     break;
>>>                 }
>>>             } else if (name) {
>>> -            /* for compatibility for old bdrv_snapshot_find call
>>> -             * will be removed */
>>> -            if (old_match) {
>>> -                if (!strcmp(sn->id_str, id) || !strcmp(sn->name, name)) {
>>> -                    *sn_info = *sn;
>>> -                    found = 1;
>>> -                    break;
>>> -                }
>>> -            } else {
>>> -                if (!strcmp(sn->name, name)) {
>>> -                    *sn_info = *sn;
>>> -                    found = 1;
>>> -                    break;
>>> -                }
>>> +            if (!strcmp(sn->name, name)) {
>>> +                *sn_info = *sn;
>>> +                found = 1;
>>> +                break;
>>>                 }
>>>             } else if (id) {
>>>                 if (!strcmp(sn->id_str, id)) {
>>> @@ -2290,7 +2280,7 @@ SnapshotInfo *qmp_vm_snapshot_save(const char *name, Error **errp)
>>>         sn->date_nsec = tv.tv_usec * 1000;
>>>         sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
>>>
>>> -    if (bdrv_snapshot_find(bs, old_sn, name, NULL, false)) {
>>> +    if (bdrv_snapshot_find(bs, old_sn, name, NULL)) {
>>>             error_setg(errp, "snapshot '%s' exists", name);
>>>             goto the_end;
>>>         } else {
>>> @@ -2388,7 +2378,7 @@ SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
>>>         }
>>>
>>>         /* Don't even try to load empty VM states */
>>> -    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id, false)) {
>>> +    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id)) {
>>>             return NULL;
>>>         }
>>>
>>> @@ -2413,7 +2403,7 @@ SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
>>>                 return NULL;
>>>             }
>>>
>>> -        if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
>>> +        if (!bdrv_snapshot_find(bs, &sn, name, id)) {
>>>                 return NULL;
>>>             }
>>>         }
>>> @@ -2484,7 +2474,7 @@ SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
>>>             return NULL;
>>>         }
>>>
>>> -    if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
>>> +    if (!bdrv_snapshot_find(bs, &sn, name, id)) {
>>>             /* no need to set an error if snapshot doesn't exist */
>>>             return NULL;
>>>         }
>>> @@ -2501,7 +2491,7 @@ SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
>>>         bs = NULL;
>>>         while ((bs = bdrv_next(bs))) {
>>>             if (bdrv_can_snapshot(bs)
>>> -                && bdrv_snapshot_find(bs, &sn, name, id, false)) {
>>> +                && bdrv_snapshot_find(bs, &sn, name, id)) {
>>>                 bdrv_snapshot_delete(bs, sn.name, errp);
>>>                 if (error_is_set(errp)) {
>>>                     return NULL;
>>> @@ -2549,8 +2539,7 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
>>>
>>>             while ((bs1 = bdrv_next(bs1))) {
>>>                 if (bdrv_can_snapshot(bs1) && bs1 != bs) {
>>> -                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str,
>>> -                                        true)) {
>>> +                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str)) {
>>>                         available = 0;
>>>                         break;
>>>                     }
>>>
>>
>>
> 
> 


-- 
Best Regards

Wenchao Xia

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-17 10:19       ` Wenchao Xia
@ 2013-04-17 10:51         ` Pavel Hrdina
  2013-04-17 18:14           ` Eric Blake
  0 siblings, 1 reply; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-17 10:51 UTC (permalink / raw)
  To: Wenchao Xia; +Cc: armbru, qemu-devel, lcapitulino

On 17.4.2013 12:19, Wenchao Xia wrote:
> 于 2013-4-17 15:52, Pavel Hrdina 写道:
>> Hi Wenchao,
>>
>> unfortunately no. According to new design of savevm, loadvm and delvm I
>> need also search for snapshots that have the specified name and id.
>>
>    It seems the logic in your function, is same with mine...

It is not the same.

Your logic:
    if id is set:
        if there is snapshot with that id:
            end searching
    if name set (search also if id is set but nothing found):
        if there is snapshot with that name:
            end searching

My logic:
    if name is set and id is set:
        if there is snapshot with than name and with that id:
            end searching
    else if name is set (means that only name is set):
        if there is snapshot with that name:
            end searching
    else if id is set (means that only id is set):
        if there is snapshot with that id:
            end searching

> 
>> I'm also touching bdrv_snapshot_list where I'm adding an Error parameter
>    I looked it before, but it needs all call back in ./block support it,
> so is it really necessary?

I think it is better if this function internally set appropriate error
message based on used disk image format (qcow2, sheepdog, rbd).

Adding to CC Eric for his opinion.

> 
>> and changing the return value to be used only for getting a number of
>> snapshots. So in case that there is some error, the return value will be 0.
>>
>> Pavel
>>
>> On 17.4.2013 04:53, Wenchao Xia wrote:
>>> Hi, Pavel
>>>      I have implemented it at
>>> http://lists.nongnu.org/archive/html/qemu-devel/2013-04/msg02533.html
>>> in patch 1,2. Could u check if it satisfy your requirement, if yes maybe
>>> you can directly use them.
>>>
>>>> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
>>>> ---
>>>>      savevm.c | 33 +++++++++++----------------------
>>>>      1 file changed, 11 insertions(+), 22 deletions(-)
>>>>
>>>> diff --git a/savevm.c b/savevm.c
>>>> index 66753da..bc829a5 100644
>>>> --- a/savevm.c
>>>> +++ b/savevm.c
>>>> @@ -2195,7 +2195,7 @@ out:
>>>>      }
>>>>
>>>>      static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
>>>> -                              const char *name, const char *id, bool old_match)
>>>> +                              const char *name, const char *id)
>>>>      {
>>>>          QEMUSnapshotInfo *sn_tab, *sn;
>>>>          int nb_sns, i, found = 0;
>>>> @@ -2218,20 +2218,10 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
>>>>                      break;
>>>>                  }
>>>>              } else if (name) {
>>>> -            /* for compatibility for old bdrv_snapshot_find call
>>>> -             * will be removed */
>>>> -            if (old_match) {
>>>> -                if (!strcmp(sn->id_str, id) || !strcmp(sn->name, name)) {
>>>> -                    *sn_info = *sn;
>>>> -                    found = 1;
>>>> -                    break;
>>>> -                }
>>>> -            } else {
>>>> -                if (!strcmp(sn->name, name)) {
>>>> -                    *sn_info = *sn;
>>>> -                    found = 1;
>>>> -                    break;
>>>> -                }
>>>> +            if (!strcmp(sn->name, name)) {
>>>> +                *sn_info = *sn;
>>>> +                found = 1;
>>>> +                break;
>>>>                  }
>>>>              } else if (id) {
>>>>                  if (!strcmp(sn->id_str, id)) {
>>>> @@ -2290,7 +2280,7 @@ SnapshotInfo *qmp_vm_snapshot_save(const char *name, Error **errp)
>>>>          sn->date_nsec = tv.tv_usec * 1000;
>>>>          sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
>>>>
>>>> -    if (bdrv_snapshot_find(bs, old_sn, name, NULL, false)) {
>>>> +    if (bdrv_snapshot_find(bs, old_sn, name, NULL)) {
>>>>              error_setg(errp, "snapshot '%s' exists", name);
>>>>              goto the_end;
>>>>          } else {
>>>> @@ -2388,7 +2378,7 @@ SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
>>>>          }
>>>>
>>>>          /* Don't even try to load empty VM states */
>>>> -    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id, false)) {
>>>> +    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id)) {
>>>>              return NULL;
>>>>          }
>>>>
>>>> @@ -2413,7 +2403,7 @@ SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
>>>>                  return NULL;
>>>>              }
>>>>
>>>> -        if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
>>>> +        if (!bdrv_snapshot_find(bs, &sn, name, id)) {
>>>>                  return NULL;
>>>>              }
>>>>          }
>>>> @@ -2484,7 +2474,7 @@ SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
>>>>              return NULL;
>>>>          }
>>>>
>>>> -    if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
>>>> +    if (!bdrv_snapshot_find(bs, &sn, name, id)) {
>>>>              /* no need to set an error if snapshot doesn't exist */
>>>>              return NULL;
>>>>          }
>>>> @@ -2501,7 +2491,7 @@ SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
>>>>          bs = NULL;
>>>>          while ((bs = bdrv_next(bs))) {
>>>>              if (bdrv_can_snapshot(bs)
>>>> -                && bdrv_snapshot_find(bs, &sn, name, id, false)) {
>>>> +                && bdrv_snapshot_find(bs, &sn, name, id)) {
>>>>                  bdrv_snapshot_delete(bs, sn.name, errp);
>>>>                  if (error_is_set(errp)) {
>>>>                      return NULL;
>>>> @@ -2549,8 +2539,7 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
>>>>
>>>>              while ((bs1 = bdrv_next(bs1))) {
>>>>                  if (bdrv_can_snapshot(bs1) && bs1 != bs) {
>>>> -                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str,
>>>> -                                        true)) {
>>>> +                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str)) {
>>>>                          available = 0;
>>>>                          break;
>>>>                      }
>>>>
>>>
>>>
>>
>>
> 
> 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-17 10:51         ` Pavel Hrdina
@ 2013-04-17 18:14           ` Eric Blake
  2013-04-17 18:22             ` Eric Blake
  2013-04-18  4:31             ` Wenchao Xia
  0 siblings, 2 replies; 48+ messages in thread
From: Eric Blake @ 2013-04-17 18:14 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: qemu-devel, armbru, Wenchao Xia, lcapitulino

[-- Attachment #1: Type: text/plain, Size: 7667 bytes --]

On 04/17/2013 04:51 AM, Pavel Hrdina wrote:
> On 17.4.2013 12:19, Wenchao Xia wrote:
>> 于 2013-4-17 15:52, Pavel Hrdina 写道:
>>> Hi Wenchao,
>>>
>>> unfortunately no. According to new design of savevm, loadvm and delvm I
>>> need also search for snapshots that have the specified name and id.
>>>
>>    It seems the logic in your function, is same with mine...
> 
> It is not the same.

Consider a qcow2 file with the following snapshots:

     id     tag
     1      2
     2      1
     3      none

Existing logic:

only one string is passed, and only one loop is performed.  If it
matches id or name, end searching

search for 1 - finds id 1 tag 2
search for 2 - finds id 1 tag 2
search for 3 - finds id 3 no tag
search for 4 - finds nothing

no way to find id 2 tag 1

The last point proves that the current algorithm is not ideal, and that
we are justified in changing it.  But there are several ways to change
it, and a consideration of whether we should preserve backwards
compatibility in HMP by making the search itself have backwards
compatibility, or by making the QMP search follow strict rules where HMP
can emulate some measure of back-compat by calling into QMP more than once.

> 
> Your logic:
[Wenchao]
>     if id is set:
>         if there is snapshot with that id:
>             end searching
>     if name set (search also if id is set but nothing found):
>         if there is snapshot with that name:
>             end searching
> 
> My logic:
[Pavel]
>     if name is set and id is set:
>         if there is snapshot with than name and with that id:
>             end searching
>     else if name is set (means that only name is set):
>         if there is snapshot with that name:
>             end searching
>     else if id is set (means that only id is set):
>         if there is snapshot with that id:
>             end searching

Best is a side-by-side comparison; when comparing to existing, I showed
three different choices of expanding a single name into a two-argument
find call.

 search for:            finds                compared to
  id     name     Wenchao       Pavel          existing
                                              name -> find(id, NULL)
  1      NULL    id 1 tag 2    id 1 tag 2    id 1 tag 2
* 2      NULL    id 2 tag 1    id 2 tag 1    id 1 tag 2
  3      NULL    id 3 no tag   id 3 no tag   id 3 no tag
  4      NULL    nothing       nothing       nothing
                                              name -> find(NULL, tag)
* NULL   1       id 2 tag 1    id 2 tag 1    id 1 tag 2
  NULL   2       id 1 tag 2    id 1 tag 2    id 1 tag 2
* NULL   3       nothing       nothing       id 3 no tag
  NULL   4       nothing       nothing       nothing
                                              not possible
  1      2       id 1 tag 2    id 1 tag 2    --
  2      1       id 2 tag 1    id 2 tag 1    --
                                              name -> find(id, tag)
* 1      1       id 1 tag 2    nothing       id 1 tag 2
* 2      2       id 2 tag 1    nothing       id 1 tag 2
* 3      3       id 3 no tag   nothing       id 3 no tag
  4      4       nothing       nothing       nothing

The two proposed approaches both allow access to a lookup that the
original could not provide (namely, id 2 tag 1), so they are an
improvement on that front.  But the two approaches differ on behavior
when both id and name are specified (Wenchao's behaves the same as an
id-only lookup, regardless of whether the name matches; Pavel's requires
a double match).  The other thing to note is that the old code allowed a
single name to match an anonymous snapshot, but both proposals fail to
find a nameless snapshot without an id search.

Can I put yet another proposed algorithm on the table?  First, written
with four loops over the source (although at most two are taken):

    if name is set and id is set:
        if there is snapshot with than name and with that id (loop 1):
            end searching
    else if name is set (means that only name is set):
        if there is snapshot with that name (loop 2):
            end searching
        if there is snapshot with that id (loop 3):
            end searching
    else if id is set (means that only id is set):
        if there is snapshot with that id (loop 4):
            end searching

Or, written another way, to implement the same results in only two coded
loops:

    if name is set:
        if there is a snapshot with that name (loop 1):
            if id is set:
                if id matches:
                    end searching successfully
                else:
                    fail
            else:
                end searching successfully
        else if id is not set:
            set id to name
    if there is a snapshot with id (loop 2):
        end searching successfully

And the resulting comparison table, again with three possibilities of
how to convert one-argument lookup into two-argument:

 search for:        finds      compared to
  id     name     mine          existing
                                name -> find(id, NULL)
  1      NULL    id 1 tag 2    id 1 tag 2
* 2      NULL    id 2 tag 1    id 1 tag 2
  3      NULL    id 3 no tag   id 3 no tag
  4      NULL    nothing       nothing
                                name -> find(NULL, tag)
* NULL   1       id 2 tag 1    id 1 tag 2
  NULL   2       id 1 tag 2    id 1 tag 2
  NULL   3       id 3 no tag   id 3 no tag
  NULL   4       nothing       nothing
                                not possible
  1      2       id 1 tag 2    --
  2      1       id 2 tag 1    --
                                name -> find(id, tag)
* 1      1       nothing       id 1 tag 2
* 2      2       nothing       id 1 tag 2
* 3      3       nothing       id 3 no tag
  4      4       nothing       nothing


With that adjusted table, I would favor converting any single name
lookup into find(NULL, tag).  Only the new QMP command that lets us do
an explicit id lookup can search for an id regardless of another name
matching the id; but we at least have the benefit of being able to
access ALL named snapshots (better than the original code unable to
access tag 2), as well as the ability to access unambiguous ids without
extra effort (ability to access id 3 without having to change the
command line).  It keeps the aspect of Pavel's code that specifying both
fields must match both fields, but otherwise favors names over ids
(generally good, since names are generally not numeric, except when we
are talking about corner cases).

So, was I convincing enough in arguing that we want something different
from the approach of both existing patch series?

> 
>>
>>> I'm also touching bdrv_snapshot_list where I'm adding an Error parameter
>>    I looked it before, but it needs all call back in ./block support it,
>> so is it really necessary?
> 
> I think it is better if this function internally set appropriate error
> message based on used disk image format (qcow2, sheepdog, rbd).

I like the idea of find() setting errp on lookup failure.  Callers can
ignore errors in situations where a failed lookup triggers a reasonable
fallback, but in case the caller wants to report an error, the lower
down that we generate an error message, the more likely the error
message is to contain full context rather than being dumbed down by
generating it higher on the call stack.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-17 18:14           ` Eric Blake
@ 2013-04-17 18:22             ` Eric Blake
  2013-04-18  4:31             ` Wenchao Xia
  1 sibling, 0 replies; 48+ messages in thread
From: Eric Blake @ 2013-04-17 18:22 UTC (permalink / raw)
  Cc: lcapitulino, Wenchao Xia, Pavel Hrdina, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 1101 bytes --]

On 04/17/2013 12:14 PM, Eric Blake wrote:

> Or, written another way, to implement the same results in only two coded
> loops:

Missed a line:

> 
>     if name is set:
>         if there is a snapshot with that name (loop 1):
>             if id is set:
>                 if id matches:
>                     end searching successfully
>                 else:
>                     fail
>             else:
>                 end searching successfully
>         else if id is not set:
>             set id to name

These two lines should instead be:

          else if id is set:
              fail
          set id to name

>     if there is a snapshot with id (loop 2):
>         end searching successfully

and of course, all of the algorithms have an implied fail if you make it
through all of the loops without a successful search end.

The tweak above is needed so that a find(id, tag) that fails a tag
lookup does not then succeed on an id lookup.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-17 18:14           ` Eric Blake
  2013-04-17 18:22             ` Eric Blake
@ 2013-04-18  4:31             ` Wenchao Xia
  2013-04-18  7:20               ` Wenchao Xia
  2013-04-18 10:22               ` Pavel Hrdina
  1 sibling, 2 replies; 48+ messages in thread
From: Wenchao Xia @ 2013-04-18  4:31 UTC (permalink / raw)
  To: Eric Blake; +Cc: lcapitulino, Pavel Hrdina, qemu-devel, armbru

于 2013-4-18 2:14, Eric Blake 写道:
> On 04/17/2013 04:51 AM, Pavel Hrdina wrote:
>> On 17.4.2013 12:19, Wenchao Xia wrote:
>>> 于 2013-4-17 15:52, Pavel Hrdina 写道:
>>>> Hi Wenchao,
>>>>
>>>> unfortunately no. According to new design of savevm, loadvm and delvm I
>>>> need also search for snapshots that have the specified name and id.
>>>>
>>>     It seems the logic in your function, is same with mine...
>>
>> It is not the same.
>
> Consider a qcow2 file with the following snapshots:
>
>       id     tag
>       1      2
>       2      1
>       3      none
>
> Existing logic:
>
> only one string is passed, and only one loop is performed.  If it
> matches id or name, end searching
>
> search for 1 - finds id 1 tag 2
> search for 2 - finds id 1 tag 2
> search for 3 - finds id 3 no tag
> search for 4 - finds nothing
>
> no way to find id 2 tag 1
>
> The last point proves that the current algorithm is not ideal, and that
> we are justified in changing it.  But there are several ways to change
> it, and a consideration of whether we should preserve backwards
> compatibility in HMP by making the search itself have backwards
> compatibility, or by making the QMP search follow strict rules where HMP
> can emulate some measure of back-compat by calling into QMP more than once.
>
>>
>> Your logic:
> [Wenchao]
>>      if id is set:
>>          if there is snapshot with that id:
>>              end searching
>>      if name set (search also if id is set but nothing found):
>>          if there is snapshot with that name:
>>              end searching
>>
>> My logic:
> [Pavel]
>>      if name is set and id is set:
>>          if there is snapshot with than name and with that id:
>>              end searching
>>      else if name is set (means that only name is set):
>>          if there is snapshot with that name:
>>              end searching
>>      else if id is set (means that only id is set):
>>          if there is snapshot with that id:
>>              end searching
>
> Best is a side-by-side comparison; when comparing to existing, I showed
> three different choices of expanding a single name into a two-argument
> find call.
>
>   search for:            finds                compared to
>    id     name     Wenchao       Pavel          existing
>                                                name -> find(id, NULL)
>    1      NULL    id 1 tag 2    id 1 tag 2    id 1 tag 2
> * 2      NULL    id 2 tag 1    id 2 tag 1    id 1 tag 2
>    3      NULL    id 3 no tag   id 3 no tag   id 3 no tag
>    4      NULL    nothing       nothing       nothing
>                                                name -> find(NULL, tag)
> * NULL   1       id 2 tag 1    id 2 tag 1    id 1 tag 2
>    NULL   2       id 1 tag 2    id 1 tag 2    id 1 tag 2
> * NULL   3       nothing       nothing       id 3 no tag
>    NULL   4       nothing       nothing       nothing
>                                                not possible
>    1      2       id 1 tag 2    id 1 tag 2    --
>    2      1       id 2 tag 1    id 2 tag 1    --
>                                                name -> find(id, tag)
> * 1      1       id 1 tag 2    nothing       id 1 tag 2
> * 2      2       id 2 tag 1    nothing       id 1 tag 2
> * 3      3       id 3 no tag   nothing       id 3 no tag
>    4      4       nothing       nothing       nothing
>
> The two proposed approaches both allow access to a lookup that the
> original could not provide (namely, id 2 tag 1), so they are an
> improvement on that front.  But the two approaches differ on behavior
> when both id and name are specified (Wenchao's behaves the same as an
> id-only lookup, regardless of whether the name matches; Pavel's requires
> a double match).  The other thing to note is that the old code allowed a
> single name to match an anonymous snapshot, but both proposals fail to
> find a nameless snapshot without an id search.
>
> Can I put yet another proposed algorithm on the table?  First, written
> with four loops over the source (although at most two are taken):
>
>      if name is set and id is set:
>          if there is snapshot with than name and with that id (loop 1):
>              end searching
>      else if name is set (means that only name is set):
>          if there is snapshot with that name (loop 2):
>              end searching
>          if there is snapshot with that id (loop 3):
>              end searching
>      else if id is set (means that only id is set):
>          if there is snapshot with that id (loop 4):
>              end searching
>
> Or, written another way, to implement the same results in only two coded
> loops:
>
>      if name is set:
>          if there is a snapshot with that name (loop 1):
>              if id is set:
>                  if id matches:
>                      end searching successfully
>                  else:
>                      fail
>              else:
>                  end searching successfully
>          else if id is not set:
>              set id to name
>      if there is a snapshot with id (loop 2):
>          end searching successfully
>
> And the resulting comparison table, again with three possibilities of
> how to convert one-argument lookup into two-argument:
>
>   search for:        finds      compared to
>    id     name     mine          existing
>                                  name -> find(id, NULL)
>    1      NULL    id 1 tag 2    id 1 tag 2
> * 2      NULL    id 2 tag 1    id 1 tag 2
>    3      NULL    id 3 no tag   id 3 no tag
>    4      NULL    nothing       nothing
>                                  name -> find(NULL, tag)
> * NULL   1       id 2 tag 1    id 1 tag 2
>    NULL   2       id 1 tag 2    id 1 tag 2
>    NULL   3       id 3 no tag   id 3 no tag
>    NULL   4       nothing       nothing
>                                  not possible
>    1      2       id 1 tag 2    --
>    2      1       id 2 tag 1    --
>                                  name -> find(id, tag)
> * 1      1       nothing       id 1 tag 2
> * 2      2       nothing       id 1 tag 2
> * 3      3       nothing       id 3 no tag
>    4      4       nothing       nothing
>
>
> With that adjusted table, I would favor converting any single name
> lookup into find(NULL, tag).  Only the new QMP command that lets us do
> an explicit id lookup can search for an id regardless of another name
> matching the id; but we at least have the benefit of being able to
> access ALL named snapshots (better than the original code unable to
> access tag 2), as well as the ability to access unambiguous ids without
> extra effort (ability to access id 3 without having to change the
> command line).  It keeps the aspect of Pavel's code that specifying both
> fields must match both fields, but otherwise favors names over ids
> (generally good, since names are generally not numeric, except when we
> are talking about corner cases).
>
> So, was I convincing enough in arguing that we want something different
> from the approach of both existing patch series?
>
   Plenty of details, thanks, Eric. I think Pavel's logic is better,
which increase the capability of it, and I don't think a more complex
logic should be there, since it is an internal function need clear
meaning.


>>
>>>
>>>> I'm also touching bdrv_snapshot_list where I'm adding an Error parameter
>>>     I looked it before, but it needs all call back in ./block support it,
>>> so is it really necessary?
>>
>> I think it is better if this function internally set appropriate error
>> message based on used disk image format (qcow2, sheepdog, rbd).
>
> I like the idea of find() setting errp on lookup failure.  Callers can
> ignore errors in situations where a failed lookup triggers a reasonable
> fallback, but in case the caller wants to report an error, the lower
> down that we generate an error message, the more likely the error
> message is to contain full context rather than being dumbed down by
> generating it higher on the call stack.
>
   I understand it helps, but now I need just a good
bdrv_snapshot_find() to use, so could this improvement work
be postponded later? I think neither my or Pavel's work
is depending on it.
   Pavel, to make us progress, I'd like a small serial change
bdrv_snapshot_find() first, then we can rebase on it, are u OK
with it?

block/qapi.c:
int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
                        const char *name, const char *id)



-- 
Best Regards

Wenchao Xia

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-18  4:31             ` Wenchao Xia
@ 2013-04-18  7:20               ` Wenchao Xia
  2013-04-18 10:22               ` Pavel Hrdina
  1 sibling, 0 replies; 48+ messages in thread
From: Wenchao Xia @ 2013-04-18  7:20 UTC (permalink / raw)
  To: Eric Blake; +Cc: lcapitulino, Pavel Hrdina, qemu-devel, armbru


>> So, was I convincing enough in arguing that we want something different
>> from the approach of both existing patch series?
>>
>    Plenty of details, thanks, Eric. I think Pavel's logic is better,
> which increase the capability of it, and I don't think a more complex
> logic should be there, since it is an internal function need clear
> meaning.
>
>
>>>
>>
>    I understand it helps, but now I need just a good
> bdrv_snapshot_find() to use, so could this improvement work
> be postponded later? I think neither my or Pavel's work
> is depending on it.
>    Pavel, to make us progress, I'd like a small serial change
> bdrv_snapshot_find() first, then we can rebase on it, are u OK
> with it?
>
> block/qapi.c:
> int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
>                         const char *name, const char *id)
>
>
>
   Actually my serial, two condition are "or" relationship,
but in Pavel's they are "and" relationship. From caller,
I think "and" is better, and taking two parameter in one function
make caller easier to use, in most case.
   I'd like a clean serial go for it, hope to know Pavel and
Markus's idea.

-- 
Best Regards

Wenchao Xia

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-18  4:31             ` Wenchao Xia
  2013-04-18  7:20               ` Wenchao Xia
@ 2013-04-18 10:22               ` Pavel Hrdina
  2013-04-19  0:28                 ` Wenchao Xia
  1 sibling, 1 reply; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-18 10:22 UTC (permalink / raw)
  To: Wenchao Xia; +Cc: armbru, qemu-devel, lcapitulino

On 18.4.2013 06:31, Wenchao Xia wrote:
> 于 2013-4-18 2:14, Eric Blake 写道:
>> On 04/17/2013 04:51 AM, Pavel Hrdina wrote:
>>> On 17.4.2013 12:19, Wenchao Xia wrote:
>>>> 于 2013-4-17 15:52, Pavel Hrdina 写道:
>>>>> Hi Wenchao,
>>>>>
>>>>> unfortunately no. According to new design of savevm, loadvm and
>>>>> delvm I
>>>>> need also search for snapshots that have the specified name and id.
>>>>>
>>>>     It seems the logic in your function, is same with mine...
>>>
>>> It is not the same.
>>
>> Consider a qcow2 file with the following snapshots:
>>
>>       id     tag
>>       1      2
>>       2      1
>>       3      none
>>
>> Existing logic:
>>
>> only one string is passed, and only one loop is performed.  If it
>> matches id or name, end searching
>>
>> search for 1 - finds id 1 tag 2
>> search for 2 - finds id 1 tag 2
>> search for 3 - finds id 3 no tag
>> search for 4 - finds nothing
>>
>> no way to find id 2 tag 1
>>
>> The last point proves that the current algorithm is not ideal, and that
>> we are justified in changing it.  But there are several ways to change
>> it, and a consideration of whether we should preserve backwards
>> compatibility in HMP by making the search itself have backwards
>> compatibility, or by making the QMP search follow strict rules where HMP
>> can emulate some measure of back-compat by calling into QMP more than
>> once.
>>
>>>
>>> Your logic:
>> [Wenchao]
>>>      if id is set:
>>>          if there is snapshot with that id:
>>>              end searching
>>>      if name set (search also if id is set but nothing found):
>>>          if there is snapshot with that name:
>>>              end searching
>>>
>>> My logic:
>> [Pavel]
>>>      if name is set and id is set:
>>>          if there is snapshot with than name and with that id:
>>>              end searching
>>>      else if name is set (means that only name is set):
>>>          if there is snapshot with that name:
>>>              end searching
>>>      else if id is set (means that only id is set):
>>>          if there is snapshot with that id:
>>>              end searching
>>
>> Best is a side-by-side comparison; when comparing to existing, I showed
>> three different choices of expanding a single name into a two-argument
>> find call.
>>
>>   search for:            finds                compared to
>>    id     name     Wenchao       Pavel          existing
>>                                                name -> find(id, NULL)
>>    1      NULL    id 1 tag 2    id 1 tag 2    id 1 tag 2
>> * 2      NULL    id 2 tag 1    id 2 tag 1    id 1 tag 2
>>    3      NULL    id 3 no tag   id 3 no tag   id 3 no tag
>>    4      NULL    nothing       nothing       nothing
>>                                                name -> find(NULL, tag)
>> * NULL   1       id 2 tag 1    id 2 tag 1    id 1 tag 2
>>    NULL   2       id 1 tag 2    id 1 tag 2    id 1 tag 2
>> * NULL   3       nothing       nothing       id 3 no tag
>>    NULL   4       nothing       nothing       nothing
>>                                                not possible
>>    1      2       id 1 tag 2    id 1 tag 2    --
>>    2      1       id 2 tag 1    id 2 tag 1    --
>>                                                name -> find(id, tag)
>> * 1      1       id 1 tag 2    nothing       id 1 tag 2
>> * 2      2       id 2 tag 1    nothing       id 1 tag 2
>> * 3      3       id 3 no tag   nothing       id 3 no tag
>>    4      4       nothing       nothing       nothing
>>
>> The two proposed approaches both allow access to a lookup that the
>> original could not provide (namely, id 2 tag 1), so they are an
>> improvement on that front.  But the two approaches differ on behavior
>> when both id and name are specified (Wenchao's behaves the same as an
>> id-only lookup, regardless of whether the name matches; Pavel's requires
>> a double match).  The other thing to note is that the old code allowed a
>> single name to match an anonymous snapshot, but both proposals fail to
>> find a nameless snapshot without an id search.
>>
>> Can I put yet another proposed algorithm on the table?  First, written
>> with four loops over the source (although at most two are taken):
>>
>>      if name is set and id is set:
>>          if there is snapshot with than name and with that id (loop 1):
>>              end searching
>>      else if name is set (means that only name is set):
>>          if there is snapshot with that name (loop 2):
>>              end searching
>>          if there is snapshot with that id (loop 3):
>>              end searching
>>      else if id is set (means that only id is set):
>>          if there is snapshot with that id (loop 4):
>>              end searching
>>
>> Or, written another way, to implement the same results in only two coded
>> loops:
>>
>>      if name is set:
>>          if there is a snapshot with that name (loop 1):
>>              if id is set:
>>                  if id matches:
>>                      end searching successfully
>>                  else:
>>                      fail
>>              else:
>>                  end searching successfully
>>          else if id is not set:
>>              set id to name
>>      if there is a snapshot with id (loop 2):
>>          end searching successfully
>>
>> And the resulting comparison table, again with three possibilities of
>> how to convert one-argument lookup into two-argument:
>>
>>   search for:        finds      compared to
>>    id     name     mine          existing
>>                                  name -> find(id, NULL)
>>    1      NULL    id 1 tag 2    id 1 tag 2
>> * 2      NULL    id 2 tag 1    id 1 tag 2
>>    3      NULL    id 3 no tag   id 3 no tag
>>    4      NULL    nothing       nothing
>>                                  name -> find(NULL, tag)
>> * NULL   1       id 2 tag 1    id 1 tag 2
>>    NULL   2       id 1 tag 2    id 1 tag 2
>>    NULL   3       id 3 no tag   id 3 no tag
>>    NULL   4       nothing       nothing
>>                                  not possible
>>    1      2       id 1 tag 2    --
>>    2      1       id 2 tag 1    --
>>                                  name -> find(id, tag)
>> * 1      1       nothing       id 1 tag 2
>> * 2      2       nothing       id 1 tag 2
>> * 3      3       nothing       id 3 no tag
>>    4      4       nothing       nothing
>>
>>
>> With that adjusted table, I would favor converting any single name
>> lookup into find(NULL, tag).  Only the new QMP command that lets us do
>> an explicit id lookup can search for an id regardless of another name
>> matching the id; but we at least have the benefit of being able to
>> access ALL named snapshots (better than the original code unable to
>> access tag 2), as well as the ability to access unambiguous ids without
>> extra effort (ability to access id 3 without having to change the
>> command line).  It keeps the aspect of Pavel's code that specifying both
>> fields must match both fields, but otherwise favors names over ids
>> (generally good, since names are generally not numeric, except when we
>> are talking about corner cases).
>>
>> So, was I convincing enough in arguing that we want something different
>> from the approach of both existing patch series?
>>
>    Plenty of details, thanks, Eric. I think Pavel's logic is better,
> which increase the capability of it, and I don't think a more complex
> logic should be there, since it is an internal function need clear
> meaning.
>

I also thank you Eric for that detailed description. I must agree with 
Wenchao that internal function needs clear meaning. Why would I need to 
find snapshot by id using name parameter if I have the id parameter? I 
know that name is in almost all cases some string and not a number and 
that it could be for some cases easier just find snapshot by id using 
name parameter, but I think that we must be strict about this logic.

>
>>>
>>>>
>>>>> I'm also touching bdrv_snapshot_list where I'm adding an Error
>>>>> parameter
>>>>     I looked it before, but it needs all call back in ./block
>>>> support it,
>>>> so is it really necessary?
>>>
>>> I think it is better if this function internally set appropriate error
>>> message based on used disk image format (qcow2, sheepdog, rbd).
>>
>> I like the idea of find() setting errp on lookup failure.  Callers can
>> ignore errors in situations where a failed lookup triggers a reasonable
>> fallback, but in case the caller wants to report an error, the lower
>> down that we generate an error message, the more likely the error
>> message is to contain full context rather than being dumbed down by
>> generating it higher on the call stack.
>>
>    I understand it helps, but now I need just a good
> bdrv_snapshot_find() to use, so could this improvement work
> be postponded later? I think neither my or Pavel's work
> is depending on it.
>    Pavel, to make us progress, I'd like a small serial change
> bdrv_snapshot_find() first, then we can rebase on it, are u OK
> with it?
>
> block/qapi.c:
> int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
>                         const char *name, const char *id)
>

I think that my whole series is almost done and it would be quickly 
accepted and applied upstream. I'll send today the v2 and we will see.

Pavel

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 07/11] qapi: Convert loadvm
  2013-04-16 23:43   ` Eric Blake
@ 2013-04-18 10:34     ` Pavel Hrdina
  0 siblings, 0 replies; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-18 10:34 UTC (permalink / raw)
  To: Eric Blake; +Cc: Wenchao Xia, lcapitulino, qemu-devel, armbru

On 17.4.2013 01:43, Eric Blake wrote:
> On 04/16/2013 10:05 AM, Pavel Hrdina wrote:
>> QMP command vm-snapshot-load and HMP command loadvm behave similar to
>> vm-snapshot-delete and delvm. The only different is that they will load
>> the snapshot instead of deleting it.
>>
>> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
>> ---
>>   hmp-commands.hx         | 16 +++++-----
>>   hmp.c                   | 35 ++++++++++++++++++++++
>>   hmp.h                   |  1 +
>>   include/sysemu/sysemu.h |  1 -
>>   monitor.c               | 12 --------
>>   qapi-schema.json        | 18 +++++++++++
>>   qmp-commands.hx         | 38 ++++++++++++++++++++++++
>>   savevm.c                | 79 ++++++++++++++++++++++++++++++-------------------
>>   vl.c                    |  7 ++++-
>>   9 files changed, 156 insertions(+), 51 deletions(-)
>>
>> diff --git a/hmp-commands.hx b/hmp-commands.hx
>> index d1701ce..e80410b 100644
>> --- a/hmp-commands.hx
>> +++ b/hmp-commands.hx
>> @@ -324,17 +324,19 @@ ETEXI
>>
>>       {
>>           .name       = "loadvm",
>> -        .args_type  = "name:s",
>> -        .params     = "tag|id",
>> -        .help       = "restore a VM snapshot from its tag or id",
>> -        .mhandler.cmd = do_loadvm,
>> +        .args_type  = "id:-i,name:s",
>> +        .params     = "[-i] tag|[id]",
>> +        .help       = "restore a VM snapshot from its tag or id if -i flag is provided",
>
> Same comments as 4/11 about possibilities of making this look nicer
> ('name' seems nicer than 'tag|[id]').
>
>>   }
>> +
>> +void hmp_vm_snapshot_load(Monitor *mon, const QDict *qdict)
>> +{
>> +    const char *name = qdict_get_try_str(qdict, "name");
>> +    const bool id = qdict_get_try_bool(qdict, "id", false);
>> +    Error *local_err = NULL;
>> +    SnapshotInfo *info = NULL;
>> +
>> +    if (id) {
>> +        info = qmp_vm_snapshot_load(false, NULL, true, name, &local_err);
>> +    } else {
>> +        info = qmp_vm_snapshot_load(true, name, false, NULL, &local_err);
>> +    }
>
> Could be written without if/else:
> qmp_vm_snapshot_load(id, name, !id, name, &local_err);
>
> but doesn't really bother me as written.
>
>> +
>> +    if (info) {
>> +        char buf[256];
>
> Fixed-size buffer...

I'll leave it there for now and Wenchao could update this in his patch 
series.

>
>> +        QEMUSnapshotInfo sn = {
>> +            .vm_state_size = info->vm_state_size,
>> +            .date_sec = info->date_sec,
>> +            .date_nsec = info->date_nsec,
>> +            .vm_clock_nsec = info->vm_clock_sec * 1000000000 +
>> +                             info->vm_clock_nsec,
>> +        };
>> +        pstrcpy(sn.id_str, sizeof(sn.id_str), info->id);
>> +        pstrcpy(sn.name, sizeof(sn.name), info->name);
>> +        monitor_printf(mon, "Loaded snapshot's info:\n");
>> +        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
>> +        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), &sn));
>
> ...but potentially large amount of information to be placed in it.  I
> would MUCH rather see this code using gstring, or even direct printing.
>   I think you need to base this on top of the ideas here:
>
> https://lists.gnu.org/archive/html/qemu-devel/2013-04/msg02540.html
>
> These two series need to be coordinated to minimize churn and rebase
> conflicts on cleanups such as removing buffer truncation from
> bdrv_snapshot_dump.
>
> Hmm, I probably should have mentioned this on 4/11 as well.
>
>> +    } else if (!error_is_set(&local_err)) {
>
> Same comments as 4/11, in that info == NULL should imply that local_err
> is set.
>
>> +++ b/qapi-schema.json
>> @@ -3522,3 +3522,21 @@
>>   ##
>>   { 'command': 'vm-snapshot-delete', 'data': {'*name': 'str', '*id': 'str'},
>>     'returns': 'SnapshotInfo' }
>> +
>> +##
>> +# @vm-snapshot-load:
>> +#
>> +# Set the whole virtual machine to the snapshot identified by the tag
>> +# or the unique snapshot id or both. It must be a snapshot of a whole VM and
>> +# at least one of the name or id parameter must be specified.
>> +#
>> +# @name: tag of existing snapshot
>> +#
>> +# @id: id of existing snapshot
>
> As in 4/11, mark these with #optional.
>
>> +#
>> +# Returns: SnapshotInfo on success
>> +#
>> +# Since: 1.5
>> +##
>> +{ 'command': 'vm-snapshot-load', 'data': {'*name': 'str', '*id': 'str'},
>> +  'returns': 'SnapshotInfo' }
>
> Same comments as 4/11 on return value design decisions.
>
>> @@ -2393,26 +2393,35 @@ void qmp_xen_save_devices_state(const char *filename, Error **errp)
>>           vm_start();
>>   }
>>
>> -int load_vmstate(const char *name)
>> +SnapshotInfo *qmp_vm_snapshot_load(bool has_name, const char *name,
>> +                                   bool has_id, const char *id, Error **errp)
>>   {
>>       BlockDriverState *bs, *bs_vm_state;
>>       QEMUSnapshotInfo sn;
>>       QEMUFile *f;
>> -    Error *local_err;
>> +    SnapshotInfo *info = NULL;
>> +    int saved_vm_running;
>
> This should be bool.  runstate_is_running() is currently typed as int,
> but it defers to runstate_check() which is bool; fixing runstate_is* to
> consistently use bool would be worthy of a separate cleanup patch.
>
>> +
>> +    if (!has_name && !has_id) {
>> +        error_setg(errp, "name or id must be specified");
>> +        return NULL;
>> +    }
>>
>>       bs_vm_state = bdrv_snapshots();
>>       if (!bs_vm_state) {
>> -        error_report("No block device supports snapshots");
>> -        return -ENOTSUP;
>> +        error_setg(errp, "no block device supports snapshots");
>> +        return NULL;
>>       }
>>
>>       /* Don't even try to load empty VM states */
>> -    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, name, true)) {
>> -        return -ENOENT;
>> -    } else if (sn.vm_state_size == 0) {
>> -        error_report("This is a disk-only snapshot. Revert to it offline "
>> -            "using qemu-img.");
>> -        return -EINVAL;
>> +    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, id, false)) {
>
> Oh, I didn't notice this before, but 4/11 has the same issue.  You are
> not guaranteed that 'name' and 'id' are initialized correctly unless you
> first check 'has_name' and 'has_id'.  And given my suggestion above of
> possibly compressing things to:
>
> qmp_vm_snapshot_load(id, name, !id, name, &local_err);
>
> then it REALLY matters that you pass NULL for the parameters that are
> not provided by the caller.  To be safe, you must use one of:
>
> if (!has_name) {
>      name = NULL;
> }
> if (!has_id) {
>      id = NULL;
> }
> ... bdrv_snapshot_find(bs_vm_state, &sn, name, id, false) ...
>

Thanks for pointing this out, I didn't realize that.

> or:
>
> bdrv_snapshot_find(bs_vm_state, &sn,
>                     has_name ? name : NULL,
>                     has_id ? id : NULL,
>                     false)
>
> unless you take on the bigger task of ensuring that ALL callers pass in
> NULL when has_name is false (and the code generator for QMP currently
> doesn't guarantee that).
>
>> +        return NULL;
>> +    }
>> +
>> +    if (sn.vm_state_size == 0) {
>> +        error_setg(errp, "this is a disk-only snapshot, revert to it offline "
>> +            "using qemu-img");
>
> Indentation is off; a continuation should line up to the character after
> the '(' of the line before.
>
>> +        return NULL;
>>       }
>>
>>       /* Verify if there is any device that doesn't support snapshots and is
>> @@ -2425,29 +2434,28 @@ int load_vmstate(const char *name)
>>           }
>>
>>           if (!bdrv_can_snapshot(bs)) {
>> -            error_report("Device '%s' is writable but does not support snapshots.",
>> -                               bdrv_get_device_name(bs));
>> -            return -ENOTSUP;
>> +            error_setg(errp, "device '%s' is writable but does not support "
>> +                       "snapshots", bdrv_get_device_name(bs));
>> +            return NULL;
>>           }
>
> Pre-existing, but why do we care?  Loading a snapshot doesn't require
> writing, just reading.

For now I'll leave it there. This basically check that there is for 
example some raw disk and therefore the snapshot state wouldn't be 
loaded for all block devices.

We anyway need to improve savevm, loadvm and delvm to do a better 
checking and as you said behave transactionally. This also applies for 
most of your comments about functionality and it should be fixed in 
another patch series.

>
>>
>> -        if (!bdrv_snapshot_find(bs, &sn, name, name, true)) {
>> -            error_report("Device '%s' does not have the requested snapshot '%s'",
>> -                           bdrv_get_device_name(bs), name);
>> -            return -ENOENT;
>> +        if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
>> +            return NULL;
>
> Missing error report.
>
>>           }
>>       }
>>
>> +    saved_vm_running = runstate_is_running();
>> +    vm_stop(RUN_STATE_RESTORE_VM);
>> +
>>       /* Flush all IO requests so they don't interfere with the new state.  */
>>       bdrv_drain_all();
>>
>>       bs = NULL;
>>       while ((bs = bdrv_next(bs))) {
>>           if (bdrv_can_snapshot(bs)) {
>> -            bdrv_snapshot_goto(bs, name, &local_err);
>> -            if (error_is_set(&local_err)) {
>> -                error_report("%s", error_get_pretty(local_err));
>> -                error_free(local_err);
>> -                return -1;
>> +            bdrv_snapshot_goto(bs, sn.name, errp);
>> +            if (error_is_set(errp)) {
>> +                return NULL;
>
> Pre-existing, but yet another case of partial failure, where it might be
> nicer to let the caller know if we failed halfway through loading a
> located snapshot, differently than complete failure where we didn't
> change any state.
>

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error()
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error() Pavel Hrdina
  2013-04-16 16:46   ` Eric Blake
@ 2013-04-18 11:44   ` Kevin Wolf
  2013-04-18 11:52     ` Pavel Hrdina
  1 sibling, 1 reply; 48+ messages in thread
From: Kevin Wolf @ 2013-04-18 11:44 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
> Later in the patch series we will use this function few times.
> This will avoid of duplicating the code.
> 
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  qemu-img.c | 17 +++++++++++------
>  1 file changed, 11 insertions(+), 6 deletions(-)
> 
> diff --git a/qemu-img.c b/qemu-img.c
> index 31627b0..dbacdb7 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -322,6 +322,16 @@ static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
>      return 0;
>  }
>  
> +static int qemu_img_handle_error(const char *msg, Error *err)
> +{
> +    if (error_is_set(&err)) {
> +        error_report("%s: %s", msg, error_get_pretty(err));
> +        error_free(err);
> +        return 1;
> +    }
> +    return 0;
> +}
> +
>  static int img_create(int argc, char **argv)
>  {
>      int c;
> @@ -400,13 +410,8 @@ static int img_create(int argc, char **argv)
>  
>      bdrv_img_create(filename, fmt, base_filename, base_fmt,
>                      options, img_size, BDRV_O_FLAGS, &local_err, quiet);
> -    if (error_is_set(&local_err)) {
> -        error_report("%s", error_get_pretty(local_err));
> -        error_free(local_err);
> -        return 1;
> -    }
>  
> -    return 0;
> +    return qemu_img_handle_error("qemu-img create failed", local_err);
>  }

This makes a change to the error message that isn't mentioned in the
commit message. It should definitely be mentioned there, but I'm not
even sure if it's a good change. Today you get something like:

    $ qemu-img create -f foo test.img
    qemu-img: Unknown file format 'foo'

With the patch applied it becomes:

    $ qemu-img create -f foo test.img
    qemu-img: qemu-img create failed: Unknown file format 'foo'

Does this add any useful information or does it just make the error
message longer? I feel it's the latter.

Kevin

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error()
  2013-04-18 11:44   ` Kevin Wolf
@ 2013-04-18 11:52     ` Pavel Hrdina
  2013-04-18 12:59       ` Kevin Wolf
  0 siblings, 1 reply; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-18 11:52 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: lcapitulino, qemu-devel, armbru

On 18.4.2013 13:44, Kevin Wolf wrote:
> Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
>> Later in the patch series we will use this function few times.
>> This will avoid of duplicating the code.
>>
>> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
>> ---
>>   qemu-img.c | 17 +++++++++++------
>>   1 file changed, 11 insertions(+), 6 deletions(-)
>>
>> diff --git a/qemu-img.c b/qemu-img.c
>> index 31627b0..dbacdb7 100644
>> --- a/qemu-img.c
>> +++ b/qemu-img.c
>> @@ -322,6 +322,16 @@ static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
>>       return 0;
>>   }
>>
>> +static int qemu_img_handle_error(const char *msg, Error *err)
>> +{
>> +    if (error_is_set(&err)) {
>> +        error_report("%s: %s", msg, error_get_pretty(err));
>> +        error_free(err);
>> +        return 1;
>> +    }
>> +    return 0;
>> +}
>> +
>>   static int img_create(int argc, char **argv)
>>   {
>>       int c;
>> @@ -400,13 +410,8 @@ static int img_create(int argc, char **argv)
>>
>>       bdrv_img_create(filename, fmt, base_filename, base_fmt,
>>                       options, img_size, BDRV_O_FLAGS, &local_err, quiet);
>> -    if (error_is_set(&local_err)) {
>> -        error_report("%s", error_get_pretty(local_err));
>> -        error_free(local_err);
>> -        return 1;
>> -    }
>>
>> -    return 0;
>> +    return qemu_img_handle_error("qemu-img create failed", local_err);
>>   }
>
> This makes a change to the error message that isn't mentioned in the
> commit message. It should definitely be mentioned there, but I'm not
> even sure if it's a good change. Today you get something like:
>
>      $ qemu-img create -f foo test.img
>      qemu-img: Unknown file format 'foo'
>
> With the patch applied it becomes:
>
>      $ qemu-img create -f foo test.img
>      qemu-img: qemu-img create failed: Unknown file format 'foo'
>
> Does this add any useful information or does it just make the error
> message longer? I feel it's the latter.
>
> Kevin
>

Thanks for pointing this out, it should be
qemu_img_handle_error("create failed", local_err);

and later in patch series also
qemu_img_handle_error("snapshot create failed", local_err);

Is that OK after this change?

Pavel

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 02/11] block: update error reporting for bdrv_snapshot_delete() and related functions
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 02/11] block: update error reporting for bdrv_snapshot_delete() and related functions Pavel Hrdina
  2013-04-16 17:14   ` Eric Blake
@ 2013-04-18 12:55   ` Kevin Wolf
  2013-04-18 13:09     ` Eric Blake
  2013-04-18 13:19     ` Pavel Hrdina
  1 sibling, 2 replies; 48+ messages in thread
From: Kevin Wolf @ 2013-04-18 12:55 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
> 
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  block.c                   | 22 ++++++++++++++--------
>  block/qcow2-snapshot.c    | 21 +++++++++++++++------
>  block/qcow2.h             |  4 +++-
>  block/rbd.c               | 11 ++++++++---
>  block/sheepdog.c          |  6 ++++--
>  include/block/block.h     |  4 +++-
>  include/block/block_int.h |  4 +++-
>  qemu-img.c                |  9 ++++-----
>  savevm.c                  | 26 ++++++++++----------------
>  9 files changed, 64 insertions(+), 43 deletions(-)
> 
> diff --git a/block.c b/block.c
> index 4ad663d..fb065e6 100644
> --- a/block.c
> +++ b/block.c
> @@ -3391,16 +3391,22 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
>      return -ENOTSUP;
>  }
>  
> -int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
> +void bdrv_snapshot_delete(BlockDriverState *bs,
> +                          const char *snapshot_id,
> +                          Error **errp)
>  {
>      BlockDriver *drv = bs->drv;
> -    if (!drv)
> -        return -ENOMEDIUM;
> -    if (drv->bdrv_snapshot_delete)
> -        return drv->bdrv_snapshot_delete(bs, snapshot_id);
> -    if (bs->file)
> -        return bdrv_snapshot_delete(bs->file, snapshot_id);
> -    return -ENOTSUP;
> +
> +    if (!drv) {
> +        error_setg(errp, "device '%s' has no medium", bdrv_get_device_name(bs));

I don't think the device name is useful here. It's always the device
that the user has specified in the monitor command.

Also, please start error messages with a capital letter. (This applies
to the whole patch, and probably also other patches in this series)

> +    } else if (drv->bdrv_snapshot_delete) {
> +        drv->bdrv_snapshot_delete(bs, snapshot_id, errp);
> +    } else if (bs->file) {
> +        bdrv_snapshot_delete(bs->file, snapshot_id, errp);
> +    } else {
> +        error_setg(errp, "snapshots are not supported on device '%s'",
> +                   bdrv_get_device_name(bs));

Same thing with the device name here.

> +    }
>  }
>  
>  int bdrv_snapshot_list(BlockDriverState *bs,
> diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
> index 992a5c8..2ebeadc 100644
> --- a/block/qcow2-snapshot.c
> +++ b/block/qcow2-snapshot.c
> @@ -530,7 +530,9 @@ fail:
>      return ret;
>  }
>  
> -int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
> +void qcow2_snapshot_delete(BlockDriverState *bs,
> +                           const char *snapshot_id,
> +                           Error **errp)
>  {
>      BDRVQcowState *s = bs->opaque;
>      QCowSnapshot sn;
> @@ -539,7 +541,9 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
>      /* Search the snapshot */
>      snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
>      if (snapshot_index < 0) {
> -        return -ENOENT;
> +        error_setg(errp, "qcow2: failed to find snapshot '%s' by id or name",
> +                   snapshot_id);
> +        return;
>      }
>      sn = s->snapshots[snapshot_index];
>  
> @@ -550,7 +554,9 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
>      s->nb_snapshots--;
>      ret = qcow2_write_snapshots(bs);
>      if (ret < 0) {
> -        return ret;
> +        error_setg_errno(errp, -ret, "qcow2: failed to remove snapshot '%s' "
> +                         "from snapshot list", sn.name);
> +        return;
>      }
>  
>      /*
> @@ -567,14 +573,18 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
>      ret = qcow2_update_snapshot_refcount(bs, sn.l1_table_offset,
>                                           sn.l1_size, -1);
>      if (ret < 0) {
> -        return ret;
> +        error_setg_errno(errp, -ret,
> +                         "qcow2: failed to update snapshot refcount");

I'd make it "qcow2: Failed to update refcounts". It's the refcounts of
all clusters referred to by the snapshot's L1 table, not of the snapshot
itself.

> +        return;
>      }
>      qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t));
>  
>      /* must update the copied flag on the current cluster offsets */
>      ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
>      if (ret < 0) {
> -        return ret;
> +        error_setg_errno(errp, -ret,
> +                         "qcow2: failed to update snapshot refcount");

"qcow2: Failed to update cluster flags"

> +        return;
>      }
>  
>  #ifdef DEBUG_ALLOC
> @@ -583,7 +593,6 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
>          qcow2_check_refcounts(bs, &result, 0);
>      }
>  #endif
> -    return 0;
>  }
>  
>  int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
> diff --git a/block/qcow2.h b/block/qcow2.h
> index 9421843..dbd332d 100644
> --- a/block/qcow2.h
> +++ b/block/qcow2.h
> @@ -384,7 +384,9 @@ int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
>  /* qcow2-snapshot.c functions */
>  int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
>  int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
> -int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
> +void qcow2_snapshot_delete(BlockDriverState *bs,
> +                           const char *snapshot_id,
> +                           Error **errp);
>  int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
>  int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name);
>  
> diff --git a/block/rbd.c b/block/rbd.c
> index 141b488..c10edbf 100644
> --- a/block/rbd.c
> +++ b/block/rbd.c
> @@ -871,14 +871,19 @@ static int qemu_rbd_snap_create(BlockDriverState *bs,
>      return 0;
>  }
>  
> -static int qemu_rbd_snap_remove(BlockDriverState *bs,
> -                                const char *snapshot_name)
> +static void qemu_rbd_snap_remove(BlockDriverState *bs,
> +                                 const char *snapshot_name,
> +                                 Error **errp)
>  {
>      BDRVRBDState *s = bs->opaque;
>      int r;
>  
>      r = rbd_snap_remove(s->image, snapshot_name);
> -    return r;
> +    if (r < 0) {
> +        error_setg_errno(errp, -r, "rbd: failed to remove snapshot '%s' on "
> +                         "device '%s'", snapshot_name,
> +                         bdrv_get_device_name(bs));

Remove the device name. You didn't have it in the qcow2 errors either.

> +    }
>  }
>  
>  static int qemu_rbd_snap_rollback(BlockDriverState *bs,
> diff --git a/block/sheepdog.c b/block/sheepdog.c
> index 1c5b532..270fa64 100644
> --- a/block/sheepdog.c
> +++ b/block/sheepdog.c
> @@ -1908,10 +1908,12 @@ out:
>      return ret;
>  }
>  
> -static int sd_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
> +static void sd_snapshot_delete(BlockDriverState *bs,
> +                               const char *snapshot_id,
> +                               Error **errp)
>  {
>      /* FIXME: Delete specified snapshot id.  */
> -    return 0;
> +    return;
>  }

Looks like there should be some error_setg("Deleting snapshots not
supported yet by sheepdog"), possibly in a separate patch.

>  static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
> diff --git a/include/block/block.h b/include/block/block.h
> index ebd9512..db8c6aa 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -337,7 +337,9 @@ int bdrv_snapshot_create(BlockDriverState *bs,
>                           QEMUSnapshotInfo *sn_info);
>  int bdrv_snapshot_goto(BlockDriverState *bs,
>                         const char *snapshot_id);
> -int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
> +void bdrv_snapshot_delete(BlockDriverState *bs,
> +                          const char *snapshot_id,
> +                          Error **errp);
>  int bdrv_snapshot_list(BlockDriverState *bs,
>                         QEMUSnapshotInfo **psn_info);
>  int bdrv_snapshot_load_tmp(BlockDriverState *bs,
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index 458cde3..53c52bb 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -157,7 +157,9 @@ struct BlockDriver {
>                                  QEMUSnapshotInfo *sn_info);
>      int (*bdrv_snapshot_goto)(BlockDriverState *bs,
>                                const char *snapshot_id);
> -    int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id);
> +    void (*bdrv_snapshot_delete)(BlockDriverState *bs,
> +                                 const char *snapshot_id,
> +                                 Error **errp);
>      int (*bdrv_snapshot_list)(BlockDriverState *bs,
>                                QEMUSnapshotInfo **psn_info);
>      int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,
> diff --git a/qemu-img.c b/qemu-img.c
> index dbacdb7..4828fe4 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -1936,6 +1936,7 @@ static int img_snapshot(int argc, char **argv)
>  {
>      BlockDriverState *bs;
>      QEMUSnapshotInfo sn;
> +    Error *local_err = NULL;
>      char *filename, *snapshot_name = NULL;
>      int c, ret = 0, bdrv_oflags;
>      int action = 0;
> @@ -2033,11 +2034,9 @@ static int img_snapshot(int argc, char **argv)
>          break;
>  
>      case SNAPSHOT_DELETE:
> -        ret = bdrv_snapshot_delete(bs, snapshot_name);
> -        if (ret) {
> -            error_report("Could not delete snapshot '%s': %d (%s)",
> -                snapshot_name, ret, strerror(-ret));
> -        }
> +        bdrv_snapshot_delete(bs, snapshot_name, &local_err);
> +        ret = qemu_img_handle_error("qemu-img snapshot delete failed",
> +                                    local_err);

Here again "qemu-img snapshot delete failed" is redundant. If this is
the command that I typed and I get an error, then it's obvious that it's
this command that failed.

>          break;
>      }
>  
> diff --git a/savevm.c b/savevm.c
> index 53515cb..6af84fd 100644
> --- a/savevm.c
> +++ b/savevm.c
> @@ -2225,18 +2225,17 @@ static int del_existing_snapshots(Monitor *mon, const char *name)
>  {
>      BlockDriverState *bs;
>      QEMUSnapshotInfo sn1, *snapshot = &sn1;
> -    int ret;
> +    Error *local_err = NULL;
>  
>      bs = NULL;
>      while ((bs = bdrv_next(bs))) {
>          if (bdrv_can_snapshot(bs) &&
>              bdrv_snapshot_find(bs, snapshot, name) >= 0)
>          {
> -            ret = bdrv_snapshot_delete(bs, name);
> -            if (ret < 0) {
> -                monitor_printf(mon,
> -                               "Error while deleting snapshot on '%s'\n",
> -                               bdrv_get_device_name(bs));
> +            bdrv_snapshot_delete(bs, name, &local_err);
> +            if (error_is_set(&local_err)) {
> +                monitor_printf(mon, "%s\n", error_get_pretty(local_err));

Here the additional monitor_printf() actually had meaningful additional
information. Deleting an old snapshot is an implicitly taken action and
not explicitly requested, so an error message should indicate that it
happened during the deletion. Maybe something like:

qerror_report(ERROR_CLASS_GENERIC_ERROR,
              "Error while deleting old snapshot on device '%s': %s",
              bdrv_get_device_name(bs), error_get_pretty(local_err));

> +                error_free(local_err);
>                  return -1;
>              }
>          }
> @@ -2450,7 +2449,7 @@ int load_vmstate(const char *name)
>  void do_delvm(Monitor *mon, const QDict *qdict)
>  {
>      BlockDriverState *bs, *bs1;
> -    int ret;
> +    Error *local_err = NULL;
>      const char *name = qdict_get_str(qdict, "name");
>  
>      bs = bdrv_snapshots();
> @@ -2462,15 +2461,10 @@ void do_delvm(Monitor *mon, const QDict *qdict)
>      bs1 = NULL;
>      while ((bs1 = bdrv_next(bs1))) {
>          if (bdrv_can_snapshot(bs1)) {
> -            ret = bdrv_snapshot_delete(bs1, name);
> -            if (ret < 0) {
> -                if (ret == -ENOTSUP)
> -                    monitor_printf(mon,
> -                                   "Snapshots not supported on device '%s'\n",
> -                                   bdrv_get_device_name(bs1));
> -                else
> -                    monitor_printf(mon, "Error %d while deleting snapshot on "
> -                                   "'%s'\n", ret, bdrv_get_device_name(bs1));
> +            bdrv_snapshot_delete(bs1, name, &local_err);
> +            if (error_is_set(&local_err)) {
> +                monitor_printf(mon, "%s\n", error_get_pretty(local_err));

Either something like above, indicating the device name on which
bdrv_snapshot_delete() failed, or qerror_report_err().

> +                error_free(local_err);
>              }
>          }
>      }

Kevin

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error()
  2013-04-18 11:52     ` Pavel Hrdina
@ 2013-04-18 12:59       ` Kevin Wolf
  2013-04-18 13:09         ` Pavel Hrdina
  0 siblings, 1 reply; 48+ messages in thread
From: Kevin Wolf @ 2013-04-18 12:59 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: armbru, qemu-devel, lcapitulino

Am 18.04.2013 um 13:52 hat Pavel Hrdina geschrieben:
> On 18.4.2013 13:44, Kevin Wolf wrote:
> >Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
> >>Later in the patch series we will use this function few times.
> >>This will avoid of duplicating the code.
> >>
> >>Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> >>---
> >>  qemu-img.c | 17 +++++++++++------
> >>  1 file changed, 11 insertions(+), 6 deletions(-)
> >>
> >>diff --git a/qemu-img.c b/qemu-img.c
> >>index 31627b0..dbacdb7 100644
> >>--- a/qemu-img.c
> >>+++ b/qemu-img.c
> >>@@ -322,6 +322,16 @@ static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
> >>      return 0;
> >>  }
> >>
> >>+static int qemu_img_handle_error(const char *msg, Error *err)
> >>+{
> >>+    if (error_is_set(&err)) {
> >>+        error_report("%s: %s", msg, error_get_pretty(err));
> >>+        error_free(err);
> >>+        return 1;
> >>+    }
> >>+    return 0;
> >>+}
> >>+
> >>  static int img_create(int argc, char **argv)
> >>  {
> >>      int c;
> >>@@ -400,13 +410,8 @@ static int img_create(int argc, char **argv)
> >>
> >>      bdrv_img_create(filename, fmt, base_filename, base_fmt,
> >>                      options, img_size, BDRV_O_FLAGS, &local_err, quiet);
> >>-    if (error_is_set(&local_err)) {
> >>-        error_report("%s", error_get_pretty(local_err));
> >>-        error_free(local_err);
> >>-        return 1;
> >>-    }
> >>
> >>-    return 0;
> >>+    return qemu_img_handle_error("qemu-img create failed", local_err);
> >>  }
> >
> >This makes a change to the error message that isn't mentioned in the
> >commit message. It should definitely be mentioned there, but I'm not
> >even sure if it's a good change. Today you get something like:
> >
> >     $ qemu-img create -f foo test.img
> >     qemu-img: Unknown file format 'foo'
> >
> >With the patch applied it becomes:
> >
> >     $ qemu-img create -f foo test.img
> >     qemu-img: qemu-img create failed: Unknown file format 'foo'
> >
> >Does this add any useful information or does it just make the error
> >message longer? I feel it's the latter.
> >
> >Kevin
> >
> 
> Thanks for pointing this out, it should be
> qemu_img_handle_error("create failed", local_err);
> 
> and later in patch series also
> qemu_img_handle_error("snapshot create failed", local_err);
> 
> Is that OK after this change?

I would in fact leave the error message as it is today. The "create
failed" doesn't help me understand the error better. I already know that
it's a create command that failed, because it was me who called 'qemu-img
create'.

Kevin

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 02/11] block: update error reporting for bdrv_snapshot_delete() and related functions
  2013-04-18 12:55   ` Kevin Wolf
@ 2013-04-18 13:09     ` Eric Blake
  2013-04-18 13:51       ` Kevin Wolf
  2013-04-18 13:19     ` Pavel Hrdina
  1 sibling, 1 reply; 48+ messages in thread
From: Eric Blake @ 2013-04-18 13:09 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: armbru, Pavel Hrdina, qemu-devel, lcapitulino

[-- Attachment #1: Type: text/plain, Size: 2711 bytes --]

On 04/18/2013 06:55 AM, Kevin Wolf wrote:
> Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
>>
>> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
>> ---
>>  
>> -int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
>> +void bdrv_snapshot_delete(BlockDriverState *bs,
>> +                          const char *snapshot_id,
>> +                          Error **errp)
>>  {
>>      BlockDriver *drv = bs->drv;
>> -    if (!drv)
>> -        return -ENOMEDIUM;
>> -    if (drv->bdrv_snapshot_delete)
>> -        return drv->bdrv_snapshot_delete(bs, snapshot_id);
>> -    if (bs->file)
>> -        return bdrv_snapshot_delete(bs->file, snapshot_id);
>> -    return -ENOTSUP;
>> +
>> +    if (!drv) {
>> +        error_setg(errp, "device '%s' has no medium", bdrv_get_device_name(bs));
> 
> I don't think the device name is useful here. It's always the device
> that the user has specified in the monitor command.

Huh?  We're talking about vm-snapshot-delete, which removes the snapshot
for multiple devices at a time.  Knowing _which_ device failed is
important in the context of a command where you don't specify a device name.

> 
> Also, please start error messages with a capital letter. (This applies
> to the whole patch, and probably also other patches in this series)

Qemu is inconsistent on this front.  The code base actually favors lower
case at the moment:

$ git grep 'error_setg.*"[a-z]' | wc
    119     957   10361
$ git grep 'error_setg.*"[A-Z]' | wc
     60     510    4996

Monitor output, on the other hand, favor uppercase:

$ git grep 'monitor_pr.*"[A-Z]' | wc
     88     576    6611
$ git grep 'monitor_pr.*"[a-z]' | wc
    108     789    8566

If you want to enforce a particular style, I think it would be best to
patch HACKING to document a preferred style.

If it helps as a tie breaker, GNU Coding Standards recommend lowercase:
https://www.gnu.org/prep/standards/standards.html#Errors

Personally, I don't care which way we go.

> 
>> +    } else if (drv->bdrv_snapshot_delete) {
>> +        drv->bdrv_snapshot_delete(bs, snapshot_id, errp);
>> +    } else if (bs->file) {
>> +        bdrv_snapshot_delete(bs->file, snapshot_id, errp);
>> +    } else {
>> +        error_setg(errp, "snapshots are not supported on device '%s'",
>> +                   bdrv_get_device_name(bs));
> 
> Same thing with the device name here.

Same thing about this function being reached via vm-snapshot-delete
where we aren't passing in a device name, so knowing which device failed
is important.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error()
  2013-04-18 12:59       ` Kevin Wolf
@ 2013-04-18 13:09         ` Pavel Hrdina
  2013-04-18 15:23           ` Luiz Capitulino
  0 siblings, 1 reply; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-18 13:09 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: armbru, qemu-devel, lcapitulino

On 18.4.2013 14:59, Kevin Wolf wrote:
> Am 18.04.2013 um 13:52 hat Pavel Hrdina geschrieben:
>> On 18.4.2013 13:44, Kevin Wolf wrote:
>>> Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
>>>> Later in the patch series we will use this function few times.
>>>> This will avoid of duplicating the code.
>>>>
>>>> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
>>>> ---
>>>>   qemu-img.c | 17 +++++++++++------
>>>>   1 file changed, 11 insertions(+), 6 deletions(-)
>>>>
>>>> diff --git a/qemu-img.c b/qemu-img.c
>>>> index 31627b0..dbacdb7 100644
>>>> --- a/qemu-img.c
>>>> +++ b/qemu-img.c
>>>> @@ -322,6 +322,16 @@ static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
>>>>       return 0;
>>>>   }
>>>>
>>>> +static int qemu_img_handle_error(const char *msg, Error *err)
>>>> +{
>>>> +    if (error_is_set(&err)) {
>>>> +        error_report("%s: %s", msg, error_get_pretty(err));
>>>> +        error_free(err);
>>>> +        return 1;
>>>> +    }
>>>> +    return 0;
>>>> +}
>>>> +
>>>>   static int img_create(int argc, char **argv)
>>>>   {
>>>>       int c;
>>>> @@ -400,13 +410,8 @@ static int img_create(int argc, char **argv)
>>>>
>>>>       bdrv_img_create(filename, fmt, base_filename, base_fmt,
>>>>                       options, img_size, BDRV_O_FLAGS, &local_err, quiet);
>>>> -    if (error_is_set(&local_err)) {
>>>> -        error_report("%s", error_get_pretty(local_err));
>>>> -        error_free(local_err);
>>>> -        return 1;
>>>> -    }
>>>>
>>>> -    return 0;
>>>> +    return qemu_img_handle_error("qemu-img create failed", local_err);
>>>>   }
>>>
>>> This makes a change to the error message that isn't mentioned in the
>>> commit message. It should definitely be mentioned there, but I'm not
>>> even sure if it's a good change. Today you get something like:
>>>
>>>      $ qemu-img create -f foo test.img
>>>      qemu-img: Unknown file format 'foo'
>>>
>>> With the patch applied it becomes:
>>>
>>>      $ qemu-img create -f foo test.img
>>>      qemu-img: qemu-img create failed: Unknown file format 'foo'
>>>
>>> Does this add any useful information or does it just make the error
>>> message longer? I feel it's the latter.
>>>
>>> Kevin
>>>
>>
>> Thanks for pointing this out, it should be
>> qemu_img_handle_error("create failed", local_err);
>>
>> and later in patch series also
>> qemu_img_handle_error("snapshot create failed", local_err);
>>
>> Is that OK after this change?
>
> I would in fact leave the error message as it is today. The "create
> failed" doesn't help me understand the error better. I already know that
> it's a create command that failed, because it was me who called 'qemu-img
> create'.
>
> Kevin
>

Yes that's true and make sense, but what if another tool internally uses 
the qemu-img command? I know that the tool could print/return/whatever 
proper error message, but qemu-img could help with that printing more 
information.

Pavel

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 03/11] savevm: update bdrv_snapshot_find() to find snapshot by id or name
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 03/11] savevm: update bdrv_snapshot_find() to find snapshot by id or name Pavel Hrdina
  2013-04-16 17:34   ` Eric Blake
@ 2013-04-18 13:17   ` Kevin Wolf
  1 sibling, 0 replies; 48+ messages in thread
From: Kevin Wolf @ 2013-04-18 13:17 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
> Finding snapshot by a name which could also be an id isn't best way
> how to do it. There will be rewrite of savevm, loadvm and delvm to
> improve the behavior of these commands. The savevm and loadvm will
> have their own patch series.
> 
> Now bdrv_snapshot_find takes more parameters. The name parameter will
> be matched only against the name of the snapshot and the same applies
> to id parameter.
> 
> There is one exception. If you set the last parameter, the name parameter
> will be matched against the name or the id of a snapshot. This exception
> is only for backward compatibility for other commands and it will be
> dropped after all commands will be rewritten.
> 
> We only need to know if that snapshot exists or not. We don't care
> about any error message. If snapshot exists it returns 1 otherwise
> it returns 0.

Sounds like it should be true/false rather than 1/0.

Also, isn't there a difference between "there is no snapshot foo" and "we
couldn't find out if there is a snapshot foo because there was an
error"?

> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  savevm.c | 73 ++++++++++++++++++++++++++++++++++++++++++++--------------------
>  1 file changed, 50 insertions(+), 23 deletions(-)
> 
> diff --git a/savevm.c b/savevm.c
> index 6af84fd..96a2340 100644
> --- a/savevm.c
> +++ b/savevm.c
> @@ -2197,25 +2197,55 @@ out:
>  }
>  
>  static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
> -                              const char *name)
> +                              const char *name, const char *id, bool old_match)
>  {
>      QEMUSnapshotInfo *sn_tab, *sn;
> -    int nb_sns, i, ret;
> +    int nb_sns, i, found = 0;
> +
> +    if (!name && !id) {
> +        return found;
> +    }

Why not just an explicit return 0? Or actually, while you touch the
prototype you could make the function return a bool and return false.

>  
> -    ret = -ENOENT;
>      nb_sns = bdrv_snapshot_list(bs, &sn_tab);
> -    if (nb_sns < 0)
> -        return ret;
> +    if (nb_sns < 0) {
> +        return found;
> +    }

Same here.

> +
>      for(i = 0; i < nb_sns; i++) {

You can add a space after 'for' while touching the function.

>          sn = &sn_tab[i];
> -        if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
> -            *sn_info = *sn;
> -            ret = 0;
> -            break;
> +        if (name && id) {
> +            if (!strcmp(sn->id_str, id) && !strcmp(sn->name, name)) {
> +                *sn_info = *sn;
> +                found = 1;
> +                break;
> +            }
> +        } else if (name) {
> +            /* for compatibility for old bdrv_snapshot_find call
> +             * will be removed */
> +            if (old_match) {
> +                if (!strcmp(sn->id_str, id) || !strcmp(sn->name, name)) {
> +                    *sn_info = *sn;
> +                    found = 1;
> +                    break;
> +                }
> +            } else {
> +                if (!strcmp(sn->name, name)) {
> +                    *sn_info = *sn;
> +                    found = 1;
> +                    break;
> +                }
> +            }
> +        } else if (id) {
> +            if (!strcmp(sn->id_str, id)) {
> +                *sn_info = *sn;
> +                found = 1;
> +                break;
> +            }
>          }
>      }
> +
>      g_free(sn_tab);
> -    return ret;
> +    return found;
>  }
>  
>  /*
> @@ -2229,8 +2259,8 @@ static int del_existing_snapshots(Monitor *mon, const char *name)
>  
>      bs = NULL;
>      while ((bs = bdrv_next(bs))) {
> -        if (bdrv_can_snapshot(bs) &&
> -            bdrv_snapshot_find(bs, snapshot, name) >= 0)
> +        if (bdrv_can_snapshot(bs)
> +                && bdrv_snapshot_find(bs, snapshot, name, name, true))

It would only retain the old behaviour if you specified NULL for id.
Now _both_ name and id must match, which will happen almost never.

How did you test this patch? Sounds like something that a qemu-iotests
case using the Python QMP methods could easily test.

>          {
>              bdrv_snapshot_delete(bs, name, &local_err);
>              if (error_is_set(&local_err)) {
> @@ -2289,8 +2319,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
>      sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
>  
>      if (name) {
> -        ret = bdrv_snapshot_find(bs, old_sn, name);
> -        if (ret >= 0) {
> +        if (bdrv_snapshot_find(bs, old_sn, name, name, true)) {

Same problem.

>              pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
>              pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
>          } else {
> @@ -2380,9 +2409,8 @@ int load_vmstate(const char *name)
>      }
>  
>      /* Don't even try to load empty VM states */
> -    ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
> -    if (ret < 0) {
> -        return ret;
> +    if (!bdrv_snapshot_find(bs_vm_state, &sn, name, name, true)) {

And again.

> +        return -ENOENT;

We're losing the real error message here. The old code said exactly what
happened, the new one always claims that the snapshot doesn't exist even
in case of I/O errors or anything.

>      } else if (sn.vm_state_size == 0) {
>          error_report("This is a disk-only snapshot. Revert to it offline "
>              "using qemu-img.");
> @@ -2404,11 +2432,10 @@ int load_vmstate(const char *name)
>              return -ENOTSUP;
>          }
>  
> -        ret = bdrv_snapshot_find(bs, &sn, name);
> -        if (ret < 0) {
> +        if (!bdrv_snapshot_find(bs, &sn, name, name, true)) {
>              error_report("Device '%s' does not have the requested snapshot '%s'",
>                             bdrv_get_device_name(bs), name);
> -            return ret;
> +            return -ENOENT;
>          }
>      }
>  
> @@ -2474,7 +2501,7 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
>  {
>      BlockDriverState *bs, *bs1;
>      QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s;
> -    int nb_sns, i, ret, available;
> +    int nb_sns, i, available;
>      int total;
>      int *available_snapshots;
>      char buf[256];
> @@ -2505,8 +2532,8 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
>  
>          while ((bs1 = bdrv_next(bs1))) {
>              if (bdrv_can_snapshot(bs1) && bs1 != bs) {
> -                ret = bdrv_snapshot_find(bs1, sn_info, sn->id_str);
> -                if (ret < 0) {
> +                if (!bdrv_snapshot_find(bs1, sn_info, sn->name, sn->id_str,
> +                                        true)) {

Is it intention that both id and name must match here? I suspect that no
because you set old_match == true, which is however ignored because both
id and name are set.

>                      available = 0;
>                      break;
>                  }

Kevin

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 02/11] block: update error reporting for bdrv_snapshot_delete() and related functions
  2013-04-18 12:55   ` Kevin Wolf
  2013-04-18 13:09     ` Eric Blake
@ 2013-04-18 13:19     ` Pavel Hrdina
  2013-04-18 13:41       ` Kevin Wolf
  1 sibling, 1 reply; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-18 13:19 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: lcapitulino, qemu-devel, armbru

On 18.4.2013 14:55, Kevin Wolf wrote:
> Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
>>
>>       /*
>> @@ -567,14 +573,18 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
>>       ret = qcow2_update_snapshot_refcount(bs, sn.l1_table_offset,
>>                                            sn.l1_size, -1);
>>       if (ret < 0) {
>> -        return ret;
>> +        error_setg_errno(errp, -ret,
>> +                         "qcow2: failed to update snapshot refcount");
>
> I'd make it "qcow2: Failed to update refcounts". It's the refcounts of
> all clusters referred to by the snapshot's L1 table, not of the snapshot
> itself.

Thanks for correction. I'm not that much familiar with qcow2 internals.

>
>> +        return;
>>       }
>>       qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t));
>>
>>       /* must update the copied flag on the current cluster offsets */
>>       ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
>>       if (ret < 0) {
>> -        return ret;
>> +        error_setg_errno(errp, -ret,
>> +                         "qcow2: failed to update snapshot refcount");
>
> "qcow2: Failed to update cluster flags"

Again thanks for correction.

>
>> +        return;
>>       }
>>
>>   #ifdef DEBUG_ALLOC
>> @@ -583,7 +593,6 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
>>           qcow2_check_refcounts(bs, &result, 0);
>>       }
>>   #endif
>> -    return 0;
>>   }
>>
>>   int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
>> diff --git a/block/qcow2.h b/block/qcow2.h
>> index 9421843..dbd332d 100644
>> --- a/block/qcow2.h
>> +++ b/block/qcow2.h
>> @@ -384,7 +384,9 @@ int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
>>   /* qcow2-snapshot.c functions */
>>   int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
>>   int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
>> -int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
>> +void qcow2_snapshot_delete(BlockDriverState *bs,
>> +                           const char *snapshot_id,
>> +                           Error **errp);
>>   int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
>>   int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name);
>>
>> diff --git a/block/rbd.c b/block/rbd.c
>> index 141b488..c10edbf 100644
>> --- a/block/rbd.c
>> +++ b/block/rbd.c
>> @@ -871,14 +871,19 @@ static int qemu_rbd_snap_create(BlockDriverState *bs,
>>       return 0;
>>   }
>>
>> -static int qemu_rbd_snap_remove(BlockDriverState *bs,
>> -                                const char *snapshot_name)
>> +static void qemu_rbd_snap_remove(BlockDriverState *bs,
>> +                                 const char *snapshot_name,
>> +                                 Error **errp)
>>   {
>>       BDRVRBDState *s = bs->opaque;
>>       int r;
>>
>>       r = rbd_snap_remove(s->image, snapshot_name);
>> -    return r;
>> +    if (r < 0) {
>> +        error_setg_errno(errp, -r, "rbd: failed to remove snapshot '%s' on "
>> +                         "device '%s'", snapshot_name,
>> +                         bdrv_get_device_name(bs));
>
> Remove the device name. You didn't have it in the qcow2 errors either.

Or maybe I should also add the device name in the qcow2 errors, because 
as Eric write to you these function are used also for vm-snapshot-delete 
and devlm and knowing which device failed is important.

>
>> +    }
>>   }
>>
>>   static int qemu_rbd_snap_rollback(BlockDriverState *bs,
>> diff --git a/block/sheepdog.c b/block/sheepdog.c
>> index 1c5b532..270fa64 100644
>> --- a/block/sheepdog.c
>> +++ b/block/sheepdog.c
>> @@ -1908,10 +1908,12 @@ out:
>>       return ret;
>>   }
>>
---
>> diff --git a/savevm.c b/savevm.c
>> index 53515cb..6af84fd 100644
>> --- a/savevm.c
>> +++ b/savevm.c
>> @@ -2225,18 +2225,17 @@ static int del_existing_snapshots(Monitor *mon, const char *name)
>>   {
>>       BlockDriverState *bs;
>>       QEMUSnapshotInfo sn1, *snapshot = &sn1;
>> -    int ret;
>> +    Error *local_err = NULL;
>>
>>       bs = NULL;
>>       while ((bs = bdrv_next(bs))) {
>>           if (bdrv_can_snapshot(bs) &&
>>               bdrv_snapshot_find(bs, snapshot, name) >= 0)
>>           {
>> -            ret = bdrv_snapshot_delete(bs, name);
>> -            if (ret < 0) {
>> -                monitor_printf(mon,
>> -                               "Error while deleting snapshot on '%s'\n",
>> -                               bdrv_get_device_name(bs));
>> +            bdrv_snapshot_delete(bs, name, &local_err);
>> +            if (error_is_set(&local_err)) {
>> +                monitor_printf(mon, "%s\n", error_get_pretty(local_err));
>
> Here the additional monitor_printf() actually had meaningful additional
> information. Deleting an old snapshot is an implicitly taken action and
> not explicitly requested, so an error message should indicate that it
> happened during the deletion. Maybe something like:

Function del_existing_snapshots will be anyway dropped later in patch 
series so this has no actual value. But I should probably make something 
similar to this for HMP command savevm.

Thanks

>
> qerror_report(ERROR_CLASS_GENERIC_ERROR,
>                "Error while deleting old snapshot on device '%s': %s",
>                bdrv_get_device_name(bs), error_get_pretty(local_err));
>
>> +                error_free(local_err);
>>                   return -1;
>>               }
>>           }
>> @@ -2450,7 +2449,7 @@ int load_vmstate(const char *name)
>>   void do_delvm(Monitor *mon, const QDict *qdict)
>>   {
>>       BlockDriverState *bs, *bs1;
>> -    int ret;
>> +    Error *local_err = NULL;
>>       const char *name = qdict_get_str(qdict, "name");
>>
>>       bs = bdrv_snapshots();
>> @@ -2462,15 +2461,10 @@ void do_delvm(Monitor *mon, const QDict *qdict)
>>       bs1 = NULL;
>>       while ((bs1 = bdrv_next(bs1))) {
>>           if (bdrv_can_snapshot(bs1)) {
>> -            ret = bdrv_snapshot_delete(bs1, name);
>> -            if (ret < 0) {
>> -                if (ret == -ENOTSUP)
>> -                    monitor_printf(mon,
>> -                                   "Snapshots not supported on device '%s'\n",
>> -                                   bdrv_get_device_name(bs1));
>> -                else
>> -                    monitor_printf(mon, "Error %d while deleting snapshot on "
>> -                                   "'%s'\n", ret, bdrv_get_device_name(bs1));
>> +            bdrv_snapshot_delete(bs1, name, &local_err);
>> +            if (error_is_set(&local_err)) {
>> +                monitor_printf(mon, "%s\n", error_get_pretty(local_err));
>
> Either something like above, indicating the device name on which
> bdrv_snapshot_delete() failed, or qerror_report_err().

Like I wrote few lines above, I should add the device name into all 
errors also in qcow2, rbd and sheepdog. This also applies for 
bdrv_snapshot_goto/create/list.

Pavel

>
>> +                error_free(local_err);
>>               }
>>           }
>>       }
>
> Kevin
>

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 04/11] qapi: Convert delvm
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 04/11] qapi: Convert delvm Pavel Hrdina
  2013-04-16 19:39   ` Eric Blake
@ 2013-04-18 13:28   ` Kevin Wolf
  1 sibling, 0 replies; 48+ messages in thread
From: Kevin Wolf @ 2013-04-18 13:28 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
> QMP command vm-snapshot-delete no takes two parameters name and id. They are
> optional, but one of the name or id must be provided. If both are provided they
> will match only the snapshot with the same name and id. The command returns
> SnapshotInfo only if the snapshot exists, if snapshot doesn't exist it returns
> nothing. If something goes wrong, it returns an error message.
> 
> HMP command delvm now uses the new vm-snapshot-delete, but behave slightly
> different. The delvm takes one optional flag -i and one parameter name. If you
> provide only the name parameter, it will match only snapshots with that name.
> If you also provide the flag, it will match only snapshots with name as id.
> Information about successfully deleted snapshot will be printed, if there is no
> snapshot with that name or id, the appropriate message will be printed. If
> something goes wrong, an error message will be printed.
> 
> These improves behavior of the command to be more strict on selecting snapshots
> because actual behavior is wrong. Now if you want to delete snapshot with name '2'
> but there is no snapshot with that name it could delete snapshot with id '2' and
> that isn't what you want.
> 
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> ---
>  hmp-commands.hx         | 14 ++++++++------
>  hmp.c                   | 35 ++++++++++++++++++++++++++++++++++
>  hmp.h                   |  1 +
>  include/sysemu/sysemu.h |  1 -
>  qapi-schema.json        | 17 +++++++++++++++++
>  qmp-commands.hx         | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  savevm.c                | 49 +++++++++++++++++++++++++++++++++++-------------
>  7 files changed, 146 insertions(+), 21 deletions(-)
> 
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index df44906..d1701ce 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -339,16 +339,18 @@ ETEXI
>  
>      {
>          .name       = "delvm",
> -        .args_type  = "name:s",
> -        .params     = "tag|id",
> -        .help       = "delete a VM snapshot from its tag or id",
> -        .mhandler.cmd = do_delvm,
> +        .args_type  = "id:-i,name:s",
> +        .params     = "[-i] tag|[id]",

This is a weird syntax description. I think I'd write it like this:
"tag|-i id"

> +        .help       = "delete a VM snapshot from its tag or id if -i flag is provided",
> +        .mhandler.cmd = hmp_vm_snapshot_delete,
>      },
>  
>  STEXI
> -@item delvm @var{tag}|@var{id}
> +@item delvm [-i] @var{tag}|[@var{id}]
>  @findex delvm
> -Delete the snapshot identified by @var{tag} or @var{id}.
> +Delete a snapshot identified by @var{tag}. If flag -i is provided, delete
> +a snapshot indentified by @var{id}.
> +
>  ETEXI
>  
>      {
> diff --git a/hmp.c b/hmp.c
> index 4fb76ec..2c754b3 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -1425,3 +1425,38 @@ void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
>      qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err);
>      hmp_handle_error(mon, &local_err);
>  }
> +
> +void hmp_vm_snapshot_delete(Monitor *mon, const QDict *qdict)
> +{
> +    const char *name = qdict_get_try_str(qdict, "name");
> +    const bool id = qdict_get_try_bool(qdict, "id", false);
> +    Error *local_err = NULL;
> +    SnapshotInfo *info;
> +
> +    if (id) {
> +        info = qmp_vm_snapshot_delete(false, NULL, true, name, &local_err);
> +    } else {
> +        info = qmp_vm_snapshot_delete(true, name, false, NULL, &local_err);
> +    }
> +
> +    if (info) {
> +        char buf[256];
> +        QEMUSnapshotInfo sn = {
> +            .vm_state_size = info->vm_state_size,
> +            .date_sec = info->date_sec,
> +            .date_nsec = info->date_nsec,
> +            .vm_clock_nsec = info->vm_clock_sec * 1000000000 +
> +                             info->vm_clock_nsec,
> +        };
> +        pstrcpy(sn.id_str, sizeof(sn.id_str), info->id);
> +        pstrcpy(sn.name, sizeof(sn.name), info->name);
> +        monitor_printf(mon, "Deleted snapshot info:\n");
> +        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
> +        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), &sn));
> +    } else if (!error_is_set(&local_err)) {
> +        monitor_printf(mon, "Snapshot '%s' not found.\n", name);
> +    }

Why isn't an error set when trying to delete a snapshot that doesn't
exist?

> +
> +    qapi_free_SnapshotInfo(info);
> +    hmp_handle_error(mon, &local_err);
> +}
> diff --git a/hmp.h b/hmp.h
> index 95fe76e..b0667b3 100644
> --- a/hmp.h
> +++ b/hmp.h
> @@ -85,5 +85,6 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
>  void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
>  void hmp_chardev_add(Monitor *mon, const QDict *qdict);
>  void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
> +void hmp_vm_snapshot_delete(Monitor *mon, const QDict *qdict);
>  
>  #endif
> diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
> index 6578782..f46f9d2 100644
> --- a/include/sysemu/sysemu.h
> +++ b/include/sysemu/sysemu.h
> @@ -67,7 +67,6 @@ void qemu_add_machine_init_done_notifier(Notifier *notify);
>  
>  void do_savevm(Monitor *mon, const QDict *qdict);
>  int load_vmstate(const char *name);
> -void do_delvm(Monitor *mon, const QDict *qdict);
>  void do_info_snapshots(Monitor *mon, const QDict *qdict);
>  
>  void qemu_announce_self(void);
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 751d3c2..641f3ac 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -3505,3 +3505,20 @@
>      '*asl_compiler_rev':  'uint32',
>      '*file':              'str',
>      '*data':              'str' }}
> +
> +##
> +# @vm-snapshot-delete:
> +#
> +# Delete a snapshot identified by name or id or both. One of the name or id
> +# is required. It will returns SnapshotInfo of successfully deleted snapshot.
> +#
> +# @name: tag of an existing snapshot
> +#
> +# @id: id of an existing snapshot
> +#
> +# Returns: SnapshotInfo on success
> +#
> +# Since: 1.5
> +##
> +{ 'command': 'vm-snapshot-delete', 'data': {'*name': 'str', '*id': 'str'},
> +  'returns': 'SnapshotInfo' }
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index 4d65422..86f399d 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -1419,7 +1419,55 @@ Example:
>  
>  -> { "execute": "add_client", "arguments": { "protocol": "vnc",
>                                               "fdname": "myclient" } }
> -<- { "return": {} }
> +<- {
> +      "return": {
> +         "id": "1",
> +         "name": "my_snapshot",
> +         "date-sec": 1364480534,
> +         "date-nsec": 978215000,
> +         "vm-clock-sec": 5,
> +         "vm-clock-nsec": 153620449,
> +        "vm-state-size": 5709953
> +      }
> +   }
> +
> +EQMP
> +    {
> +        .name       = "vm-snapshot-delete",
> +        .args_type  = "name:s?,id:s?",
> +        .params     = "[tag] [id]",
> +        .help       = "delete a VM snapshot from its tag or id",
> +        .mhandler.cmd_new = qmp_marshal_input_vm_snapshot_delete
> +    },
> +
> +SQMP
> +vm-snapshot-delete
> +------
> +
> +Delete a snapshot identified by name or id or both. One of the name or id
> +is required. It will returns SnapshotInfo of successfully deleted snapshot.
> +
> +Arguments:
> +
> +- "name": tag of an existing snapshot (json-string, optional)
> +
> +- "id": id of an existing snapshot (json-string, optional)
> +
> +Example:
> +
> +-> { "execute": "vm-snapshot-delete", "arguments": { "name": "my_snapshot" } }
> +<- {
> +      "return": {
> +         "id": "1",
> +         "name": "my_snapshot",
> +         "date-sec": 1364480534,
> +         "date-nsec": 978215000,
> +         "vm-clock-sec": 5,
> +         "vm-clock-nsec": 153620449,
> +         "vm-state-size": 5709953
> +      }
> +   }
> +
>  
>  EQMP
>      {
> diff --git a/savevm.c b/savevm.c
> index 96a2340..4af7d2d 100644
> --- a/savevm.c
> +++ b/savevm.c
> @@ -2473,28 +2473,51 @@ int load_vmstate(const char *name)
>      return 0;
>  }
>  
> -void do_delvm(Monitor *mon, const QDict *qdict)
> +SnapshotInfo *qmp_vm_snapshot_delete(const bool has_name, const char *name,
> +                                     const bool has_id, const char *id,
> +                                     Error **errp)
>  {
> -    BlockDriverState *bs, *bs1;
> -    Error *local_err = NULL;
> -    const char *name = qdict_get_str(qdict, "name");
> +    BlockDriverState *bs;
> +    SnapshotInfo *info = NULL;
> +    QEMUSnapshotInfo sn;
> +
> +    if (!has_name && !has_id) {
> +        error_setg(errp, "name or id must be provided");
> +        return NULL;
> +    }
>  
>      bs = bdrv_snapshots();
>      if (!bs) {
> -        monitor_printf(mon, "No block device supports snapshots\n");
> -        return;
> +        error_setg(errp, "no block device supports snapshots");

Please leave a capital N at the start of the message.

> +        return NULL;
>      }
>  
> -    bs1 = NULL;
> -    while ((bs1 = bdrv_next(bs1))) {
> -        if (bdrv_can_snapshot(bs1)) {
> -            bdrv_snapshot_delete(bs1, name, &local_err);
> -            if (error_is_set(&local_err)) {
> -                monitor_printf(mon, "%s\n", error_get_pretty(local_err));
> -                error_free(local_err);
> +    if (!bdrv_snapshot_find(bs, &sn, name, id, false)) {
> +        /* no need to set an error if snapshot doesn't exist */
> +        return NULL;
> +    }

Is it even allowed in QMP that you return NULL without setting an error?
What would the JSON response look like?

> +
> +    info = g_malloc0(sizeof(SnapshotInfo));
> +    info->id = g_strdup(sn.id_str);
> +    info->name = g_strdup(sn.name);
> +    info->date_nsec = sn.date_nsec;
> +    info->date_sec = sn.date_sec;
> +    info->vm_state_size = sn.vm_state_size;
> +    info->vm_clock_nsec = sn.vm_clock_nsec % 1000000000;
> +    info->vm_clock_sec = sn.vm_clock_nsec / 1000000000;
> +
> +    bs = NULL;
> +    while ((bs = bdrv_next(bs))) {
> +        if (bdrv_can_snapshot(bs)
> +                && bdrv_snapshot_find(bs, &sn, name, id, false)) {
> +            bdrv_snapshot_delete(bs, sn.name, errp);
> +            if (error_is_set(errp)) {

You need to use a local_err, the caller could have passed a NULL errp,
and then you wouldn't detect the error here.

> +                return NULL;
>              }
>          }
>      }
> +
> +    return info;
>  }

Kevin

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 02/11] block: update error reporting for bdrv_snapshot_delete() and related functions
  2013-04-18 13:19     ` Pavel Hrdina
@ 2013-04-18 13:41       ` Kevin Wolf
  0 siblings, 0 replies; 48+ messages in thread
From: Kevin Wolf @ 2013-04-18 13:41 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

Am 18.04.2013 um 15:19 hat Pavel Hrdina geschrieben:
> On 18.4.2013 14:55, Kevin Wolf wrote:
> >Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
> >>--- a/block/rbd.c
> >>+++ b/block/rbd.c
> >>@@ -871,14 +871,19 @@ static int qemu_rbd_snap_create(BlockDriverState *bs,
> >>      return 0;
> >>  }
> >>
> >>-static int qemu_rbd_snap_remove(BlockDriverState *bs,
> >>-                                const char *snapshot_name)
> >>+static void qemu_rbd_snap_remove(BlockDriverState *bs,
> >>+                                 const char *snapshot_name,
> >>+                                 Error **errp)
> >>  {
> >>      BDRVRBDState *s = bs->opaque;
> >>      int r;
> >>
> >>      r = rbd_snap_remove(s->image, snapshot_name);
> >>-    return r;
> >>+    if (r < 0) {
> >>+        error_setg_errno(errp, -r, "rbd: failed to remove snapshot '%s' on "
> >>+                         "device '%s'", snapshot_name,
> >>+                         bdrv_get_device_name(bs));
> >
> >Remove the device name. You didn't have it in the qcow2 errors either.
> 
> Or maybe I should also add the device name in the qcow2 errors,
> because as Eric write to you these function are used also for
> vm-snapshot-delete and devlm and knowing which device failed is
> important.

I don't think it's the right approach to let the lowest layer add all
information that is potentially useful in some contexts. It should only
consider what information is essential for its direct caller.

You are right that in delvm multiple devices can be affected. This is
why delvm should amend the error message with any information that is
required for the error message to be helpful in the context of delvm.
This is essentially what I suggested here:

> >>@@ -2225,18 +2225,17 @@ static int del_existing_snapshots(Monitor *mon, const char *name)
> >>  {
> >>      BlockDriverState *bs;
> >>      QEMUSnapshotInfo sn1, *snapshot = &sn1;
> >>-    int ret;
> >>+    Error *local_err = NULL;
> >>
> >>      bs = NULL;
> >>      while ((bs = bdrv_next(bs))) {
> >>          if (bdrv_can_snapshot(bs) &&
> >>              bdrv_snapshot_find(bs, snapshot, name) >= 0)
> >>          {
> >>-            ret = bdrv_snapshot_delete(bs, name);
> >>-            if (ret < 0) {
> >>-                monitor_printf(mon,
> >>-                               "Error while deleting snapshot on '%s'\n",
> >>-                               bdrv_get_device_name(bs));
> >>+            bdrv_snapshot_delete(bs, name, &local_err);
> >>+            if (error_is_set(&local_err)) {
> >>+                monitor_printf(mon, "%s\n", error_get_pretty(local_err));
> >
> >Here the additional monitor_printf() actually had meaningful additional
> >information. Deleting an old snapshot is an implicitly taken action and
> >not explicitly requested, so an error message should indicate that it
> >happened during the deletion. Maybe something like:
> 
> Function del_existing_snapshots will be anyway dropped later in
> patch series so this has no actual value. But I should probably make
> something similar to this for HMP command savevm.
> 
> Thanks
> 
> >
> >qerror_report(ERROR_CLASS_GENERIC_ERROR,
> >               "Error while deleting old snapshot on device '%s': %s",
> >               bdrv_get_device_name(bs), error_get_pretty(local_err));

See how I added the device name and the context of the error ("while
deleteing the old snapshot") only in the place where it's actually
necessary for the caller to understand the error?

By the way, I'm also unsure if the "qcow2:" or "rbd:" prefix is actually
helpful.

Kevin

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 02/11] block: update error reporting for bdrv_snapshot_delete() and related functions
  2013-04-18 13:09     ` Eric Blake
@ 2013-04-18 13:51       ` Kevin Wolf
  0 siblings, 0 replies; 48+ messages in thread
From: Kevin Wolf @ 2013-04-18 13:51 UTC (permalink / raw)
  To: Eric Blake; +Cc: armbru, Pavel Hrdina, qemu-devel, lcapitulino

Am 18.04.2013 um 15:09 hat Eric Blake geschrieben:
> On 04/18/2013 06:55 AM, Kevin Wolf wrote:
> > Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
> >>
> >> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> >> ---
> >>  
> >> -int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
> >> +void bdrv_snapshot_delete(BlockDriverState *bs,
> >> +                          const char *snapshot_id,
> >> +                          Error **errp)
> >>  {
> >>      BlockDriver *drv = bs->drv;
> >> -    if (!drv)
> >> -        return -ENOMEDIUM;
> >> -    if (drv->bdrv_snapshot_delete)
> >> -        return drv->bdrv_snapshot_delete(bs, snapshot_id);
> >> -    if (bs->file)
> >> -        return bdrv_snapshot_delete(bs->file, snapshot_id);
> >> -    return -ENOTSUP;
> >> +
> >> +    if (!drv) {
> >> +        error_setg(errp, "device '%s' has no medium", bdrv_get_device_name(bs));
> > 
> > I don't think the device name is useful here. It's always the device
> > that the user has specified in the monitor command.
> 
> Huh?  We're talking about vm-snapshot-delete, which removes the snapshot
> for multiple devices at a time.  Knowing _which_ device failed is
> important in the context of a command where you don't specify a device name.

No, we're talking about bdrv_snapshot_delete(). Talking about
vm-snapshot-delete in this patch would be a layering violation.

If it's important for vm-snapshot-delete to have the device name in the
error message (and I agree it is when deleting multiple snapshots), then
qmp_vm_snapshot_delete() should add that information.

> > 
> > Also, please start error messages with a capital letter. (This applies
> > to the whole patch, and probably also other patches in this series)
> 
> Qemu is inconsistent on this front.  The code base actually favors lower
> case at the moment:
> 
> $ git grep 'error_setg.*"[a-z]' | wc
>     119     957   10361
> $ git grep 'error_setg.*"[A-Z]' | wc
>      60     510    4996
> 
> Monitor output, on the other hand, favor uppercase:
> 
> $ git grep 'monitor_pr.*"[A-Z]' | wc
>      88     576    6611
> $ git grep 'monitor_pr.*"[a-z]' | wc
>     108     789    8566

If you don't pipe it through wc but look at the output, you'll see that
many of these start with a lower case device, module or parameter
name, which of course wouldn't be right with upper case.

So far I think the block layer messages are pretty consistently upper
case where it makes sense.

Kevin

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error()
  2013-04-18 13:09         ` Pavel Hrdina
@ 2013-04-18 15:23           ` Luiz Capitulino
  0 siblings, 0 replies; 48+ messages in thread
From: Luiz Capitulino @ 2013-04-18 15:23 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: Kevin Wolf, qemu-devel, armbru

On Thu, 18 Apr 2013 15:09:27 +0200
Pavel Hrdina <phrdina@redhat.com> wrote:

> On 18.4.2013 14:59, Kevin Wolf wrote:
> > Am 18.04.2013 um 13:52 hat Pavel Hrdina geschrieben:
> >> On 18.4.2013 13:44, Kevin Wolf wrote:
> >>> Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
> >>>> Later in the patch series we will use this function few times.
> >>>> This will avoid of duplicating the code.
> >>>>
> >>>> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
> >>>> ---
> >>>>   qemu-img.c | 17 +++++++++++------
> >>>>   1 file changed, 11 insertions(+), 6 deletions(-)
> >>>>
> >>>> diff --git a/qemu-img.c b/qemu-img.c
> >>>> index 31627b0..dbacdb7 100644
> >>>> --- a/qemu-img.c
> >>>> +++ b/qemu-img.c
> >>>> @@ -322,6 +322,16 @@ static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
> >>>>       return 0;
> >>>>   }
> >>>>
> >>>> +static int qemu_img_handle_error(const char *msg, Error *err)
> >>>> +{
> >>>> +    if (error_is_set(&err)) {
> >>>> +        error_report("%s: %s", msg, error_get_pretty(err));
> >>>> +        error_free(err);
> >>>> +        return 1;
> >>>> +    }
> >>>> +    return 0;
> >>>> +}
> >>>> +
> >>>>   static int img_create(int argc, char **argv)
> >>>>   {
> >>>>       int c;
> >>>> @@ -400,13 +410,8 @@ static int img_create(int argc, char **argv)
> >>>>
> >>>>       bdrv_img_create(filename, fmt, base_filename, base_fmt,
> >>>>                       options, img_size, BDRV_O_FLAGS, &local_err, quiet);
> >>>> -    if (error_is_set(&local_err)) {
> >>>> -        error_report("%s", error_get_pretty(local_err));
> >>>> -        error_free(local_err);
> >>>> -        return 1;
> >>>> -    }
> >>>>
> >>>> -    return 0;
> >>>> +    return qemu_img_handle_error("qemu-img create failed", local_err);
> >>>>   }
> >>>
> >>> This makes a change to the error message that isn't mentioned in the
> >>> commit message. It should definitely be mentioned there, but I'm not
> >>> even sure if it's a good change. Today you get something like:
> >>>
> >>>      $ qemu-img create -f foo test.img
> >>>      qemu-img: Unknown file format 'foo'
> >>>
> >>> With the patch applied it becomes:
> >>>
> >>>      $ qemu-img create -f foo test.img
> >>>      qemu-img: qemu-img create failed: Unknown file format 'foo'
> >>>
> >>> Does this add any useful information or does it just make the error
> >>> message longer? I feel it's the latter.
> >>>
> >>> Kevin
> >>>
> >>
> >> Thanks for pointing this out, it should be
> >> qemu_img_handle_error("create failed", local_err);
> >>
> >> and later in patch series also
> >> qemu_img_handle_error("snapshot create failed", local_err);
> >>
> >> Is that OK after this change?
> >
> > I would in fact leave the error message as it is today. The "create
> > failed" doesn't help me understand the error better. I already know that
> > it's a create command that failed, because it was me who called 'qemu-img
> > create'.
> >
> > Kevin
> >
> 
> Yes that's true and make sense, but what if another tool internally uses 
> the qemu-img command? I know that the tool could print/return/whatever 
> proper error message, but qemu-img could help with that printing more 
> information.

Then the tool should prepend any relevant information. We can't guess
all use cases.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-18 10:22               ` Pavel Hrdina
@ 2013-04-19  0:28                 ` Wenchao Xia
  2013-04-24  3:51                   ` Wenchao Xia
  0 siblings, 1 reply; 48+ messages in thread
From: Wenchao Xia @ 2013-04-19  0:28 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: armbru, qemu-devel, lcapitulino

于 2013-4-18 18:22, Pavel Hrdina 写道:
> On 18.4.2013 06:31, Wenchao Xia wrote:
>> 于 2013-4-18 2:14, Eric Blake 写道:
>>> On 04/17/2013 04:51 AM, Pavel Hrdina wrote:
>>>> On 17.4.2013 12:19, Wenchao Xia wrote:
>>>>> 于 2013-4-17 15:52, Pavel Hrdina 写道:
>>>>>> Hi Wenchao,
>>>>>>
>>>>>> unfortunately no. According to new design of savevm, loadvm and
>>>>>> delvm I
>>>>>> need also search for snapshots that have the specified name and id.
>>>>>>
>>>>>     It seems the logic in your function, is same with mine...
>>>>
>>>> It is not the same.
>>>
>>> Consider a qcow2 file with the following snapshots:
>>>
>>>       id     tag
>>>       1      2
>>>       2      1
>>>       3      none
>>>
>>> Existing logic:
>>>
>>> only one string is passed, and only one loop is performed.  If it
>>> matches id or name, end searching
>>>
>>> search for 1 - finds id 1 tag 2
>>> search for 2 - finds id 1 tag 2
>>> search for 3 - finds id 3 no tag
>>> search for 4 - finds nothing
>>>
>>> no way to find id 2 tag 1
>>>
>>> The last point proves that the current algorithm is not ideal, and that
>>> we are justified in changing it.  But there are several ways to change
>>> it, and a consideration of whether we should preserve backwards
>>> compatibility in HMP by making the search itself have backwards
>>> compatibility, or by making the QMP search follow strict rules where HMP
>>> can emulate some measure of back-compat by calling into QMP more than
>>> once.
>>>
>>>>
>>>> Your logic:
>>> [Wenchao]
>>>>      if id is set:
>>>>          if there is snapshot with that id:
>>>>              end searching
>>>>      if name set (search also if id is set but nothing found):
>>>>          if there is snapshot with that name:
>>>>              end searching
>>>>
>>>> My logic:
>>> [Pavel]
>>>>      if name is set and id is set:
>>>>          if there is snapshot with than name and with that id:
>>>>              end searching
>>>>      else if name is set (means that only name is set):
>>>>          if there is snapshot with that name:
>>>>              end searching
>>>>      else if id is set (means that only id is set):
>>>>          if there is snapshot with that id:
>>>>              end searching
>>>
>>> Best is a side-by-side comparison; when comparing to existing, I showed
>>> three different choices of expanding a single name into a two-argument
>>> find call.
>>>
>>>   search for:            finds                compared to
>>>    id     name     Wenchao       Pavel          existing
>>>                                                name -> find(id, NULL)
>>>    1      NULL    id 1 tag 2    id 1 tag 2    id 1 tag 2
>>> * 2      NULL    id 2 tag 1    id 2 tag 1    id 1 tag 2
>>>    3      NULL    id 3 no tag   id 3 no tag   id 3 no tag
>>>    4      NULL    nothing       nothing       nothing
>>>                                                name -> find(NULL, tag)
>>> * NULL   1       id 2 tag 1    id 2 tag 1    id 1 tag 2
>>>    NULL   2       id 1 tag 2    id 1 tag 2    id 1 tag 2
>>> * NULL   3       nothing       nothing       id 3 no tag
>>>    NULL   4       nothing       nothing       nothing
>>>                                                not possible
>>>    1      2       id 1 tag 2    id 1 tag 2    --
>>>    2      1       id 2 tag 1    id 2 tag 1    --
>>>                                                name -> find(id, tag)
>>> * 1      1       id 1 tag 2    nothing       id 1 tag 2
>>> * 2      2       id 2 tag 1    nothing       id 1 tag 2
>>> * 3      3       id 3 no tag   nothing       id 3 no tag
>>>    4      4       nothing       nothing       nothing
>>>
>>> The two proposed approaches both allow access to a lookup that the
>>> original could not provide (namely, id 2 tag 1), so they are an
>>> improvement on that front.  But the two approaches differ on behavior
>>> when both id and name are specified (Wenchao's behaves the same as an
>>> id-only lookup, regardless of whether the name matches; Pavel's requires
>>> a double match).  The other thing to note is that the old code allowed a
>>> single name to match an anonymous snapshot, but both proposals fail to
>>> find a nameless snapshot without an id search.
>>>
>>> Can I put yet another proposed algorithm on the table?  First, written
>>> with four loops over the source (although at most two are taken):
>>>
>>>      if name is set and id is set:
>>>          if there is snapshot with than name and with that id (loop 1):
>>>              end searching
>>>      else if name is set (means that only name is set):
>>>          if there is snapshot with that name (loop 2):
>>>              end searching
>>>          if there is snapshot with that id (loop 3):
>>>              end searching
>>>      else if id is set (means that only id is set):
>>>          if there is snapshot with that id (loop 4):
>>>              end searching
>>>
>>> Or, written another way, to implement the same results in only two coded
>>> loops:
>>>
>>>      if name is set:
>>>          if there is a snapshot with that name (loop 1):
>>>              if id is set:
>>>                  if id matches:
>>>                      end searching successfully
>>>                  else:
>>>                      fail
>>>              else:
>>>                  end searching successfully
>>>          else if id is not set:
>>>              set id to name
>>>      if there is a snapshot with id (loop 2):
>>>          end searching successfully
>>>
>>> And the resulting comparison table, again with three possibilities of
>>> how to convert one-argument lookup into two-argument:
>>>
>>>   search for:        finds      compared to
>>>    id     name     mine          existing
>>>                                  name -> find(id, NULL)
>>>    1      NULL    id 1 tag 2    id 1 tag 2
>>> * 2      NULL    id 2 tag 1    id 1 tag 2
>>>    3      NULL    id 3 no tag   id 3 no tag
>>>    4      NULL    nothing       nothing
>>>                                  name -> find(NULL, tag)
>>> * NULL   1       id 2 tag 1    id 1 tag 2
>>>    NULL   2       id 1 tag 2    id 1 tag 2
>>>    NULL   3       id 3 no tag   id 3 no tag
>>>    NULL   4       nothing       nothing
>>>                                  not possible
>>>    1      2       id 1 tag 2    --
>>>    2      1       id 2 tag 1    --
>>>                                  name -> find(id, tag)
>>> * 1      1       nothing       id 1 tag 2
>>> * 2      2       nothing       id 1 tag 2
>>> * 3      3       nothing       id 3 no tag
>>>    4      4       nothing       nothing
>>>
>>>
>>> With that adjusted table, I would favor converting any single name
>>> lookup into find(NULL, tag).  Only the new QMP command that lets us do
>>> an explicit id lookup can search for an id regardless of another name
>>> matching the id; but we at least have the benefit of being able to
>>> access ALL named snapshots (better than the original code unable to
>>> access tag 2), as well as the ability to access unambiguous ids without
>>> extra effort (ability to access id 3 without having to change the
>>> command line).  It keeps the aspect of Pavel's code that specifying both
>>> fields must match both fields, but otherwise favors names over ids
>>> (generally good, since names are generally not numeric, except when we
>>> are talking about corner cases).
>>>
>>> So, was I convincing enough in arguing that we want something different
>>> from the approach of both existing patch series?
>>>
>>    Plenty of details, thanks, Eric. I think Pavel's logic is better,
>> which increase the capability of it, and I don't think a more complex
>> logic should be there, since it is an internal function need clear
>> meaning.
>>
>
> I also thank you Eric for that detailed description. I must agree with
> Wenchao that internal function needs clear meaning. Why would I need to
> find snapshot by id using name parameter if I have the id parameter? I
> know that name is in almost all cases some string and not a number and
> that it could be for some cases easier just find snapshot by id using
> name parameter, but I think that we must be strict about this logic.
>
>>
>>>>
>>>>>
>>>>>> I'm also touching bdrv_snapshot_list where I'm adding an Error
>>>>>> parameter
>>>>>     I looked it before, but it needs all call back in ./block
>>>>> support it,
>>>>> so is it really necessary?
>>>>
>>>> I think it is better if this function internally set appropriate error
>>>> message based on used disk image format (qcow2, sheepdog, rbd).
>>>
>>> I like the idea of find() setting errp on lookup failure.  Callers can
>>> ignore errors in situations where a failed lookup triggers a reasonable
>>> fallback, but in case the caller wants to report an error, the lower
>>> down that we generate an error message, the more likely the error
>>> message is to contain full context rather than being dumbed down by
>>> generating it higher on the call stack.
>>>
>>    I understand it helps, but now I need just a good
>> bdrv_snapshot_find() to use, so could this improvement work
>> be postponded later? I think neither my or Pavel's work
>> is depending on it.
>>    Pavel, to make us progress, I'd like a small serial change
>> bdrv_snapshot_find() first, then we can rebase on it, are u OK
>> with it?
>>
>> block/qapi.c:
>> int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
>>                         const char *name, const char *id)
>>
>
> I think that my whole series is almost done and it would be quickly
> accepted and applied upstream. I'll send today the v2 and we will see.
>
> Pavel
>
   OK, I'll review v2 too to make it faster.

-- 
Best Regards

Wenchao Xia

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 05/11] block: update error reporting for bdrv_snapshot_goto() and related functions
  2013-04-16 16:05 ` [Qemu-devel] [PATCH 05/11] block: update error reporting for bdrv_snapshot_goto() and related functions Pavel Hrdina
  2013-04-16 20:48   ` Eric Blake
@ 2013-04-23 14:08   ` Kevin Wolf
  1 sibling, 0 replies; 48+ messages in thread
From: Kevin Wolf @ 2013-04-23 14:08 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, qemu-devel, armbru

Am 16.04.2013 um 18:05 hat Pavel Hrdina geschrieben:
> 
> Signed-off-by: Pavel Hrdina <phrdina@redhat.com>

Can you split this in two separate patches for goto and for list?

> ---
>  block.c                   | 55 ++++++++++++++++++++++++++---------------------
>  block/qcow2-snapshot.c    | 32 +++++++++++++++++++--------
>  block/qcow2.h             |  8 +++++--
>  block/rbd.c               | 19 +++++++++++-----
>  block/sheepdog.c          | 33 ++++++++++++++++------------
>  include/block/block.h     |  8 ++++---
>  include/block/block_int.h |  8 ++++---
>  qemu-img.c                | 20 ++++++++++-------
>  savevm.c                  | 21 ++++++++++--------
>  9 files changed, 127 insertions(+), 77 deletions(-)
> 
> diff --git a/block.c b/block.c
> index fb065e6..a760a2f 100644
> --- a/block.c
> +++ b/block.c
> @@ -3365,30 +3365,30 @@ int bdrv_snapshot_create(BlockDriverState *bs,
>      return -ENOTSUP;
>  }
>  
> -int bdrv_snapshot_goto(BlockDriverState *bs,
> -                       const char *snapshot_id)
> +void bdrv_snapshot_goto(BlockDriverState *bs,
> +                        const char *snapshot_id,
> +                        Error **errp)
>  {
>      BlockDriver *drv = bs->drv;
> -    int ret, open_ret;
> -
> -    if (!drv)
> -        return -ENOMEDIUM;
> -    if (drv->bdrv_snapshot_goto)
> -        return drv->bdrv_snapshot_goto(bs, snapshot_id);
> +    int ret;
>  
> -    if (bs->file) {
> +    if (!drv) {
> +        error_setg(errp, "device '%s' has no medium", bdrv_get_device_name(bs));

It would probably make sense to define a macro for this message because
it's the same thing for pretty much every block layer function.

And the usual comment about upper case and the device name not being
necessary here (won't repeat them everywhere).

> +    } else if (drv->bdrv_snapshot_goto) {
> +        drv->bdrv_snapshot_goto(bs, snapshot_id, errp);
> +    } else if (bs->file) {
>          drv->bdrv_close(bs);
> -        ret = bdrv_snapshot_goto(bs->file, snapshot_id);
> -        open_ret = drv->bdrv_open(bs, NULL, bs->open_flags);
> -        if (open_ret < 0) {
> +        bdrv_snapshot_goto(bs->file, snapshot_id, errp);
> +        ret = drv->bdrv_open(bs, NULL, bs->open_flags);
> +        if (ret < 0) {
>              bdrv_delete(bs->file);
>              bs->drv = NULL;
> -            return open_ret;
> +            error_setg(errp, "failed to open '%s'", bdrv_get_device_name(bs));

Use error_setg_errno() so that we don't lose information.

If both bdrv_snapshot_goto() and bdrv_open() fail, errp is already set
and you'll trigger an assertion here. You need to decide which of the
errors should take precedence.

>          }
> -        return ret;
> +    } else {
> +        error_setg(errp, "snapshots are not supported on device '%s'",
> +                           bdrv_get_device_name(bs));
>      }
> -
> -    return -ENOTSUP;
>  }
>  
>  void bdrv_snapshot_delete(BlockDriverState *bs,
> @@ -3410,16 +3410,23 @@ void bdrv_snapshot_delete(BlockDriverState *bs,
>  }
>  
>  int bdrv_snapshot_list(BlockDriverState *bs,
> -                       QEMUSnapshotInfo **psn_info)
> +                       QEMUSnapshotInfo **psn_info,
> +                       Error **errp)
>  {
>      BlockDriver *drv = bs->drv;
> -    if (!drv)
> -        return -ENOMEDIUM;
> -    if (drv->bdrv_snapshot_list)
> -        return drv->bdrv_snapshot_list(bs, psn_info);
> -    if (bs->file)
> -        return bdrv_snapshot_list(bs->file, psn_info);
> -    return -ENOTSUP;
> +
> +    if (!drv) {
> +        error_setg(errp, "device '%s' has no medium", bdrv_get_device_name(bs));
> +        return 0;
> +    } else if (drv->bdrv_snapshot_list) {
> +        return drv->bdrv_snapshot_list(bs, psn_info, errp);
> +    } else if (bs->file) {
> +        return bdrv_snapshot_list(bs->file, psn_info, errp);
> +    } else {
> +        error_setg(errp, "snapshots are not supported on device '%s'",
> +                   bdrv_get_device_name(bs));
> +        return 0;
> +    }
>  }
>  
>  int bdrv_snapshot_load_tmp(BlockDriverState *bs,
> diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
> index 2ebeadc..4a69b88 100644
> --- a/block/qcow2-snapshot.c
> +++ b/block/qcow2-snapshot.c
> @@ -417,7 +417,9 @@ fail:
>  }
>  
>  /* copy the snapshot 'snapshot_name' into the current disk image */
> -int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
> +void qcow2_snapshot_goto(BlockDriverState *bs,
> +                         const char *snapshot_id,
> +                         Error **errp)
>  {
>      BDRVQcowState *s = bs->opaque;
>      QCowSnapshot *sn;
> @@ -429,14 +431,15 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
>      /* Search the snapshot */
>      snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
>      if (snapshot_index < 0) {
> -        return -ENOENT;
> +        error_setg(errp, "qcow2: failed to find snapshot '%s' by id or name",
> +                   snapshot_id);
> +        return;
>      }
>      sn = &s->snapshots[snapshot_index];
>  
>      if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
> -        error_report("qcow2: Loading snapshots with different disk "
> -            "size is not implemented");
> -        ret = -ENOTSUP;
> +        error_setg(errp, "qcow2: loading snapshots with different disk size "
> +                   "is not implemented");
>          goto fail;
>      }
>  
> @@ -447,6 +450,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
>       */
>      ret = qcow2_grow_l1_table(bs, sn->l1_size, true);
>      if (ret < 0) {
> +        error_setg_errno(errp, -ret, "fqcow2: ailed to grow L1 table");

That 'f' isn't quite in the right place :-)

>          goto fail;
>      }
>  
> @@ -465,18 +469,23 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
>  
>      ret = bdrv_pread(bs->file, sn->l1_table_offset, sn_l1_table, sn_l1_bytes);
>      if (ret < 0) {
> +        error_setg_errno(errp, -ret,
> +                         "qcow2: failed to load data into L1 table");
>          goto fail;
>      }
>  
>      ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset,
>                                           sn->l1_size, 1);
>      if (ret < 0) {
> +        error_setg_errno(errp, -ret,
> +                         "qcow2: failed to update snapshot refcount");

"Failed to increase the cluster refcounts of the snapshot to load"

>          goto fail;
>      }
>  
>      ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, sn_l1_table,
>                             cur_l1_bytes);
>      if (ret < 0) {
> +        error_setg_errno(errp, -ret, "qcow2: failed to save L1 table");
>          goto fail;
>      }
>  
> @@ -502,6 +511,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
>      }
>  
>      if (ret < 0) {
> +        error_setg_errno(errp, -ret, "qcow2: failed to sync L1 table");

"Failed to decrease the cluster refcounts of the old snapshot"

>          goto fail;
>      }
>  
> @@ -514,6 +524,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
>       */
>      ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
>      if (ret < 0) {
> +        error_setg_errno(errp, -ret,
> +                         "qcow2: failed to update snapshot refcount");

"Failed to update the cluster flags"

>          goto fail;
>      }
>  
> @@ -523,11 +535,10 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
>          qcow2_check_refcounts(bs, &result, 0);
>      }
>  #endif
> -    return 0;
> +    return;
>  
>  fail:
>      g_free(sn_l1_table);
> -    return ret;
>  }
>  
>  void qcow2_snapshot_delete(BlockDriverState *bs,
> @@ -595,7 +606,9 @@ void qcow2_snapshot_delete(BlockDriverState *bs,
>  #endif
>  }
>  
> -int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
> +int qcow2_snapshot_list(BlockDriverState *bs,
> +                        QEMUSnapshotInfo **psn_tab,
> +                        Error **errp)
>  {
>      BDRVQcowState *s = bs->opaque;
>      QEMUSnapshotInfo *sn_tab, *sn_info;
> @@ -604,7 +617,8 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
>  
>      if (!s->nb_snapshots) {
>          *psn_tab = NULL;
> -        return s->nb_snapshots;
> +        error_setg(errp, "qcow2: there is no snapshot available");
> +        return 0;

Why is this an error condition?

>      }
>  
>      sn_tab = g_malloc0(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
> diff --git a/block/qcow2.h b/block/qcow2.h
> index dbd332d..ae62953 100644
> --- a/block/qcow2.h
> +++ b/block/qcow2.h
> @@ -383,11 +383,15 @@ int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
>  
>  /* qcow2-snapshot.c functions */
>  int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
> -int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
> +void qcow2_snapshot_goto(BlockDriverState *bs,
> +                         const char *snapshot_id,
> +                         Error **errp);
>  void qcow2_snapshot_delete(BlockDriverState *bs,
>                             const char *snapshot_id,
>                             Error **errp);
> -int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
> +int qcow2_snapshot_list(BlockDriverState *bs,
> +                        QEMUSnapshotInfo **psn_tab,
> +                        Error **errp);
>  int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name);
>  
>  void qcow2_free_snapshots(BlockDriverState *bs);
> diff --git a/block/rbd.c b/block/rbd.c
> index c10edbf..9259621 100644
> --- a/block/rbd.c
> +++ b/block/rbd.c
> @@ -886,18 +886,22 @@ static void qemu_rbd_snap_remove(BlockDriverState *bs,
>      }
>  }
>  
> -static int qemu_rbd_snap_rollback(BlockDriverState *bs,
> -                                  const char *snapshot_name)
> +static void qemu_rbd_snap_rollback(BlockDriverState *bs,
> +                                   const char *snapshot_name,
> +                                   Error **errp)
>  {
>      BDRVRBDState *s = bs->opaque;
>      int r;
>  
>      r = rbd_snap_rollback(s->image, snapshot_name);
> -    return r;
> +    if (r < 0) {
> +        error_setg_errno(errp, -r, "rbd: failed to rollback snapshot");
> +    }
>  }
>  
>  static int qemu_rbd_snap_list(BlockDriverState *bs,
> -                              QEMUSnapshotInfo **psn_tab)
> +                              QEMUSnapshotInfo **psn_tab,
> +                              Error **errp)
>  {
>      BDRVRBDState *s = bs->opaque;
>      QEMUSnapshotInfo *sn_info, *sn_tab = NULL;
> @@ -913,7 +917,12 @@ static int qemu_rbd_snap_list(BlockDriverState *bs,
>          }
>      } while (snap_count == -ERANGE);
>  
> -    if (snap_count <= 0) {
> +    if (snap_count < 0) {
> +        error_setg_errno(errp, -snap_count, "rbd: failed to find snapshots");

Here you don't have snap_count == 0 as an error condition, which makes
more sense to me. I think you should change qcow2.

> +        snap_count = 0;
> +    }
> +
> +    if (snap_count == 0) {
>          goto done;
>      }
>  
> diff --git a/block/sheepdog.c b/block/sheepdog.c
> index 270fa64..3d44575 100644
> --- a/block/sheepdog.c
> +++ b/block/sheepdog.c
> @@ -1838,7 +1838,9 @@ cleanup:
>      return ret;
>  }
>  
> -static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
> +static void sd_snapshot_goto(BlockDriverState *bs,
> +                             const char *snapshot_id,
> +                             Error **errp)
>  {
>      BDRVSheepdogState *s = bs->opaque;
>      BDRVSheepdogState *old_s;
> @@ -1863,12 +1865,14 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
>  
>      ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1);
>      if (ret) {
> -        error_report("Failed to find_vdi_name");
> +        error_setg_errno(errp, -ret, "sd: failed to find VDI snapshot '%s'",
> +                         vdi);
>          goto out;
>      }
>  
>      fd = connect_to_sdog(s);
>      if (fd < 0) {
> +        error_setg_errno(errp, -fd, "sd: failed to connect to sdog");
>          ret = fd;

It ret ever used after this assignment?

>          goto out;
>      }
> @@ -1880,14 +1884,15 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
>      closesocket(fd);
>  
>      if (ret) {
> +        error_setg_errno(errp, -ret, "sd: failed to open VDI snapshot '%s'",
> +                         vdi);
>          goto out;
>      }
>  
>      memcpy(&s->inode, buf, sizeof(s->inode));
>  
>      if (!s->inode.vm_state_size) {
> -        error_report("Invalid snapshot");
> -        ret = -ENOENT;
> +        error_setg(errp, "sd: invalid snapshot '%s'", snapshot_id);
>          goto out;
>      }
>  
> @@ -1896,16 +1901,12 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
>      g_free(buf);
>      g_free(old_s);
>  
> -    return 0;
> +    return;
>  out:
>      /* recover bdrv_sd_state */
>      memcpy(s, old_s, sizeof(BDRVSheepdogState));
>      g_free(buf);
>      g_free(old_s);
> -
> -    error_report("failed to open. recover old bdrv_sd_state.");
> -
> -    return ret;
>  }
>  
>  static void sd_snapshot_delete(BlockDriverState *bs,
> @@ -1916,11 +1917,13 @@ static void sd_snapshot_delete(BlockDriverState *bs,
>      return;
>  }
>  
> -static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
> +static int sd_snapshot_list(BlockDriverState *bs,
> +                            QEMUSnapshotInfo **psn_tab,
> +                            Error **errp)
>  {
>      BDRVSheepdogState *s = bs->opaque;
>      SheepdogReq req;
> -    int fd, nr = 1024, ret, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long);
> +    int fd, nr = 1024, ret = 0, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long);

This change has no effect. ret is overwritten with the return value of
do_req() before it's read.

>      QEMUSnapshotInfo *sn_tab = NULL;
>      unsigned wlen, rlen;
>      int found = 0;
> @@ -1934,7 +1937,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
>  
>      fd = connect_to_sdog(s);
>      if (fd < 0) {
> -        ret = fd;
> +        error_setg_errno(errp, -fd, "sd: failed to connect to sdog");

It's probably nicer to leave an explicit ret = 0 here, even if it
happens to always be 0 in this place anyway.

>          goto out;
>      }
>  
> @@ -1950,6 +1953,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
>  
>      closesocket(fd);
>      if (ret) {
> +        error_setg_errno(errp, -ret, "sd: failed to read VDIs");
>          goto out;
>      }
>  
> @@ -1961,7 +1965,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
>  
>      fd = connect_to_sdog(s);
>      if (fd < 0) {
> -        ret = fd;
> +        error_setg_errno(errp, -fd, "sd: failed to connect to sdog");
>          goto out;
>      }
>  
> @@ -2001,7 +2005,8 @@ out:
>      g_free(vdi_inuse);
>  
>      if (ret < 0) {
> -        return ret;
> +        error_setg_errno(errp, -ret, "sd: failed to read VDI object");
> +        return 0;
>      }
>  
>      return found;
> diff --git a/include/block/block.h b/include/block/block.h
> index db8c6aa..33d498b 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -335,13 +335,15 @@ int bdrv_is_snapshot(BlockDriverState *bs);
>  BlockDriverState *bdrv_snapshots(void);
>  int bdrv_snapshot_create(BlockDriverState *bs,
>                           QEMUSnapshotInfo *sn_info);
> -int bdrv_snapshot_goto(BlockDriverState *bs,
> -                       const char *snapshot_id);
> +void bdrv_snapshot_goto(BlockDriverState *bs,
> +                        const char *snapshot_id,
> +                        Error **errp);
>  void bdrv_snapshot_delete(BlockDriverState *bs,
>                            const char *snapshot_id,
>                            Error **errp);
>  int bdrv_snapshot_list(BlockDriverState *bs,
> -                       QEMUSnapshotInfo **psn_info);
> +                       QEMUSnapshotInfo **psn_info,
> +                       Error **errp);
>  int bdrv_snapshot_load_tmp(BlockDriverState *bs,
>                             const char *snapshot_name);
>  char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn);
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index 53c52bb..c56d923 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -155,13 +155,15 @@ struct BlockDriver {
>  
>      int (*bdrv_snapshot_create)(BlockDriverState *bs,
>                                  QEMUSnapshotInfo *sn_info);
> -    int (*bdrv_snapshot_goto)(BlockDriverState *bs,
> -                              const char *snapshot_id);
> +    void (*bdrv_snapshot_goto)(BlockDriverState *bs,
> +                               const char *snapshot_id,
> +                               Error **errp);
>      void (*bdrv_snapshot_delete)(BlockDriverState *bs,
>                                   const char *snapshot_id,
>                                   Error **errp);
>      int (*bdrv_snapshot_list)(BlockDriverState *bs,
> -                              QEMUSnapshotInfo **psn_info);
> +                              QEMUSnapshotInfo **psn_info,
> +                              Error **errp);
>      int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,
>                                    const char *snapshot_name);
>      int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
> diff --git a/qemu-img.c b/qemu-img.c
> index 4828fe4..06cd8af 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -1563,10 +1563,13 @@ static void dump_snapshots(BlockDriverState *bs)
>      QEMUSnapshotInfo *sn_tab, *sn;
>      int nb_sns, i;
>      char buf[256];
> +    Error *local_err = NULL;
>  
> -    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
> -    if (nb_sns <= 0)
> +    nb_sns = bdrv_snapshot_list(bs, &sn_tab, &local_err);
> +    if (qemu_img_handle_error("qemu-img dump snapshots failed", local_err)
> +            || nb_sns == 0) {
>          return;
> +    }
>      printf("Snapshot list:\n");
>      printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
>      for(i = 0; i < nb_sns; i++) {
> @@ -1598,7 +1601,10 @@ static void collect_snapshots(BlockDriverState *bs , ImageInfo *info)
>      int i, sn_count;
>      QEMUSnapshotInfo *sn_tab = NULL;
>      SnapshotInfoList *info_list, *cur_item = NULL;
> -    sn_count = bdrv_snapshot_list(bs, &sn_tab);
> +    Error *local_err = NULL;
> +    sn_count = bdrv_snapshot_list(bs, &sn_tab, &local_err);
> +
> +    qemu_img_handle_error("qemu-img collect snapshots failed", local_err);
>  
>      for (i = 0; i < sn_count; i++) {
>          info->has_snapshots = true;
> @@ -2026,11 +2032,9 @@ static int img_snapshot(int argc, char **argv)
>          break;
>  
>      case SNAPSHOT_APPLY:
> -        ret = bdrv_snapshot_goto(bs, snapshot_name);
> -        if (ret) {
> -            error_report("Could not apply snapshot '%s': %d (%s)",
> -                snapshot_name, ret, strerror(-ret));
> -        }
> +        bdrv_snapshot_goto(bs, snapshot_name, &local_err);
> +        ret = qemu_img_handle_error("qemu-img snapshot apply failed",
> +                                    local_err);
>          break;
>  
>      case SNAPSHOT_DELETE:
> diff --git a/savevm.c b/savevm.c
> index 4af7d2d..ca4a42e 100644
> --- a/savevm.c
> +++ b/savevm.c
> @@ -2206,7 +2206,7 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
>          return found;
>      }
>  
> -    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
> +    nb_sns = bdrv_snapshot_list(bs, &sn_tab, NULL);
>      if (nb_sns < 0) {
>          return found;
>      }
> @@ -2401,6 +2401,7 @@ int load_vmstate(const char *name)
>      QEMUSnapshotInfo sn;
>      QEMUFile *f;
>      int ret;
> +    Error *local_err;
>  
>      bs_vm_state = bdrv_snapshots();
>      if (!bs_vm_state) {
> @@ -2445,11 +2446,11 @@ int load_vmstate(const char *name)
>      bs = NULL;
>      while ((bs = bdrv_next(bs))) {
>          if (bdrv_can_snapshot(bs)) {
> -            ret = bdrv_snapshot_goto(bs, name);
> -            if (ret < 0) {
> -                error_report("Error %d while activating snapshot '%s' on '%s'",
> -                             ret, name, bdrv_get_device_name(bs));
> -                return ret;
> +            bdrv_snapshot_goto(bs, name, &local_err);
> +            if (error_is_set(&local_err)) {
> +                error_report("%s", error_get_pretty(local_err));

qerror_report_err()

> +                error_free(local_err);
> +                return -1;

Use some -errno code, and if it's only -EIO. If you don't choose one, it
becomes -EPERM in practice, which is confusing.

>              }
>          }
>      }
> @@ -2528,6 +2529,7 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
>      int total;
>      int *available_snapshots;
>      char buf[256];
> +    Error *local_err = NULL;
>  
>      bs = bdrv_snapshots();
>      if (!bs) {
> @@ -2535,9 +2537,10 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict)
>          return;
>      }
>  
> -    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
> -    if (nb_sns < 0) {
> -        monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
> +    nb_sns = bdrv_snapshot_list(bs, &sn_tab, &local_err);
> +    if (error_is_set(&local_err)) {
> +        monitor_printf(mon, "%s\n", error_get_pretty(local_err));

And another qerror_report_err().

> +        error_free(local_err);
>          return;
>      }

Kevin

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-19  0:28                 ` Wenchao Xia
@ 2013-04-24  3:51                   ` Wenchao Xia
  2013-04-24  9:37                     ` Pavel Hrdina
  0 siblings, 1 reply; 48+ messages in thread
From: Wenchao Xia @ 2013-04-24  3:51 UTC (permalink / raw)
  To: Pavel Hrdina; +Cc: lcapitulino, armbru, qemu-devel


>>
>> I think that my whole series is almost done and it would be quickly
>> accepted and applied upstream. I'll send today the v2 and we will see.
>>
>> Pavel
>>
>    OK, I'll review v2 too to make it faster.
>
Hi, Pavel
   Sorry for query your progress, I hope to catch up qemu 1.5, so
wonder whether V2 is ready.
   If you agree, I will use your logic in my bdrv_snapshot_find() to
progress. But still, if you can upstream your version quickly, or form
a clean patch for this function, I am happy to rebase on it.:>

-- 
Best Regards

Wenchao Xia

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find()
  2013-04-24  3:51                   ` Wenchao Xia
@ 2013-04-24  9:37                     ` Pavel Hrdina
  0 siblings, 0 replies; 48+ messages in thread
From: Pavel Hrdina @ 2013-04-24  9:37 UTC (permalink / raw)
  To: Wenchao Xia; +Cc: lcapitulino, armbru, qemu-devel

On 24.4.2013 05:51, Wenchao Xia wrote:
>
>>>
>>> I think that my whole series is almost done and it would be quickly
>>> accepted and applied upstream. I'll send today the v2 and we will see.
>>>
>>> Pavel
>>>
>>    OK, I'll review v2 too to make it faster.
>>
> Hi, Pavel
>    Sorry for query your progress, I hope to catch up qemu 1.5, so
> wonder whether V2 is ready.
>    If you agree, I will use your logic in my bdrv_snapshot_find() to
> progress. But still, if you can upstream your version quickly, or form
> a clean patch for this function, I am happy to rebase on it.:>
>

Hi Wenchao,

np, I have the v2 almost ready and today I'll send that v2 into upstream 
for review.

^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2013-04-24  9:37 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-04-16 16:05 [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Pavel Hrdina
2013-04-16 16:05 ` [Qemu-devel] [PATCH 01/11] qemu-img: introduce qemu_img_handle_error() Pavel Hrdina
2013-04-16 16:46   ` Eric Blake
2013-04-18 11:44   ` Kevin Wolf
2013-04-18 11:52     ` Pavel Hrdina
2013-04-18 12:59       ` Kevin Wolf
2013-04-18 13:09         ` Pavel Hrdina
2013-04-18 15:23           ` Luiz Capitulino
2013-04-16 16:05 ` [Qemu-devel] [PATCH 02/11] block: update error reporting for bdrv_snapshot_delete() and related functions Pavel Hrdina
2013-04-16 17:14   ` Eric Blake
2013-04-18 12:55   ` Kevin Wolf
2013-04-18 13:09     ` Eric Blake
2013-04-18 13:51       ` Kevin Wolf
2013-04-18 13:19     ` Pavel Hrdina
2013-04-18 13:41       ` Kevin Wolf
2013-04-16 16:05 ` [Qemu-devel] [PATCH 03/11] savevm: update bdrv_snapshot_find() to find snapshot by id or name Pavel Hrdina
2013-04-16 17:34   ` Eric Blake
2013-04-18 13:17   ` Kevin Wolf
2013-04-16 16:05 ` [Qemu-devel] [PATCH 04/11] qapi: Convert delvm Pavel Hrdina
2013-04-16 19:39   ` Eric Blake
2013-04-18 13:28   ` Kevin Wolf
2013-04-16 16:05 ` [Qemu-devel] [PATCH 05/11] block: update error reporting for bdrv_snapshot_goto() and related functions Pavel Hrdina
2013-04-16 20:48   ` Eric Blake
2013-04-23 14:08   ` Kevin Wolf
2013-04-16 16:05 ` [Qemu-devel] [PATCH 06/11] savevm: update error reporting for qemu_loadvm_state() Pavel Hrdina
2013-04-16 21:42   ` Eric Blake
2013-04-16 16:05 ` [Qemu-devel] [PATCH 07/11] qapi: Convert loadvm Pavel Hrdina
2013-04-16 23:43   ` Eric Blake
2013-04-18 10:34     ` Pavel Hrdina
2013-04-16 16:05 ` [Qemu-devel] [PATCH 08/11] block: update error reporting for bdrv_snapshot_create() and related functions Pavel Hrdina
2013-04-16 23:54   ` Eric Blake
2013-04-16 16:05 ` [Qemu-devel] [PATCH 09/11] savevm: update error reporting off qemu_savevm_state() " Pavel Hrdina
2013-04-17  0:02   ` Eric Blake
2013-04-16 16:05 ` [Qemu-devel] [PATCH 10/11] qapi: Convert savevm Pavel Hrdina
2013-04-16 16:05 ` [Qemu-devel] [PATCH 11/11] savevm: remove backward compatibility from bdrv_snapshot_find() Pavel Hrdina
2013-04-17  2:53   ` Wenchao Xia
2013-04-17  7:52     ` Pavel Hrdina
2013-04-17 10:19       ` Wenchao Xia
2013-04-17 10:51         ` Pavel Hrdina
2013-04-17 18:14           ` Eric Blake
2013-04-17 18:22             ` Eric Blake
2013-04-18  4:31             ` Wenchao Xia
2013-04-18  7:20               ` Wenchao Xia
2013-04-18 10:22               ` Pavel Hrdina
2013-04-19  0:28                 ` Wenchao Xia
2013-04-24  3:51                   ` Wenchao Xia
2013-04-24  9:37                     ` Pavel Hrdina
2013-04-16 16:33 ` [Qemu-devel] [PATCH 00/11] covert savevm, loadvm and delvm into qapi Eric Blake

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.