qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v1 00/34]: add new error format
@ 2012-08-02  1:02 Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 01/34] monitor: drop unused monitor debug code Luiz Capitulino
                   ` (35 more replies)
  0 siblings, 36 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Quick summary first, long introduction afterwards.

>From the rfc:

 o rebased on top of master
 o dropped patch "qapi: qapi.py: allow the "'" character be escaped"
 o split patch "qerror: drop qerror_abort()" into two patches
 o fixed tcp_start_outgoing_migration() not to use QERR_ macros
 o fixed qemu-ga to use the new error format
 o dropped more unused stuff
 o improved several changelogs

Btw, please take a special look in patches 14/34, 15/34 and 16/34.


This series implements the 'Plan for error handling in QMP' as described
by Anthony in this email:

    http://lists.gnu.org/archive/html/qemu-devel/2012-07/msg03764.html

Basically, this replaces almost all error classes by GenericError (the
exception are a few error classes used by libvirt) and drops the error
data memeber. This also adds a free form string to error_set().

On the wire, we go from:

    { "error": { "class": "DeviceNotRemovable",
                 "data": { "device": "virtio0" },
                 "desc": "Device 'virtio0' is not removable" } }

to:

     { "error": { "class": "GenericError",
                  "desc": "Device 'virtio0' is not removable" } }

Internally, we go from:

  void error_set(Error **err, const char *fmt, ...);

to:

  void error_set(Error **err, ErrorClass err_class, const char *fmt, ...);

 Makefile.objs         |   2 +-
 QMP/qmp-spec.txt      |  10 +-
 block.c               |   1 +
 block_int.h           |   1 +
 configure             |  10 -
 error.c               |  91 +--------
 error.h               |  18 +-
 error_int.h           |  29 ---
 hmp.c                 |  97 ++++++----
 hmp.h                 |   1 +
 migration-tcp.c       |  34 ++--
 monitor.c             |  83 ++------
 nbd.c                 |   2 +-
 qapi-schema.json      |  33 +++-
 qapi/qmp-core.h       |   1 +
 qapi/qmp-dispatch.c   |  11 +-
 qemu-char.c           |   2 +-
 qemu-ga.c             |   5 +-
 qemu-sockets.c        |  21 +-
 qemu_socket.h         |   4 +-
 qerror.c              | 518 ++------------------------------------------------
 qerror.h              | 168 ++++++++--------
 qmp-commands.hx       |   3 +-
 scripts/qapi-types.py |  17 +-
 ui/vnc.c              |   2 +-
 25 files changed, 284 insertions(+), 880 deletions(-)

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

* [Qemu-devel] [PATCH 01/34] monitor: drop unused monitor debug code
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 02/34] qerror: QERR_AMBIGUOUS_PATH: drop %(object) from human msg Luiz Capitulino
                   ` (34 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

In the old QMP days, this code was used to find out QMP commands that
might be calling monitor_printf() down its call chain.

This is almost impossible to happen today, because the qapi converted
commands don't even have a monitor object. Besides, it's been more than
a year since I used this last time.

Let's just drop it.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 configure | 10 ----------
 monitor.c | 65 ---------------------------------------------------------------
 2 files changed, 75 deletions(-)

diff --git a/configure b/configure
index 027a718..4bfbf98 100755
--- a/configure
+++ b/configure
@@ -147,7 +147,6 @@ vhost_net="no"
 kvm="no"
 gprof="no"
 debug_tcg="no"
-debug_mon="no"
 debug="no"
 strip_opt="yes"
 tcg_interpreter="no"
@@ -633,14 +632,9 @@ for opt do
   ;;
   --disable-debug-tcg) debug_tcg="no"
   ;;
-  --enable-debug-mon) debug_mon="yes"
-  ;;
-  --disable-debug-mon) debug_mon="no"
-  ;;
   --enable-debug)
       # Enable debugging options that aren't excessively noisy
       debug_tcg="yes"
-      debug_mon="yes"
       debug="yes"
       strip_opt="no"
   ;;
@@ -3041,7 +3035,6 @@ echo "host CPU          $cpu"
 echo "host big endian   $bigendian"
 echo "target list       $target_list"
 echo "tcg debug enabled $debug_tcg"
-echo "Mon debug enabled $debug_mon"
 echo "gprof enabled     $gprof"
 echo "sparse enabled    $sparse"
 echo "strip binaries    $strip_opt"
@@ -3134,9 +3127,6 @@ echo "ARCH=$ARCH" >> $config_host_mak
 if test "$debug_tcg" = "yes" ; then
   echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak
 fi
-if test "$debug_mon" = "yes" ; then
-  echo "CONFIG_DEBUG_MONITOR=y" >> $config_host_mak
-fi
 if test "$debug" = "yes" ; then
   echo "CONFIG_DEBUG_EXEC=y" >> $config_host_mak
 fi
diff --git a/monitor.c b/monitor.c
index 49dccfe..aa57167 100644
--- a/monitor.c
+++ b/monitor.c
@@ -172,41 +172,11 @@ struct Monitor {
     CPUArchState *mon_cpu;
     BlockDriverCompletionFunc *password_completion_cb;
     void *password_opaque;
-#ifdef CONFIG_DEBUG_MONITOR
-    int print_calls_nr;
-#endif
     QError *error;
     QLIST_HEAD(,mon_fd_t) fds;
     QLIST_ENTRY(Monitor) entry;
 };
 
-#ifdef CONFIG_DEBUG_MONITOR
-#define MON_DEBUG(fmt, ...) do {    \
-    fprintf(stderr, "Monitor: ");       \
-    fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-
-static inline void mon_print_count_inc(Monitor *mon)
-{
-    mon->print_calls_nr++;
-}
-
-static inline void mon_print_count_init(Monitor *mon)
-{
-    mon->print_calls_nr = 0;
-}
-
-static inline int mon_print_count_get(const Monitor *mon)
-{
-    return mon->print_calls_nr;
-}
-
-#else /* !CONFIG_DEBUG_MONITOR */
-#define MON_DEBUG(fmt, ...) do { } while (0)
-static inline void mon_print_count_inc(Monitor *mon) { }
-static inline void mon_print_count_init(Monitor *mon) { }
-static inline int mon_print_count_get(const Monitor *mon) { return 0; }
-#endif /* CONFIG_DEBUG_MONITOR */
-
 /* QMP checker flags */
 #define QMP_ACCEPT_UNKNOWNS 1
 
@@ -299,8 +269,6 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
     if (!mon)
         return;
 
-    mon_print_count_inc(mon);
-
     if (monitor_ctrl_mode(mon)) {
         return;
     }
@@ -3860,8 +3828,6 @@ void monitor_set_error(Monitor *mon, QError *qerror)
     if (!mon->error) {
         mon->error = qerror;
     } else {
-        MON_DEBUG("Additional error report at %s:%d\n",
-                  qerror->file, qerror->linenr);
         QDECREF(qerror);
     }
 }
@@ -3875,36 +3841,7 @@ static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
          * Action: Report an internal error to the client if in QMP.
          */
         qerror_report(QERR_UNDEFINED_ERROR);
-        MON_DEBUG("command '%s' returned failure but did not pass an error\n",
-                  cmd->name);
     }
-
-#ifdef CONFIG_DEBUG_MONITOR
-    if (!ret && monitor_has_error(mon)) {
-        /*
-         * If it returns success, it must not have passed an error.
-         *
-         * Action: Report the passed error to the client.
-         */
-        MON_DEBUG("command '%s' returned success but passed an error\n",
-                  cmd->name);
-    }
-
-    if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) {
-        /*
-         * Handlers should not call Monitor print functions.
-         *
-         * Action: Ignore them in QMP.
-         *
-         * (XXX: we don't check any 'info' or 'query' command here
-         * because the user print function _is_ called by do_info(), hence
-         * we will trigger this check. This problem will go away when we
-         * make 'query' commands real and kill do_info())
-         */
-        MON_DEBUG("command '%s' called print functions %d time(s)\n",
-                  cmd->name, mon_print_count_get(mon));
-    }
-#endif
 }
 
 static void handle_user_command(Monitor *mon, const char *cmdline)
@@ -4433,8 +4370,6 @@ static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd,
     int ret;
     QObject *data = NULL;
 
-    mon_print_count_init(mon);
-
     ret = cmd->mhandler.cmd_new(mon, params, &data);
     handler_audit(mon, cmd, ret);
     monitor_protocol_emitter(mon, data);
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 02/34] qerror: QERR_AMBIGUOUS_PATH: drop %(object) from human msg
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 01/34] monitor: drop unused monitor debug code Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 03/34] qerror: QERR_DEVICE_ENCRYPTED: add filename info to " Luiz Capitulino
                   ` (33 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Actually, renames it to 'object'. This must be what the original author
meant to write, as there's no 'object' in the error's data member.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qerror.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qerror.c b/qerror.c
index 92c4eff..082de98 100644
--- a/qerror.c
+++ b/qerror.c
@@ -49,7 +49,7 @@ static const QErrorStringTable qerror_table[] = {
     },
     {
         .error_fmt = QERR_AMBIGUOUS_PATH,
-        .desc      = "Path '%(path)' does not uniquely identify a %(object)"
+        .desc      = "Path '%(path)' does not uniquely identify an object"
     },
     {
         .error_fmt = QERR_BAD_BUS_FOR_DEVICE,
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 03/34] qerror: QERR_DEVICE_ENCRYPTED: add filename info to human msg
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 01/34] monitor: drop unused monitor debug code Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 02/34] qerror: QERR_AMBIGUOUS_PATH: drop %(object) from human msg Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 04/34] qerror: reduce public exposure Luiz Capitulino
                   ` (32 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qerror.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qerror.c b/qerror.c
index 082de98..b2ed0e3 100644
--- a/qerror.c
+++ b/qerror.c
@@ -81,7 +81,7 @@ static const QErrorStringTable qerror_table[] = {
     },
     {
         .error_fmt = QERR_DEVICE_ENCRYPTED,
-        .desc      = "Device '%(device)' is encrypted",
+        .desc      = "Device '%(device)' is encrypted (filename is '%(filename)')",
     },
     {
         .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 04/34] qerror: reduce public exposure
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (2 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 03/34] qerror: QERR_DEVICE_ENCRYPTED: add filename info to " Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 05/34] qerror: drop qerror_abort() Luiz Capitulino
                   ` (31 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

qerror will be dropped in a near future, let's reduce its public
exposure by making functions only used in qerror.c static.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qerror.c | 10 +++++-----
 qerror.h |  5 -----
 2 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/qerror.c b/qerror.c
index b2ed0e3..ce0499b 100644
--- a/qerror.c
+++ b/qerror.c
@@ -336,7 +336,7 @@ static const QErrorStringTable qerror_table[] = {
  *
  * Return strong reference.
  */
-QError *qerror_new(void)
+static QError *qerror_new(void)
 {
     QError *qerr;
 
@@ -424,8 +424,8 @@ static void qerror_set_desc(QError *qerr, const char *fmt)
  *
  * Return strong reference.
  */
-QError *qerror_from_info(const char *file, int linenr, const char *func,
-                         const char *fmt, va_list *va)
+static QError *qerror_from_info(const char *file, int linenr, const char *func,
+                                const char *fmt, va_list *va)
 {
     QError *qerr;
 
@@ -549,7 +549,7 @@ QString *qerror_human(const QError *qerror)
  * it uses error_report() for this, so that the output is routed to the right
  * place (ie. stderr or Monitor's device).
  */
-void qerror_print(QError *qerror)
+static void qerror_print(QError *qerror)
 {
     QString *qstring = qerror_human(qerror);
     loc_push_restore(&qerror->loc);
@@ -620,7 +620,7 @@ void assert_no_error(Error *err)
 /**
  * qobject_to_qerror(): Convert a QObject into a QError
  */
-QError *qobject_to_qerror(const QObject *obj)
+static QError *qobject_to_qerror(const QObject *obj)
 {
     if (qobject_type(obj) != QTYPE_QERROR) {
         return NULL;
diff --git a/qerror.h b/qerror.h
index b4c8758..fe8870c 100644
--- a/qerror.h
+++ b/qerror.h
@@ -33,11 +33,7 @@ typedef struct QError {
     const QErrorStringTable *entry;
 } QError;
 
-QError *qerror_new(void);
-QError *qerror_from_info(const char *file, int linenr, const char *func,
-                         const char *fmt, va_list *va) GCC_FMT_ATTR(4, 0);
 QString *qerror_human(const QError *qerror);
-void qerror_print(QError *qerror);
 void qerror_report_internal(const char *file, int linenr, const char *func,
                             const char *fmt, ...) GCC_FMT_ATTR(4, 5);
 void qerror_report_err(Error *err);
@@ -45,7 +41,6 @@ void assert_no_error(Error *err);
 QString *qerror_format(const char *fmt, QDict *error);
 #define qerror_report(fmt, ...) \
     qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
-QError *qobject_to_qerror(const QObject *obj);
 
 /*
  * QError class list
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 05/34] qerror: drop qerror_abort()
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (3 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 04/34] qerror: reduce public exposure Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 06/34] qerror: avoid passing qerr pointer Luiz Capitulino
                   ` (30 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

qerror_abort() depends on the 'file', 'func' and 'linenr' members of
QError. However, these members are going to be dropped by the next
commit, so let's drop qerror_abort() in favor of printing an error
message to stderr plus a call to abort().

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qerror.c | 41 ++++++++++++++---------------------------
 1 file changed, 14 insertions(+), 27 deletions(-)

diff --git a/qerror.c b/qerror.c
index ce0499b..5efccec 100644
--- a/qerror.c
+++ b/qerror.c
@@ -346,22 +346,6 @@ static QError *qerror_new(void)
     return qerr;
 }
 
-static void GCC_FMT_ATTR(2, 3) qerror_abort(const QError *qerr,
-                                            const char *fmt, ...)
-{
-    va_list ap;
-
-    fprintf(stderr, "qerror: bad call in function '%s':\n", qerr->func);
-    fprintf(stderr, "qerror: -> ");
-
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-
-    fprintf(stderr, "\nqerror: call at %s:%d\n", qerr->file, qerr->linenr);
-    abort();
-}
-
 static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
                                                const char *fmt, va_list *va)
 {
@@ -369,28 +353,34 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
 
     obj = qobject_from_jsonv(fmt, va);
     if (!obj) {
-        qerror_abort(qerr, "invalid format '%s'", fmt);
+        fprintf(stderr, "invalid json in error dict '%s'\n", fmt);
+        abort();
     }
     if (qobject_type(obj) != QTYPE_QDICT) {
-        qerror_abort(qerr, "error format is not a QDict '%s'", fmt);
+        fprintf(stderr, "error is not a dict '%s'\n", fmt);
+        abort();
     }
 
     qerr->error = qobject_to_qdict(obj);
 
     obj = qdict_get(qerr->error, "class");
     if (!obj) {
-        qerror_abort(qerr, "missing 'class' key in '%s'", fmt);
+        fprintf(stderr, "missing 'class' key in '%s'\n", fmt);
+        abort();
     }
     if (qobject_type(obj) != QTYPE_QSTRING) {
-        qerror_abort(qerr, "'class' key value should be a QString");
+        fprintf(stderr, "'class' key value should be a string in '%s'\n", fmt);
+        abort();
     }
     
     obj = qdict_get(qerr->error, "data");
     if (!obj) {
-        qerror_abort(qerr, "missing 'data' key in '%s'", fmt);
+        fprintf(stderr, "missing 'data' key in '%s'\n", fmt);
+        abort();
     }
     if (qobject_type(obj) != QTYPE_QDICT) {
-        qerror_abort(qerr, "'data' key value should be a QDICT");
+        fprintf(stderr, "'data' key value should be a dict in '%s'\n", fmt);
+        abort();
     }
 }
 
@@ -407,7 +397,8 @@ static void qerror_set_desc(QError *qerr, const char *fmt)
         }
     }
 
-    qerror_abort(qerr, "error format '%s' not found", fmt);
+    fprintf(stderr, "error format '%s' not found\n", fmt);
+    abort();
 }
 
 /**
@@ -435,10 +426,6 @@ static QError *qerror_from_info(const char *file, int linenr, const char *func,
     qerr->file = file;
     qerr->func = func;
 
-    if (!fmt) {
-        qerror_abort(qerr, "QDict not specified");
-    }
-
     qerror_set_data(qerr, fmt, va);
     qerror_set_desc(qerr, fmt);
 
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 06/34] qerror: avoid passing qerr pointer
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (4 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 05/34] qerror: drop qerror_abort() Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 11:23   ` Markus Armbruster
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 07/34] qerror: QError: drop file, linenr, func Luiz Capitulino
                   ` (29 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Helps dropping/modifying qerror functions.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qerror.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/qerror.c b/qerror.c
index 5efccec..59025ea 100644
--- a/qerror.c
+++ b/qerror.c
@@ -346,10 +346,10 @@ static QError *qerror_new(void)
     return qerr;
 }
 
-static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
-                                               const char *fmt, va_list *va)
+static QDict *error_obj_from_fmt_no_fail(const char *fmt, va_list *va)
 {
     QObject *obj;
+    QDict *ret;
 
     obj = qobject_from_jsonv(fmt, va);
     if (!obj) {
@@ -361,9 +361,8 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
         abort();
     }
 
-    qerr->error = qobject_to_qdict(obj);
-
-    obj = qdict_get(qerr->error, "class");
+    ret = qobject_to_qdict(obj);
+    obj = qdict_get(ret, "class");
     if (!obj) {
         fprintf(stderr, "missing 'class' key in '%s'\n", fmt);
         abort();
@@ -372,8 +371,8 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
         fprintf(stderr, "'class' key value should be a string in '%s'\n", fmt);
         abort();
     }
-    
-    obj = qdict_get(qerr->error, "data");
+
+    obj = qdict_get(ret, "data");
     if (!obj) {
         fprintf(stderr, "missing 'data' key in '%s'\n", fmt);
         abort();
@@ -382,9 +381,11 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
         fprintf(stderr, "'data' key value should be a dict in '%s'\n", fmt);
         abort();
     }
+
+    return ret;
 }
 
-static void qerror_set_desc(QError *qerr, const char *fmt)
+static const QErrorStringTable *get_desc_no_fail(const char *fmt)
 {
     int i;
 
@@ -392,8 +393,7 @@ static void qerror_set_desc(QError *qerr, const char *fmt)
 
     for (i = 0; qerror_table[i].error_fmt; i++) {
         if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
-            qerr->entry = &qerror_table[i];
-            return;
+            return &qerror_table[i];
         }
     }
 
@@ -426,8 +426,8 @@ static QError *qerror_from_info(const char *file, int linenr, const char *func,
     qerr->file = file;
     qerr->func = func;
 
-    qerror_set_data(qerr, fmt, va);
-    qerror_set_desc(qerr, fmt);
+    qerr->error = error_obj_from_fmt_no_fail(fmt, va);
+    qerr->entry = get_desc_no_fail(fmt);
 
     return qerr;
 }
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 07/34] qerror: QError: drop file, linenr, func
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (5 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 06/34] qerror: avoid passing qerr pointer Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 08/34] qerror: qerror_format(): return an allocated string Luiz Capitulino
                   ` (28 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

They have never been fully used and conflict with future error
improvements.

Also makes qerror_report() a proper function, as there's no point
in having it as a macro anymore.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qerror.c | 20 +++-----------------
 qerror.h |  8 +-------
 2 files changed, 4 insertions(+), 24 deletions(-)

diff --git a/qerror.c b/qerror.c
index 59025ea..f55a652 100644
--- a/qerror.c
+++ b/qerror.c
@@ -404,27 +404,14 @@ static const QErrorStringTable *get_desc_no_fail(const char *fmt)
 /**
  * qerror_from_info(): Create a new QError from error information
  *
- * The information consists of:
- *
- * - file   the file name of where the error occurred
- * - linenr the line number of where the error occurred
- * - func   the function name of where the error occurred
- * - fmt    JSON printf-like dictionary, there must exist keys 'class' and
- *          'data'
- * - va     va_list of all arguments specified by fmt
- *
  * Return strong reference.
  */
-static QError *qerror_from_info(const char *file, int linenr, const char *func,
-                                const char *fmt, va_list *va)
+static QError *qerror_from_info(const char *fmt, va_list *va)
 {
     QError *qerr;
 
     qerr = qerror_new();
     loc_save(&qerr->loc);
-    qerr->linenr = linenr;
-    qerr->file = file;
-    qerr->func = func;
 
     qerr->error = error_obj_from_fmt_no_fail(fmt, va);
     qerr->entry = get_desc_no_fail(fmt);
@@ -545,14 +532,13 @@ static void qerror_print(QError *qerror)
     QDECREF(qstring);
 }
 
-void qerror_report_internal(const char *file, int linenr, const char *func,
-                            const char *fmt, ...)
+void qerror_report(const char *fmt, ...)
 {
     va_list va;
     QError *qerror;
 
     va_start(va, fmt);
-    qerror = qerror_from_info(file, linenr, func, fmt, &va);
+    qerror = qerror_from_info(fmt, &va);
     va_end(va);
 
     if (monitor_cur_is_qmp()) {
diff --git a/qerror.h b/qerror.h
index fe8870c..3c0b14c 100644
--- a/qerror.h
+++ b/qerror.h
@@ -27,20 +27,14 @@ typedef struct QError {
     QObject_HEAD;
     QDict *error;
     Location loc;
-    int linenr;
-    const char *file;
-    const char *func;
     const QErrorStringTable *entry;
 } QError;
 
 QString *qerror_human(const QError *qerror);
-void qerror_report_internal(const char *file, int linenr, const char *func,
-                            const char *fmt, ...) GCC_FMT_ATTR(4, 5);
+void qerror_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
 void qerror_report_err(Error *err);
 void assert_no_error(Error *err);
 QString *qerror_format(const char *fmt, QDict *error);
-#define qerror_report(fmt, ...) \
-    qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
 
 /*
  * QError class list
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 08/34] qerror: qerror_format(): return an allocated string
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (6 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 07/34] qerror: QError: drop file, linenr, func Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 09/34] qerror: don't delay error message construction Luiz Capitulino
                   ` (27 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Simplifies current and future users.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 error.c  |  5 +----
 qerror.c | 10 ++++++++--
 qerror.h |  2 +-
 3 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/error.c b/error.c
index 58f55a0..3a62592 100644
--- a/error.c
+++ b/error.c
@@ -65,10 +65,7 @@ bool error_is_set(Error **errp)
 const char *error_get_pretty(Error *err)
 {
     if (err->msg == NULL) {
-        QString *str;
-        str = qerror_format(err->fmt, err->obj);
-        err->msg = g_strdup(qstring_get_str(str));
-        QDECREF(str);
+        err->msg = qerror_format(err->fmt, err->obj);
     }
 
     return err->msg;
diff --git a/qerror.c b/qerror.c
index f55a652..5b4266c 100644
--- a/qerror.c
+++ b/qerror.c
@@ -493,9 +493,11 @@ static QString *qerror_format_desc(QDict *error,
     return qstring;
 }
 
-QString *qerror_format(const char *fmt, QDict *error)
+char *qerror_format(const char *fmt, QDict *error)
 {
     const QErrorStringTable *entry = NULL;
+    QString *qstr;
+    char *ret;
     int i;
 
     for (i = 0; qerror_table[i].error_fmt; i++) {
@@ -505,7 +507,11 @@ QString *qerror_format(const char *fmt, QDict *error)
         }
     }
 
-    return qerror_format_desc(error, entry);
+    qstr = qerror_format_desc(error, entry);
+    ret = g_strdup(qstring_get_str(qstr));
+    QDECREF(qstr);
+
+    return ret;
 }
 
 /**
diff --git a/qerror.h b/qerror.h
index 3c0b14c..aec76b2 100644
--- a/qerror.h
+++ b/qerror.h
@@ -34,7 +34,7 @@ QString *qerror_human(const QError *qerror);
 void qerror_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
 void qerror_report_err(Error *err);
 void assert_no_error(Error *err);
-QString *qerror_format(const char *fmt, QDict *error);
+char *qerror_format(const char *fmt, QDict *error);
 
 /*
  * QError class list
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 09/34] qerror: don't delay error message construction
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (7 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 08/34] qerror: qerror_format(): return an allocated string Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 10/34] error: " Luiz Capitulino
                   ` (26 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Today, the error message is only constructed when it's used. This commit
changes qerror to construct the error message when the error object is
built (ie. when the error is reported).

This eliminates the need of storing a pointer to qerror_table[], which
will be dropped soon, and also simplifies the code.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qerror.c | 29 ++++-------------------------
 qerror.h |  2 +-
 2 files changed, 5 insertions(+), 26 deletions(-)

diff --git a/qerror.c b/qerror.c
index 5b4266c..5b7d67d 100644
--- a/qerror.c
+++ b/qerror.c
@@ -385,22 +385,6 @@ static QDict *error_obj_from_fmt_no_fail(const char *fmt, va_list *va)
     return ret;
 }
 
-static const QErrorStringTable *get_desc_no_fail(const char *fmt)
-{
-    int i;
-
-    // FIXME: inefficient loop
-
-    for (i = 0; qerror_table[i].error_fmt; i++) {
-        if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
-            return &qerror_table[i];
-        }
-    }
-
-    fprintf(stderr, "error format '%s' not found\n", fmt);
-    abort();
-}
-
 /**
  * qerror_from_info(): Create a new QError from error information
  *
@@ -414,7 +398,7 @@ static QError *qerror_from_info(const char *fmt, va_list *va)
     loc_save(&qerr->loc);
 
     qerr->error = error_obj_from_fmt_no_fail(fmt, va);
-    qerr->entry = get_desc_no_fail(fmt);
+    qerr->err_msg = qerror_format(fmt, qerr->error);
 
     return qerr;
 }
@@ -519,7 +503,7 @@ char *qerror_format(const char *fmt, QDict *error)
  */
 QString *qerror_human(const QError *qerror)
 {
-    return qerror_format_desc(qerror->error, qerror->entry);
+    return qstring_from_str(qerror->err_msg);
 }
 
 /**
@@ -566,19 +550,13 @@ struct Error
 void qerror_report_err(Error *err)
 {
     QError *qerr;
-    int i;
 
     qerr = qerror_new();
     loc_save(&qerr->loc);
     QINCREF(err->obj);
     qerr->error = err->obj;
 
-    for (i = 0; qerror_table[i].error_fmt; i++) {
-        if (strcmp(qerror_table[i].error_fmt, err->fmt) == 0) {
-            qerr->entry = &qerror_table[i];
-            break;
-        }
-    }
+    qerr->err_msg = qerror_format(err->fmt, qerr->error);
 
     if (monitor_cur_is_qmp()) {
         monitor_set_error(cur_mon, qerr);
@@ -619,5 +597,6 @@ static void qerror_destroy_obj(QObject *obj)
     qerr = qobject_to_qerror(obj);
 
     QDECREF(qerr->error);
+    g_free(qerr->err_msg);
     g_free(qerr);
 }
diff --git a/qerror.h b/qerror.h
index aec76b2..de8497d 100644
--- a/qerror.h
+++ b/qerror.h
@@ -27,7 +27,7 @@ typedef struct QError {
     QObject_HEAD;
     QDict *error;
     Location loc;
-    const QErrorStringTable *entry;
+    char *err_msg;
 } QError;
 
 QString *qerror_human(const QError *qerror);
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 10/34] error: don't delay error message construction
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (8 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 09/34] qerror: don't delay error message construction Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field Luiz Capitulino
                   ` (25 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Today, the error message is only constructed when it's used. This commit
changes that to construct the error message when the error object is
built (ie. when the error is reported).

This simplifies the Error object.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 error.c  | 8 +-------
 qerror.c | 4 +---
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/error.c b/error.c
index 3a62592..2ade99b 100644
--- a/error.c
+++ b/error.c
@@ -20,7 +20,6 @@
 struct Error
 {
     QDict *obj;
-    const char *fmt;
     char *msg;
 };
 
@@ -39,7 +38,7 @@ void error_set(Error **errp, const char *fmt, ...)
     va_start(ap, fmt);
     err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap));
     va_end(ap);
-    err->fmt = fmt;
+    err->msg = qerror_format(fmt, err->obj);
 
     *errp = err;
 }
@@ -50,7 +49,6 @@ Error *error_copy(const Error *err)
 
     err_new = g_malloc0(sizeof(*err));
     err_new->msg = g_strdup(err->msg);
-    err_new->fmt = err->fmt;
     err_new->obj = err->obj;
     QINCREF(err_new->obj);
 
@@ -64,10 +62,6 @@ bool error_is_set(Error **errp)
 
 const char *error_get_pretty(Error *err)
 {
-    if (err->msg == NULL) {
-        err->msg = qerror_format(err->fmt, err->obj);
-    }
-
     return err->msg;
 }
 
diff --git a/qerror.c b/qerror.c
index 5b7d67d..691d8a8 100644
--- a/qerror.c
+++ b/qerror.c
@@ -543,7 +543,6 @@ void qerror_report(const char *fmt, ...)
 struct Error
 {
     QDict *obj;
-    const char *fmt;
     char *msg;
 };
 
@@ -555,8 +554,7 @@ void qerror_report_err(Error *err)
     loc_save(&qerr->loc);
     QINCREF(err->obj);
     qerr->error = err->obj;
-
-    qerr->err_msg = qerror_format(err->fmt, qerr->error);
+    qerr->err_msg = g_strdup(err->msg);
 
     if (monitor_cur_is_qmp()) {
         monitor_set_error(cur_mon, qerr);
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (9 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 10/34] error: " Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 11:35   ` Markus Armbruster
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 12/34] hmp: hmp_cont(): don't rely on QERR_DEVICE_ENCRYPTED Luiz Capitulino
                   ` (24 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 block.c          | 1 +
 qapi-schema.json | 7 +++++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/block.c b/block.c
index b38940b..9c113b8 100644
--- a/block.c
+++ b/block.c
@@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
             info->value->inserted->ro = bs->read_only;
             info->value->inserted->drv = g_strdup(bs->drv->format_name);
             info->value->inserted->encrypted = bs->encrypted;
+            info->value->inserted->valid_encryption_key = bs->valid_key;
             if (bs->backing_file[0]) {
                 info->value->inserted->has_backing_file = true;
                 info->value->inserted->backing_file = g_strdup(bs->backing_file);
diff --git a/qapi-schema.json b/qapi-schema.json
index bc55ed2..1b2d7f5 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -400,6 +400,8 @@
 #
 # @encrypted: true if the backing device is encrypted
 #
+# @valid_encryption_key: true if a valid encryption key has been set
+#
 # @bps: total throughput limit in bytes per second is specified
 #
 # @bps_rd: read throughput limit in bytes per second is specified
@@ -419,8 +421,9 @@
 { 'type': 'BlockDeviceInfo',
   'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
             '*backing_file': 'str', 'encrypted': 'bool',
-            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
-            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
+            'valid_encryption_key': 'bool', 'bps': 'int',
+            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
+            'iops_rd': 'int', 'iops_wr': 'int'} }
 
 ##
 # @BlockDeviceIoStatus:
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 12/34] hmp: hmp_cont(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (10 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 11:53   ` Markus Armbruster
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 13/34] hmp: hmp_change(): " Luiz Capitulino
                   ` (23 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

This commit changes hmp_cont() to loop through all block devices
and proactively set an encryption key for any encrypted device
without a valid one.

This change is needed because QERR_DEVICE_ENCRYPTED is going to be
dropped by a future commit.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 hmp.c | 43 +++++++++++++++++++++++++------------------
 1 file changed, 25 insertions(+), 18 deletions(-)

diff --git a/hmp.c b/hmp.c
index 6b72a64..1ebeb63 100644
--- a/hmp.c
+++ b/hmp.c
@@ -610,34 +610,41 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
 
 static void hmp_cont_cb(void *opaque, int err)
 {
-    Monitor *mon = opaque;
-
     if (!err) {
-        hmp_cont(mon, NULL);
+        qmp_cont(NULL);
     }
 }
 
-void hmp_cont(Monitor *mon, const QDict *qdict)
+static bool blockinfo_is_encrypted(const BlockInfo *bdev)
 {
-    Error *errp = NULL;
-
-    qmp_cont(&errp);
-    if (error_is_set(&errp)) {
-        if (error_is_type(errp, QERR_DEVICE_ENCRYPTED)) {
-            const char *device;
+    return (bdev->inserted && bdev->inserted->encrypted);
+}
 
-            /* The device is encrypted. Ask the user for the password
-               and retry */
+static bool blockinfo_key_is_set(const BlockInfo *bdev)
+{
+    return (bdev->inserted && bdev->inserted->valid_encryption_key);
+}
 
-            device = error_get_field(errp, "device");
-            assert(device != NULL);
+void hmp_cont(Monitor *mon, const QDict *qdict)
+{
+    BlockInfoList *bdev_list, *bdev;
+    Error *errp = NULL;
 
-            monitor_read_block_device_key(mon, device, hmp_cont_cb, mon);
-            error_free(errp);
-            return;
+    bdev_list = qmp_query_block(NULL);
+    for (bdev = bdev_list; bdev; bdev = bdev->next) {
+        if (blockinfo_is_encrypted(bdev->value) &&
+            !blockinfo_key_is_set(bdev->value)) {
+                monitor_read_block_device_key(mon, bdev->value->device,
+                                              hmp_cont_cb, NULL);
+                goto out;
         }
-        hmp_handle_error(mon, &errp);
     }
+
+    qmp_cont(&errp);
+    hmp_handle_error(mon, &errp);
+
+out:
+    qapi_free_BlockInfoList(bdev_list);
 }
 
 void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 13/34] hmp: hmp_change(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (11 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 12/34] hmp: hmp_cont(): don't rely on QERR_DEVICE_ENCRYPTED Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 13:27   ` Markus Armbruster
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 14/34] net: inet_connect(), inet_connect_opts(): add in_progress argument Luiz Capitulino
                   ` (22 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

This commit changes the way hmp_change() checks if an encryption key
is required for the device to be inserted.

Instead of checking for QERR_DEVICE_ENCRYPTED, hmp_change() now checks
if the device was successfully inserted, is encrypted and is missing
an encryption key.

This change is needed because QERR_DEVICE_ENCRYPTED is going to be
dropped by a future commit.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 hmp.c | 54 ++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 38 insertions(+), 16 deletions(-)

diff --git a/hmp.c b/hmp.c
index 1ebeb63..ea21cf7 100644
--- a/hmp.c
+++ b/hmp.c
@@ -783,17 +783,29 @@ static void hmp_change_read_arg(Monitor *mon, const char *password,
 static void cb_hmp_change_bdrv_pwd(Monitor *mon, const char *password,
                                    void *opaque)
 {
-    Error *encryption_err = opaque;
+    char *device = opaque;
     Error *err = NULL;
-    const char *device;
-
-    device = error_get_field(encryption_err, "device");
 
     qmp_block_passwd(device, password, &err);
     hmp_handle_error(mon, &err);
-    error_free(encryption_err);
 
     monitor_read_command(mon, 1);
+    g_free(device);
+}
+
+static void hmp_change_ask_user_key(Monitor *mon, const BlockInfo *binfo)
+{
+    monitor_printf(mon, "%s (%s) is encrypted.\n", binfo->device,
+                   binfo->inserted->file);
+
+    if (!monitor_get_rs(mon)) {
+        monitor_printf(mon,
+                "terminal does not support password prompting\n");
+        return;
+    }
+
+    readline_start(monitor_get_rs(mon), "Password: ", 1,
+                   cb_hmp_change_bdrv_pwd, g_strdup(binfo->device));
 }
 
 void hmp_change(Monitor *mon, const QDict *qdict)
@@ -801,6 +813,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
     const char *device = qdict_get_str(qdict, "device");
     const char *target = qdict_get_str(qdict, "target");
     const char *arg = qdict_get_try_str(qdict, "arg");
+    BlockInfoList *bdev_list = NULL, *bdev;
     Error *err = NULL;
 
     if (strcmp(device, "vnc") == 0 &&
@@ -813,21 +826,30 @@ void hmp_change(Monitor *mon, const QDict *qdict)
     }
 
     qmp_change(device, target, !!arg, arg, &err);
-    if (error_is_type(err, QERR_DEVICE_ENCRYPTED)) {
-        monitor_printf(mon, "%s (%s) is encrypted.\n",
-                       error_get_field(err, "device"),
-                       error_get_field(err, "filename"));
-        if (!monitor_get_rs(mon)) {
-            monitor_printf(mon,
-                    "terminal does not support password prompting\n");
+    if (error_is_set(&err)) {
+        /* qmp_change() failed. If 'device' is returned by qmp_query_block(),
+         * is encrypted and doesn't have a valid encryption key set, then
+         * either the user passed an invalid key or didn't pass one at all.
+         * Ask the user for the key.
+         */
+        bdev_list = qmp_query_block(NULL);
+        for (bdev = bdev_list; bdev; bdev = bdev->next) {
+            if (!strcmp(bdev->value->device, device) &&
+                blockinfo_is_encrypted(bdev->value) &&
+                !blockinfo_key_is_set(bdev->value)) {
+                hmp_change_ask_user_key(mon, bdev->value);
+                break;
+            }
+        }
+
+        if (bdev) {
             error_free(err);
-            return;
+            err = NULL;
         }
-        readline_start(monitor_get_rs(mon), "Password: ", 1,
-                       cb_hmp_change_bdrv_pwd, err);
-        return;
     }
+
     hmp_handle_error(mon, &err);
+    qapi_free_BlockInfoList(bdev_list);
 }
 
 void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 14/34] net: inet_connect(), inet_connect_opts(): add in_progress argument
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (12 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 13/34] hmp: hmp_change(): " Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 15:12   ` Markus Armbruster
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 15/34] net: inet_connect(), inet_connect_opts(): return -errno Luiz Capitulino
                   ` (21 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

It's used to indicate the special case where a valid file-descriptor
is returned (ie. success) but the connection can't be completed
w/o blocking.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 migration-tcp.c |  2 +-
 nbd.c           |  2 +-
 qemu-char.c     |  2 +-
 qemu-sockets.c  | 14 +++++++++++---
 qemu_socket.h   |  4 ++--
 ui/vnc.c        |  2 +-
 6 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/migration-tcp.c b/migration-tcp.c
index 440804d..18944a4 100644
--- a/migration-tcp.c
+++ b/migration-tcp.c
@@ -86,7 +86,7 @@ int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
     s->write = socket_write;
     s->close = tcp_close;
 
-    s->fd = inet_connect(host_port, false, errp);
+    s->fd = inet_connect(host_port, false, NULL, errp);
 
     if (!error_is_set(errp)) {
         migrate_fd_connect(s);
diff --git a/nbd.c b/nbd.c
index dc0adf9..0dd60c5 100644
--- a/nbd.c
+++ b/nbd.c
@@ -162,7 +162,7 @@ int tcp_socket_outgoing(const char *address, uint16_t port)
 
 int tcp_socket_outgoing_spec(const char *address_and_port)
 {
-    return inet_connect(address_and_port, true, NULL);
+    return inet_connect(address_and_port, true, NULL, NULL);
 }
 
 int tcp_socket_incoming(const char *address, uint16_t port)
diff --git a/qemu-char.c b/qemu-char.c
index c2aaaee..382c71e 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2446,7 +2446,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
         if (is_listen) {
             fd = inet_listen_opts(opts, 0, NULL);
         } else {
-            fd = inet_connect_opts(opts, NULL);
+            fd = inet_connect_opts(opts, NULL, NULL);
         }
     }
     if (fd < 0) {
diff --git a/qemu-sockets.c b/qemu-sockets.c
index 668fa93..33b65cf 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -209,7 +209,7 @@ listen:
     return slisten;
 }
 
-int inet_connect_opts(QemuOpts *opts, Error **errp)
+int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp)
 {
     struct addrinfo ai,*res,*e;
     const char *addr;
@@ -224,6 +224,10 @@ int inet_connect_opts(QemuOpts *opts, Error **errp)
     ai.ai_family = PF_UNSPEC;
     ai.ai_socktype = SOCK_STREAM;
 
+    if (in_progress) {
+        *in_progress = false;
+    }
+
     addr = qemu_opt_get(opts, "host");
     port = qemu_opt_get(opts, "port");
     block = qemu_opt_get_bool(opts, "block", 0);
@@ -277,6 +281,10 @@ int inet_connect_opts(QemuOpts *opts, Error **errp)
   #else
         if (!block && (rc == -EINPROGRESS)) {
   #endif
+            if (in_progress) {
+                *in_progress = true;
+            }
+
             error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS);
         } else if (rc < 0) {
             if (NULL == e->ai_next)
@@ -488,7 +496,7 @@ int inet_listen(const char *str, char *ostr, int olen,
     return sock;
 }
 
-int inet_connect(const char *str, bool block, Error **errp)
+int inet_connect(const char *str, bool block, bool *in_progress, Error **errp)
 {
     QemuOpts *opts;
     int sock = -1;
@@ -498,7 +506,7 @@ int inet_connect(const char *str, bool block, Error **errp)
         if (block) {
             qemu_opt_set(opts, "block", "on");
         }
-        sock = inet_connect_opts(opts, errp);
+        sock = inet_connect_opts(opts, in_progress, errp);
     } else {
         error_set(errp, QERR_SOCKET_CREATE_FAILED);
     }
diff --git a/qemu_socket.h b/qemu_socket.h
index 4689ff3..30ae6af 100644
--- a/qemu_socket.h
+++ b/qemu_socket.h
@@ -42,8 +42,8 @@ int send_all(int fd, const void *buf, int len1);
 int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp);
 int inet_listen(const char *str, char *ostr, int olen,
                 int socktype, int port_offset, Error **errp);
-int inet_connect_opts(QemuOpts *opts, Error **errp);
-int inet_connect(const char *str, bool block, Error **errp);
+int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp);
+int inet_connect(const char *str, bool block, bool *in_progress, Error **errp);
 int inet_dgram_opts(QemuOpts *opts);
 const char *inet_strfamily(int family);
 
diff --git a/ui/vnc.c b/ui/vnc.c
index cfc61a7..9263577 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3051,7 +3051,7 @@ int vnc_display_open(DisplayState *ds, const char *display)
         if (strncmp(display, "unix:", 5) == 0)
             vs->lsock = unix_connect(display+5);
         else
-            vs->lsock = inet_connect(display, true, NULL);
+            vs->lsock = inet_connect(display, true, NULL, NULL);
         if (-1 == vs->lsock) {
             g_free(vs->display);
             vs->display = NULL;
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 15/34] net: inet_connect(), inet_connect_opts(): return -errno
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (13 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 14/34] net: inet_connect(), inet_connect_opts(): add in_progress argument Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 13:41   ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 16/34] migration: don't rely on QERR_SOCKET_* Luiz Capitulino
                   ` (20 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Next commit wants to use this.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---

This patch is an interesting case, because one of the goal of the error
format that's being replaced was that callers could use it to know the
error cause (with error_is_type().

However, the new error format doesn't allow this as most errors are
class GenericError. So, we'll have to use errno to know the error cause,
this is the case of inet_connect() when called by
tcp_start_outgoing_migration().

 qemu-sockets.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/qemu-sockets.c b/qemu-sockets.c
index 33b65cf..82f4736 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -234,7 +234,7 @@ int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp)
     if (addr == NULL || port == NULL) {
         fprintf(stderr, "inet_connect: host and/or port not specified\n");
         error_set(errp, QERR_SOCKET_CREATE_FAILED);
-        return -1;
+        return -EINVAL;
     }
 
     if (qemu_opt_get_bool(opts, "ipv4", 0))
@@ -247,7 +247,7 @@ int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp)
         fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
                 gai_strerror(rc));
         error_set(errp, QERR_SOCKET_CREATE_FAILED);
-	return -1;
+        return -EINVAL;
     }
 
     for (e = res; e != NULL; e = e->ai_next) {
@@ -300,7 +300,7 @@ int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp)
     }
     error_set(errp, QERR_SOCKET_CONNECT_FAILED);
     freeaddrinfo(res);
-    return -1;
+    return -ENOTCONN;
 }
 
 int inet_dgram_opts(QemuOpts *opts)
@@ -508,6 +508,7 @@ int inet_connect(const char *str, bool block, bool *in_progress, Error **errp)
         }
         sock = inet_connect_opts(opts, in_progress, errp);
     } else {
+        sock = -EINVAL;
         error_set(errp, QERR_SOCKET_CREATE_FAILED);
     }
     qemu_opts_del(opts);
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 16/34] migration: don't rely on QERR_SOCKET_*
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (14 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 15/34] net: inet_connect(), inet_connect_opts(): return -errno Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 17/34] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS Luiz Capitulino
                   ` (19 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Use the error code returned by inet_connect() instead. This change
is needed because all QERR_SOCKET_* errors are going to be dropped
by a future commit.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 migration-tcp.c | 34 ++++++++++++++++++++--------------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/migration-tcp.c b/migration-tcp.c
index 18944a4..7fe0ffe 100644
--- a/migration-tcp.c
+++ b/migration-tcp.c
@@ -82,27 +82,33 @@ static void tcp_wait_for_connect(void *opaque)
 int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
                                  Error **errp)
 {
+    bool in_progress;
+
     s->get_error = socket_errno;
     s->write = socket_write;
     s->close = tcp_close;
 
-    s->fd = inet_connect(host_port, false, NULL, errp);
+    s->fd = inet_connect(host_port, false, &in_progress, errp);
+    if (s->fd < 0) {
+        switch (s->fd) {
+        case -EINVAL:
+            DPRINTF("connect failed\n");
+            return -1;
+        case -ENOTCONN:
+            DPRINTF("connect failed\n");
+            migrate_fd_error(s);
+            return -1;
+        default:
+            DPRINTF("unknown error\n");
+            return -1;
+        }
+    }
 
-    if (!error_is_set(errp)) {
-        migrate_fd_connect(s);
-    } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_IN_PROGRESS)) {
-        DPRINTF("connect in progress\n");
+    if (in_progress) {
         qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
-    } else if (error_is_type(*errp, QERR_SOCKET_CREATE_FAILED)) {
-        DPRINTF("connect failed\n");
-        return -1;
-    } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_FAILED)) {
-        DPRINTF("connect failed\n");
-        migrate_fd_error(s);
-        return -1;
     } else {
-        DPRINTF("unknown error\n");
-        return -1;
+        /* connected */
+        migrate_fd_connect(s);
     }
 
     return 0;
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 17/34] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (15 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 16/34] migration: don't rely on QERR_SOCKET_* Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 15:58   ` Markus Armbruster
  2012-08-02 16:54   ` Michael Roth
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 18/34] error: drop unused functions Luiz Capitulino
                   ` (18 subsequent siblings)
  35 siblings, 2 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

This error is currently returned by inet_connect_opts(), however
it causes the follow spurious message on HMP:

    (qemu) migrate tcp:0:4444
    migrate: Connection can not be completed immediately
    (qemu)

But migration succeeds.

inet_connect_opts() has a 'in_progress' argument that callers can
use to check whether a connection is in progress. The QERR_ macro
is not needed anymore.

PS: I didn't test with QMP, but I guess the migrate command will
    return an error response.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qemu-sockets.c | 2 --
 qerror.c       | 4 ----
 qerror.h       | 3 ---
 3 files changed, 9 deletions(-)

diff --git a/qemu-sockets.c b/qemu-sockets.c
index 82f4736..7196c5f 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -284,8 +284,6 @@ int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp)
             if (in_progress) {
                 *in_progress = true;
             }
-
-            error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS);
         } else if (rc < 0) {
             if (NULL == e->ai_next)
                 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
diff --git a/qerror.c b/qerror.c
index 691d8a8..33b8780 100644
--- a/qerror.c
+++ b/qerror.c
@@ -309,10 +309,6 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "Could not start VNC server on %(target)",
     },
     {
-        .error_fmt = QERR_SOCKET_CONNECT_IN_PROGRESS,
-        .desc      = "Connection can not be completed immediately",
-    },
-    {
         .error_fmt = QERR_SOCKET_CONNECT_FAILED,
         .desc      = "Failed to connect to socket",
     },
diff --git a/qerror.h b/qerror.h
index de8497d..52ce58d 100644
--- a/qerror.h
+++ b/qerror.h
@@ -240,9 +240,6 @@ char *qerror_format(const char *fmt, QDict *error);
 #define QERR_VNC_SERVER_FAILED \
     "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
 
-#define QERR_SOCKET_CONNECT_IN_PROGRESS \
-    "{ 'class': 'SockConnectInprogress', 'data': {} }"
-
 #define QERR_SOCKET_CONNECT_FAILED \
     "{ 'class': 'SockConnectFailed', 'data': {} }"
 
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 18/34] error: drop unused functions
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (16 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 17/34] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 19/34] block: block_int: include qerror.h Luiz Capitulino
                   ` (17 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Besides of being unused, they operate on the current error format,
which is going to be replaced soon.

Useful replacements for the dropped functions will be added along
with the new error format.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 error.c     | 48 ------------------------------------------------
 error.h     | 16 ----------------
 error_int.h |  1 -
 3 files changed, 65 deletions(-)

diff --git a/error.c b/error.c
index 2ade99b..216cb08 100644
--- a/error.c
+++ b/error.c
@@ -65,29 +65,6 @@ const char *error_get_pretty(Error *err)
     return err->msg;
 }
 
-const char *error_get_field(Error *err, const char *field)
-{
-    if (strcmp(field, "class") == 0) {
-        return qdict_get_str(err->obj, field);
-    } else {
-        QDict *dict = qdict_get_qdict(err->obj, "data");
-        return qdict_get_str(dict, field);
-    }
-}
-
-QDict *error_get_data(Error *err)
-{
-    QDict *data = qdict_get_qdict(err->obj, "data");
-    QINCREF(data);
-    return data;
-}
-
-void error_set_field(Error *err, const char *field, const char *value)
-{
-    QDict *dict = qdict_get_qdict(err->obj, "data");
-    qdict_put(dict, field, qstring_from_str(value));
-}
-
 void error_free(Error *err)
 {
     if (err) {
@@ -97,31 +74,6 @@ void error_free(Error *err)
     }
 }
 
-bool error_is_type(Error *err, const char *fmt)
-{
-    const char *error_class;
-    char *ptr;
-    char *end;
-
-    if (!err) {
-        return false;
-    }
-
-    ptr = strstr(fmt, "'class': '");
-    assert(ptr != NULL);
-    ptr += strlen("'class': '");
-
-    end = strchr(ptr, '\'');
-    assert(end != NULL);
-
-    error_class = error_get_field(err, "class");
-    if (strlen(error_class) != end - ptr) {
-        return false;
-    }
-
-    return strncmp(ptr, error_class, end - ptr) == 0;
-}
-
 void error_propagate(Error **dst_err, Error *local_err)
 {
     if (dst_err && !*dst_err) {
diff --git a/error.h b/error.h
index 3d9d96d..3d038a5 100644
--- a/error.h
+++ b/error.h
@@ -45,16 +45,6 @@ Error *error_copy(const Error *err);
 const char *error_get_pretty(Error *err);
 
 /**
- * Get an individual named error field.
- */
-const char *error_get_field(Error *err, const char *field);
-
-/**
- * Get an individual named error field.
- */
-void error_set_field(Error *err, const char *field, const char *value);
-
-/**
  * Propagate an error to an indirect pointer to an error.  This function will
  * always transfer ownership of the error reference and handles the case where
  * dst_err is NULL correctly.  Errors after the first are discarded.
@@ -66,10 +56,4 @@ void error_propagate(Error **dst_err, Error *local_err);
  */
 void error_free(Error *err);
 
-/**
- * Determine if an error is of a speific type (based on the qerror format).
- * Non-QEMU users should get the `class' field to identify the error type.
- */
-bool error_is_type(Error *err, const char *fmt);
-
 #endif
diff --git a/error_int.h b/error_int.h
index 5e39424..4b00d08 100644
--- a/error_int.h
+++ b/error_int.h
@@ -22,7 +22,6 @@
  *
  * These are used to convert QErrors to Errors
  */
-QDict *error_get_data(Error *err);
 QObject *error_get_qobject(Error *err);
 void error_set_qobject(Error **errp, QObject *obj);
   
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 19/34] block: block_int: include qerror.h
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (17 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 18/34] error: drop unused functions Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 20/34] hmp: hmp.h: include qdict.h Luiz Capitulino
                   ` (16 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Several block/ files are relying on qerror.h being provided by
qapi-types.h. Fix this, as a future commit will change qapi-types.h
not to provide qerror.h.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 block_int.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/block_int.h b/block_int.h
index d72317f..00892e8 100644
--- a/block_int.h
+++ b/block_int.h
@@ -30,6 +30,7 @@
 #include "qemu-coroutine.h"
 #include "qemu-timer.h"
 #include "qapi-types.h"
+#include "qerror.h"
 
 #define BLOCK_FLAG_ENCRYPT	1
 #define BLOCK_FLAG_COMPAT6	4
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 20/34] hmp: hmp.h: include qdict.h
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (18 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 19/34] block: block_int: include qerror.h Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 21/34] qapi: qapi-types.h: don't include qapi/qapi-types-core.h Luiz Capitulino
                   ` (15 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

hmp.h is relying on qdict.h being provided by qapi-types.h. Fix this,
as a future commit will change qapi-types.h not to provide qdict.h.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 hmp.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hmp.h b/hmp.h
index 8d2b0d7..3275522 100644
--- a/hmp.h
+++ b/hmp.h
@@ -16,6 +16,7 @@
 
 #include "qemu-common.h"
 #include "qapi-types.h"
+#include "qdict.h"
 
 void hmp_info_name(Monitor *mon);
 void hmp_info_version(Monitor *mon);
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 21/34] qapi: qapi-types.h: don't include qapi/qapi-types-core.h
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (19 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 20/34] hmp: hmp.h: include qdict.h Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 22/34] qapi: generate correct enum names for camel case enums Luiz Capitulino
                   ` (14 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

qapi-types.h needs only qemu-common.h. Including qapi-types-core.h
causes problems when qerror.h or error.h includes qapi-types.h.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 scripts/qapi-types.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 4a734f5..3ed9f04 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -253,7 +253,8 @@ fdecl.write(mcgen('''
 #ifndef %(guard)s
 #define %(guard)s
 
-#include "qapi/qapi-types-core.h"
+#include "qemu-common.h"
+
 ''',
                   guard=guardname(h_file)))
 
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 22/34] qapi: generate correct enum names for camel case enums
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (20 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 21/34] qapi: qapi-types.h: don't include qapi/qapi-types-core.h Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 23/34] qapi: don't convert enum strings to lowercase Luiz Capitulino
                   ` (13 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

An enum like GenericError in the schema, should generate
GENERIC_ERROR and not GENERICERROR.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 scripts/qapi-types.py | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 3ed9f04..9b7da96 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -79,6 +79,16 @@ const char *%(name)s_lookup[] = {
 ''')
     return ret
 
+def generate_enum_name(name):
+    if name.isupper():
+        return c_fun(name)
+    new_name = ''
+    for c in c_fun(name):
+        if c.isupper():
+            new_name += '_'
+        new_name += c
+    return new_name.lstrip('_').upper()
+
 def generate_enum(name, values):
     lookup_decl = mcgen('''
 extern const char *%(name)s_lookup[];
@@ -100,7 +110,7 @@ typedef enum %(name)s
     %(abbrev)s_%(value)s = %(i)d,
 ''',
                      abbrev=de_camel_case(name).upper(),
-                     value=c_fun(value).upper(),
+                     value=generate_enum_name(value),
                      i=i)
         i += 1
 
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 23/34] qapi: don't convert enum strings to lowercase
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (21 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 22/34] qapi: generate correct enum names for camel case enums Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 24/34] qapi-schema: add ErrorClass enum Luiz Capitulino
                   ` (12 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Next commit will introduce enum strings in camel case.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 scripts/qapi-types.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 9b7da96..cf601ae 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -70,7 +70,7 @@ const char *%(name)s_lookup[] = {
         ret += mcgen('''
     "%(value)s",
 ''',
-                     value=value.lower())
+                     value=value)
 
     ret += mcgen('''
     NULL,
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 24/34] qapi-schema: add ErrorClass enum
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (22 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 23/34] qapi: don't convert enum strings to lowercase Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 25/34] qerror: qerror_table: don't use C99 struct initializers Luiz Capitulino
                   ` (11 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qapi-schema.json | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/qapi-schema.json b/qapi-schema.json
index 1b2d7f5..6be937b 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3,6 +3,32 @@
 # QAPI Schema
 
 ##
+# @ErrorClass
+#
+# QEMU error classes
+#
+# @GenericError: this is used for errors that don't require a specific error
+#                class. This should be the default case for most errors
+#
+# @CommandNotFound: the requested command has not been found
+#
+# @DeviceNotActive: a device has failed to be become active
+#
+# @DeviceNotFound: the requested device has not been found
+#
+# @KVMMissingCap: the requested operation can't be fulfilled because a
+#                 required KVM capability is missing
+#
+# @MigrationExpected: the requested operation can't be fulfilled because a
+#                     migration process is expected
+#
+# Since: 1.2
+##
+{ 'enum': 'ErrorClass',
+  'data': [ 'GenericError', 'CommandNotFound', 'DeviceNotActive',
+            'KVMMissingCap', 'DeviceNotFound', 'MigrationExpected' ] }
+
+##
 # @NameInfo:
 #
 # Guest name information.
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 25/34] qerror: qerror_table: don't use C99 struct initializers
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (23 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 24/34] qapi-schema: add ErrorClass enum Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 16:48   ` Markus Armbruster
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 26/34] error, qerror: add ErrorClass argument to error functions Luiz Capitulino
                   ` (10 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

This allows for changing QERR_ macros to initialize two struct members
at the same time. See next commit for more details.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qerror.c | 276 +++++++++++++++++++++++++++++++--------------------------------
 qerror.h |   2 +-
 2 files changed, 139 insertions(+), 139 deletions(-)

diff --git a/qerror.c b/qerror.c
index 33b8780..664efb3 100644
--- a/qerror.c
+++ b/qerror.c
@@ -44,285 +44,285 @@ static const QType qerror_type = {
  */
 static const QErrorStringTable qerror_table[] = {
     {
-        .error_fmt = QERR_ADD_CLIENT_FAILED,
-        .desc      = "Could not add client",
+         QERR_ADD_CLIENT_FAILED,
+         "Could not add client",
     },
     {
-        .error_fmt = QERR_AMBIGUOUS_PATH,
-        .desc      = "Path '%(path)' does not uniquely identify an object"
+         QERR_AMBIGUOUS_PATH,
+         "Path '%(path)' does not uniquely identify an object"
     },
     {
-        .error_fmt = QERR_BAD_BUS_FOR_DEVICE,
-        .desc      = "Device '%(device)' can't go on a %(bad_bus_type) bus",
+         QERR_BAD_BUS_FOR_DEVICE,
+         "Device '%(device)' can't go on a %(bad_bus_type) bus",
     },
     {
-        .error_fmt = QERR_BASE_NOT_FOUND,
-        .desc      = "Base '%(base)' not found",
+         QERR_BASE_NOT_FOUND,
+         "Base '%(base)' not found",
     },
     {
-        .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
-        .desc      = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
+         QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
+         "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
     },
     {
-        .error_fmt = QERR_BUS_NO_HOTPLUG,
-        .desc      = "Bus '%(bus)' does not support hotplugging",
+         QERR_BUS_NO_HOTPLUG,
+         "Bus '%(bus)' does not support hotplugging",
     },
     {
-        .error_fmt = QERR_BUS_NOT_FOUND,
-        .desc      = "Bus '%(bus)' not found",
+         QERR_BUS_NOT_FOUND,
+         "Bus '%(bus)' not found",
     },
     {
-        .error_fmt = QERR_COMMAND_DISABLED,
-        .desc      = "The command %(name) has been disabled for this instance",
+         QERR_COMMAND_DISABLED,
+         "The command %(name) has been disabled for this instance",
     },
     {
-        .error_fmt = QERR_COMMAND_NOT_FOUND,
-        .desc      = "The command %(name) has not been found",
+         QERR_COMMAND_NOT_FOUND,
+         "The command %(name) has not been found",
     },
     {
-        .error_fmt = QERR_DEVICE_ENCRYPTED,
-        .desc      = "Device '%(device)' is encrypted (filename is '%(filename)')",
+         QERR_DEVICE_ENCRYPTED,
+         "Device '%(device)' is encrypted (filename is '%(filename)')",
     },
     {
-        .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
-        .desc      = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
+         QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
+         "Migration is disabled when using feature '%(feature)' in device '%(device)'",
     },
     {
-        .error_fmt = QERR_DEVICE_HAS_NO_MEDIUM,
-        .desc      = "Device '%(device)' has no medium",
+         QERR_DEVICE_HAS_NO_MEDIUM,
+         "Device '%(device)' has no medium",
     },
     {
-        .error_fmt = QERR_DEVICE_INIT_FAILED,
-        .desc      = "Device '%(device)' could not be initialized",
+         QERR_DEVICE_INIT_FAILED,
+         "Device '%(device)' could not be initialized",
     },
     {
-        .error_fmt = QERR_DEVICE_IN_USE,
-        .desc      = "Device '%(device)' is in use",
+         QERR_DEVICE_IN_USE,
+         "Device '%(device)' is in use",
     },
     {
-        .error_fmt = QERR_DEVICE_IS_READ_ONLY,
-        .desc      = "Device '%(device)' is read only",
+         QERR_DEVICE_IS_READ_ONLY,
+         "Device '%(device)' is read only",
     },
     {
-        .error_fmt = QERR_DEVICE_LOCKED,
-        .desc      = "Device '%(device)' is locked",
+         QERR_DEVICE_LOCKED,
+         "Device '%(device)' is locked",
     },
     {
-        .error_fmt = QERR_DEVICE_MULTIPLE_BUSSES,
-        .desc      = "Device '%(device)' has multiple child busses",
+         QERR_DEVICE_MULTIPLE_BUSSES,
+         "Device '%(device)' has multiple child busses",
     },
     {
-        .error_fmt = QERR_DEVICE_NO_BUS,
-        .desc      = "Device '%(device)' has no child bus",
+         QERR_DEVICE_NO_BUS,
+         "Device '%(device)' has no child bus",
     },
     {
-        .error_fmt = QERR_DEVICE_NO_HOTPLUG,
-        .desc      = "Device '%(device)' does not support hotplugging",
+         QERR_DEVICE_NO_HOTPLUG,
+         "Device '%(device)' does not support hotplugging",
     },
     {
-        .error_fmt = QERR_DEVICE_NOT_ACTIVE,
-        .desc      = "Device '%(device)' has not been activated",
+         QERR_DEVICE_NOT_ACTIVE,
+         "Device '%(device)' has not been activated",
     },
     {
-        .error_fmt = QERR_DEVICE_NOT_ENCRYPTED,
-        .desc      = "Device '%(device)' is not encrypted",
+         QERR_DEVICE_NOT_ENCRYPTED,
+         "Device '%(device)' is not encrypted",
     },
     {
-        .error_fmt = QERR_DEVICE_NOT_FOUND,
-        .desc      = "Device '%(device)' not found",
+         QERR_DEVICE_NOT_FOUND,
+         "Device '%(device)' not found",
     },
     {
-        .error_fmt = QERR_DEVICE_NOT_REMOVABLE,
-        .desc      = "Device '%(device)' is not removable",
+         QERR_DEVICE_NOT_REMOVABLE,
+         "Device '%(device)' is not removable",
     },
     {
-        .error_fmt = QERR_DUPLICATE_ID,
-        .desc      = "Duplicate ID '%(id)' for %(object)",
+         QERR_DUPLICATE_ID,
+         "Duplicate ID '%(id)' for %(object)",
     },
     {
-        .error_fmt = QERR_FD_NOT_FOUND,
-        .desc      = "File descriptor named '%(name)' not found",
+         QERR_FD_NOT_FOUND,
+         "File descriptor named '%(name)' not found",
     },
     {
-        .error_fmt = QERR_FD_NOT_SUPPLIED,
-        .desc      = "No file descriptor supplied via SCM_RIGHTS",
+         QERR_FD_NOT_SUPPLIED,
+         "No file descriptor supplied via SCM_RIGHTS",
     },
     {
-        .error_fmt = QERR_FEATURE_DISABLED,
-        .desc      = "The feature '%(name)' is not enabled",
+         QERR_FEATURE_DISABLED,
+         "The feature '%(name)' is not enabled",
     },
     {
-        .error_fmt = QERR_INVALID_BLOCK_FORMAT,
-        .desc      = "Invalid block format '%(name)'",
+         QERR_INVALID_BLOCK_FORMAT,
+         "Invalid block format '%(name)'",
     },
     {
-        .error_fmt = QERR_INVALID_OPTION_GROUP,
-        .desc      = "There is no option group '%(group)'",
+         QERR_INVALID_OPTION_GROUP,
+         "There is no option group '%(group)'",
     },
     {
-        .error_fmt = QERR_INVALID_PARAMETER,
-        .desc      = "Invalid parameter '%(name)'",
+         QERR_INVALID_PARAMETER,
+         "Invalid parameter '%(name)'",
     },
     {
-        .error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
-        .desc      = "Invalid parameter combination",
+         QERR_INVALID_PARAMETER_COMBINATION,
+         "Invalid parameter combination",
     },
     {
-        .error_fmt = QERR_INVALID_PARAMETER_TYPE,
-        .desc      = "Invalid parameter type for '%(name)', expected: %(expected)",
+         QERR_INVALID_PARAMETER_TYPE,
+         "Invalid parameter type for '%(name)', expected: %(expected)",
     },
     {
-        .error_fmt = QERR_INVALID_PARAMETER_VALUE,
-        .desc      = "Parameter '%(name)' expects %(expected)",
+         QERR_INVALID_PARAMETER_VALUE,
+         "Parameter '%(name)' expects %(expected)",
     },
     {
-        .error_fmt = QERR_INVALID_PASSWORD,
-        .desc      = "Password incorrect",
+         QERR_INVALID_PASSWORD,
+         "Password incorrect",
     },
     {
-        .error_fmt = QERR_IO_ERROR,
-        .desc      = "An IO error has occurred",
+         QERR_IO_ERROR,
+         "An IO error has occurred",
     },
     {
-        .error_fmt = QERR_JSON_PARSE_ERROR,
-        .desc      = "JSON parse error, %(message)",
+         QERR_JSON_PARSE_ERROR,
+         "JSON parse error, %(message)",
 
     },
     {
-        .error_fmt = QERR_JSON_PARSING,
-        .desc      = "Invalid JSON syntax",
+         QERR_JSON_PARSING,
+         "Invalid JSON syntax",
     },
     {
-        .error_fmt = QERR_KVM_MISSING_CAP,
-        .desc      = "Using KVM without %(capability), %(feature) unavailable",
+         QERR_KVM_MISSING_CAP,
+         "Using KVM without %(capability), %(feature) unavailable",
     },
     {
-        .error_fmt = QERR_MIGRATION_ACTIVE,
-        .desc      = "There's a migration process in progress",
+         QERR_MIGRATION_ACTIVE,
+         "There's a migration process in progress",
     },
     {
-        .error_fmt = QERR_MIGRATION_NOT_SUPPORTED,
-        .desc      = "State blocked by non-migratable device '%(device)'",
+         QERR_MIGRATION_NOT_SUPPORTED,
+         "State blocked by non-migratable device '%(device)'",
     },
     {
-        .error_fmt = QERR_MIGRATION_EXPECTED,
-        .desc      = "An incoming migration is expected before this command can be executed",
+         QERR_MIGRATION_EXPECTED,
+         "An incoming migration is expected before this command can be executed",
     },
     {
-        .error_fmt = QERR_MISSING_PARAMETER,
-        .desc      = "Parameter '%(name)' is missing",
+         QERR_MISSING_PARAMETER,
+         "Parameter '%(name)' is missing",
     },
     {
-        .error_fmt = QERR_NO_BUS_FOR_DEVICE,
-        .desc      = "No '%(bus)' bus found for device '%(device)'",
+         QERR_NO_BUS_FOR_DEVICE,
+         "No '%(bus)' bus found for device '%(device)'",
     },
     {
-        .error_fmt = QERR_NOT_SUPPORTED,
-        .desc      = "Not supported",
+         QERR_NOT_SUPPORTED,
+         "Not supported",
     },
     {
-        .error_fmt = QERR_OPEN_FILE_FAILED,
-        .desc      = "Could not open '%(filename)'",
+         QERR_OPEN_FILE_FAILED,
+         "Could not open '%(filename)'",
     },
     {
-        .error_fmt = QERR_PERMISSION_DENIED,
-        .desc      = "Insufficient permission to perform this operation",
+         QERR_PERMISSION_DENIED,
+         "Insufficient permission to perform this operation",
     },
     {
-        .error_fmt = QERR_PROPERTY_NOT_FOUND,
-        .desc      = "Property '%(device).%(property)' not found",
+         QERR_PROPERTY_NOT_FOUND,
+         "Property '%(device).%(property)' not found",
     },
     {
-        .error_fmt = QERR_PROPERTY_VALUE_BAD,
-        .desc      = "Property '%(device).%(property)' doesn't take value '%(value)'",
+         QERR_PROPERTY_VALUE_BAD,
+         "Property '%(device).%(property)' doesn't take value '%(value)'",
     },
     {
-        .error_fmt = QERR_PROPERTY_VALUE_IN_USE,
-        .desc      = "Property '%(device).%(property)' can't take value '%(value)', it's in use",
+         QERR_PROPERTY_VALUE_IN_USE,
+         "Property '%(device).%(property)' can't take value '%(value)', it's in use",
     },
     {
-        .error_fmt = QERR_PROPERTY_VALUE_NOT_FOUND,
-        .desc      = "Property '%(device).%(property)' can't find value '%(value)'",
+         QERR_PROPERTY_VALUE_NOT_FOUND,
+         "Property '%(device).%(property)' can't find value '%(value)'",
     },
     {
-        .error_fmt = QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
-        .desc      = "Property '%(device).%(property)' doesn't take "
+         QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
+         "Property '%(device).%(property)' doesn't take "
                      "value '%(value)', it's not a power of 2",
     },
     {
-        .error_fmt = QERR_PROPERTY_VALUE_OUT_OF_RANGE,
-        .desc      = "Property '%(device).%(property)' doesn't take "
+         QERR_PROPERTY_VALUE_OUT_OF_RANGE,
+         "Property '%(device).%(property)' doesn't take "
                      "value %(value) (minimum: %(min), maximum: %(max))",
     },
     {
-        .error_fmt = QERR_QGA_COMMAND_FAILED,
-        .desc      = "Guest agent command failed, error was '%(message)'",
+         QERR_QGA_COMMAND_FAILED,
+         "Guest agent command failed, error was '%(message)'",
     },
     {
-        .error_fmt = QERR_QGA_LOGGING_FAILED,
-        .desc      = "Guest agent failed to log non-optional log statement",
+         QERR_QGA_LOGGING_FAILED,
+         "Guest agent failed to log non-optional log statement",
     },
     {
-        .error_fmt = QERR_QMP_BAD_INPUT_OBJECT,
-        .desc      = "Expected '%(expected)' in QMP input",
+         QERR_QMP_BAD_INPUT_OBJECT,
+         "Expected '%(expected)' in QMP input",
     },
     {
-        .error_fmt = QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
-        .desc      = "QMP input object member '%(member)' expects '%(expected)'",
+         QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
+         "QMP input object member '%(member)' expects '%(expected)'",
     },
     {
-        .error_fmt = QERR_QMP_EXTRA_MEMBER,
-        .desc      = "QMP input object member '%(member)' is unexpected",
+         QERR_QMP_EXTRA_MEMBER,
+         "QMP input object member '%(member)' is unexpected",
     },
     {
-        .error_fmt = QERR_RESET_REQUIRED,
-        .desc      = "Resetting the Virtual Machine is required",
+         QERR_RESET_REQUIRED,
+         "Resetting the Virtual Machine is required",
     },
     {
-        .error_fmt = QERR_SET_PASSWD_FAILED,
-        .desc      = "Could not set password",
+         QERR_SET_PASSWD_FAILED,
+         "Could not set password",
     },
     {
-        .error_fmt = QERR_TOO_MANY_FILES,
-        .desc      = "Too many open files",
+         QERR_TOO_MANY_FILES,
+         "Too many open files",
     },
     {
-        .error_fmt = QERR_UNDEFINED_ERROR,
-        .desc      = "An undefined error has occurred",
+         QERR_UNDEFINED_ERROR,
+         "An undefined error has occurred",
     },
     {
-        .error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
-        .desc      = "'%(device)' uses a %(format) feature which is not "
+         QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+         "'%(device)' uses a %(format) feature which is not "
                      "supported by this qemu version: %(feature)",
     },
     {
-        .error_fmt = QERR_UNSUPPORTED,
-        .desc      = "this feature or command is not currently supported",
+         QERR_UNSUPPORTED,
+         "this feature or command is not currently supported",
     },
     {
-        .error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
-        .desc      = "Migration is disabled when VirtFS export path '%(path)' "
+         QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
+         "Migration is disabled when VirtFS export path '%(path)' "
                      "is mounted in the guest using mount_tag '%(tag)'",
     },
     {
-        .error_fmt = QERR_VNC_SERVER_FAILED,
-        .desc      = "Could not start VNC server on %(target)",
+         QERR_VNC_SERVER_FAILED,
+         "Could not start VNC server on %(target)",
     },
     {
-        .error_fmt = QERR_SOCKET_CONNECT_FAILED,
-        .desc      = "Failed to connect to socket",
+         QERR_SOCKET_CONNECT_FAILED,
+         "Failed to connect to socket",
     },
     {
-        .error_fmt = QERR_SOCKET_LISTEN_FAILED,
-        .desc      = "Failed to set socket to listening mode",
+         QERR_SOCKET_LISTEN_FAILED,
+         "Failed to set socket to listening mode",
     },
     {
-        .error_fmt = QERR_SOCKET_BIND_FAILED,
-        .desc      = "Failed to bind socket",
+         QERR_SOCKET_BIND_FAILED,
+         "Failed to bind socket",
     },
     {
-        .error_fmt = QERR_SOCKET_CREATE_FAILED,
-        .desc      = "Failed to create socket",
+         QERR_SOCKET_CREATE_FAILED,
+         "Failed to create socket",
     },
     {}
 };
diff --git a/qerror.h b/qerror.h
index 52ce58d..2e6a49d 100644
--- a/qerror.h
+++ b/qerror.h
@@ -19,8 +19,8 @@
 #include <stdarg.h>
 
 typedef struct QErrorStringTable {
-    const char *desc;
     const char *error_fmt;
+    const char *desc;
 } QErrorStringTable;
 
 typedef struct QError {
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 26/34] error, qerror: add ErrorClass argument to error functions
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (24 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 25/34] qerror: qerror_table: don't use C99 struct initializers Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 16:57   ` Markus Armbruster
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 27/34] qerror: add proper ErrorClass value for QERR_ macros Luiz Capitulino
                   ` (9 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

The new argument is added to functions qerror_report() and error_set().
It's stored in Error and QError. qerror_report_err() is also updated to
take care of it.

The QERR_ macros are changed to contain a place holder value for the
new argument, so that the value is used on all current calls to
qerror_report() and error_set() (and also to initialize qerror_table[]).

Next commit will update the QERR_ macros with a proper ErrorClass
value.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 error.c  |   6 ++-
 error.h  |   3 +-
 qerror.c |  10 +++--
 qerror.h | 145 ++++++++++++++++++++++++++++++++-------------------------------
 4 files changed, 88 insertions(+), 76 deletions(-)

diff --git a/error.c b/error.c
index 216cb08..6c8f7b8 100644
--- a/error.c
+++ b/error.c
@@ -14,6 +14,7 @@
 #include "error.h"
 #include "qjson.h"
 #include "qdict.h"
+#include "qapi-types.h"
 #include "error_int.h"
 #include "qerror.h"
 
@@ -21,9 +22,10 @@ struct Error
 {
     QDict *obj;
     char *msg;
+    ErrorClass err_class;
 };
 
-void error_set(Error **errp, const char *fmt, ...)
+void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...)
 {
     Error *err;
     va_list ap;
@@ -39,6 +41,7 @@ void error_set(Error **errp, const char *fmt, ...)
     err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap));
     va_end(ap);
     err->msg = qerror_format(fmt, err->obj);
+    err->err_class = err_class;
 
     *errp = err;
 }
@@ -49,6 +52,7 @@ Error *error_copy(const Error *err)
 
     err_new = g_malloc0(sizeof(*err));
     err_new->msg = g_strdup(err->msg);
+    err_new->err_class = err->err_class;
     err_new->obj = err->obj;
     QINCREF(err_new->obj);
 
diff --git a/error.h b/error.h
index 3d038a5..905613a 100644
--- a/error.h
+++ b/error.h
@@ -13,6 +13,7 @@
 #define ERROR_H
 
 #include "compiler.h"
+#include "qapi-types.h"
 #include <stdbool.h>
 
 /**
@@ -26,7 +27,7 @@ typedef struct Error Error;
  * Currently, qerror.h defines these error formats.  This function is not
  * meant to be used outside of QEMU.
  */
-void error_set(Error **err, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(3, 4);
 
 /**
  * Returns true if an indirect pointer to an error is pointing to a valid
diff --git a/qerror.c b/qerror.c
index 664efb3..19a1902 100644
--- a/qerror.c
+++ b/qerror.c
@@ -386,13 +386,15 @@ static QDict *error_obj_from_fmt_no_fail(const char *fmt, va_list *va)
  *
  * Return strong reference.
  */
-static QError *qerror_from_info(const char *fmt, va_list *va)
+static QError *qerror_from_info(ErrorClass err_class, const char *fmt,
+                                va_list *va)
 {
     QError *qerr;
 
     qerr = qerror_new();
     loc_save(&qerr->loc);
 
+    qerr->err_class = err_class;
     qerr->error = error_obj_from_fmt_no_fail(fmt, va);
     qerr->err_msg = qerror_format(fmt, qerr->error);
 
@@ -518,13 +520,13 @@ static void qerror_print(QError *qerror)
     QDECREF(qstring);
 }
 
-void qerror_report(const char *fmt, ...)
+void qerror_report(ErrorClass eclass, const char *fmt, ...)
 {
     va_list va;
     QError *qerror;
 
     va_start(va, fmt);
-    qerror = qerror_from_info(fmt, &va);
+    qerror = qerror_from_info(eclass, fmt, &va);
     va_end(va);
 
     if (monitor_cur_is_qmp()) {
@@ -540,6 +542,7 @@ struct Error
 {
     QDict *obj;
     char *msg;
+    ErrorClass err_class;
 };
 
 void qerror_report_err(Error *err)
@@ -551,6 +554,7 @@ void qerror_report_err(Error *err)
     QINCREF(err->obj);
     qerr->error = err->obj;
     qerr->err_msg = g_strdup(err->msg);
+    qerr->err_class = err->err_class;
 
     if (monitor_cur_is_qmp()) {
         monitor_set_error(cur_mon, qerr);
diff --git a/qerror.h b/qerror.h
index 2e6a49d..bcc93f8 100644
--- a/qerror.h
+++ b/qerror.h
@@ -16,9 +16,11 @@
 #include "qstring.h"
 #include "qemu-error.h"
 #include "error.h"
+#include "qapi-types.h"
 #include <stdarg.h>
 
 typedef struct QErrorStringTable {
+    ErrorClass err_class;
     const char *error_fmt;
     const char *desc;
 } QErrorStringTable;
@@ -28,10 +30,11 @@ typedef struct QError {
     QDict *error;
     Location loc;
     char *err_msg;
+    ErrorClass err_class;
 } QError;
 
 QString *qerror_human(const QError *qerror);
-void qerror_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+void qerror_report(ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
 void qerror_report_err(Error *err);
 void assert_no_error(Error *err);
 char *qerror_format(const char *fmt, QDict *error);
@@ -42,214 +45,214 @@ char *qerror_format(const char *fmt, QDict *error);
  * Use scripts/check-qerror.sh to check.
  */
 #define QERR_ADD_CLIENT_FAILED \
-    "{ 'class': 'AddClientFailed', 'data': {} }"
+    -1, "{ 'class': 'AddClientFailed', 'data': {} }"
 
 #define QERR_AMBIGUOUS_PATH \
-    "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }"
+    -1, "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }"
 
 #define QERR_BAD_BUS_FOR_DEVICE \
-    "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
+    -1, "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
 
 #define QERR_BASE_NOT_FOUND \
-    "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }"
+    -1, "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }"
 
 #define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
-    "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
+    -1, "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
 
 #define QERR_BUFFER_OVERRUN \
-    "{ 'class': 'BufferOverrun', 'data': {} }"
+    -1, "{ 'class': 'BufferOverrun', 'data': {} }"
 
 #define QERR_BUS_NO_HOTPLUG \
-    "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
+    -1, "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
 
 #define QERR_BUS_NOT_FOUND \
-    "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
+    -1, "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
 
 #define QERR_COMMAND_DISABLED \
-    "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
+    -1, "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
 
 #define QERR_COMMAND_NOT_FOUND \
-    "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+    -1, "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
 
 #define QERR_DEVICE_ENCRYPTED \
-    "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
+    -1, "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
 
 #define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
-    "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+    -1, "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
 
 #define QERR_DEVICE_HAS_NO_MEDIUM \
-    "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }"
+    -1, "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_INIT_FAILED \
-    "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
+    -1, "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_IN_USE \
-    "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
+    -1, "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_IS_READ_ONLY \
-    "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
+    -1, "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_LOCKED \
-    "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
+    -1, "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_MULTIPLE_BUSSES \
-    "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
+    -1, "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_NO_BUS \
-    "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
+    -1, "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_NO_HOTPLUG \
-    "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
+    -1, "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_NOT_ACTIVE \
-    "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
+    -1, "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_NOT_ENCRYPTED \
-    "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }"
+    -1, "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_NOT_FOUND \
-    "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }"
+    -1, "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_NOT_REMOVABLE \
-    "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
+    -1, "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
 
 #define QERR_DUPLICATE_ID \
-    "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
+    -1, "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
 
 #define QERR_FD_NOT_FOUND \
-    "{ 'class': 'FdNotFound', 'data': { 'name': %s } }"
+    -1, "{ 'class': 'FdNotFound', 'data': { 'name': %s } }"
 
 #define QERR_FD_NOT_SUPPLIED \
-    "{ 'class': 'FdNotSupplied', 'data': {} }"
+    -1, "{ 'class': 'FdNotSupplied', 'data': {} }"
 
 #define QERR_FEATURE_DISABLED \
-    "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
+    -1, "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
 
 #define QERR_INVALID_BLOCK_FORMAT \
-    "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
+    -1, "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
 
 #define QERR_INVALID_OPTION_GROUP \
-    "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }"
+    -1, "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }"
 
 #define QERR_INVALID_PARAMETER \
-    "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
+    -1, "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
 
 #define QERR_INVALID_PARAMETER_COMBINATION \
-    "{ 'class': 'InvalidParameterCombination', 'data': {} }"
+    -1, "{ 'class': 'InvalidParameterCombination', 'data': {} }"
 
 #define QERR_INVALID_PARAMETER_TYPE \
-    "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
+    -1, "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
 
 #define QERR_INVALID_PARAMETER_VALUE \
-    "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }"
+    -1, "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }"
 
 #define QERR_INVALID_PASSWORD \
-    "{ 'class': 'InvalidPassword', 'data': {} }"
+    -1, "{ 'class': 'InvalidPassword', 'data': {} }"
 
 #define QERR_IO_ERROR \
-    "{ 'class': 'IOError', 'data': {} }"
+    -1, "{ 'class': 'IOError', 'data': {} }"
 
 #define QERR_JSON_PARSE_ERROR \
-    "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
+    -1, "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
 
 #define QERR_JSON_PARSING \
-    "{ 'class': 'JSONParsing', 'data': {} }"
+    -1, "{ 'class': 'JSONParsing', 'data': {} }"
 
 #define QERR_KVM_MISSING_CAP \
-    "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
+    -1, "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
 
 #define QERR_MIGRATION_ACTIVE \
-    "{ 'class': 'MigrationActive', 'data': {} }"
+    -1, "{ 'class': 'MigrationActive', 'data': {} }"
 
 #define QERR_MIGRATION_NOT_SUPPORTED \
-    "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }"
+    -1, "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }"
 
 #define QERR_MIGRATION_EXPECTED \
-    "{ 'class': 'MigrationExpected', 'data': {} }"
+    -1, "{ 'class': 'MigrationExpected', 'data': {} }"
 
 #define QERR_MISSING_PARAMETER \
-    "{ 'class': 'MissingParameter', 'data': { 'name': %s } }"
+    -1, "{ 'class': 'MissingParameter', 'data': { 'name': %s } }"
 
 #define QERR_NO_BUS_FOR_DEVICE \
-    "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }"
+    -1, "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }"
 
 #define QERR_NOT_SUPPORTED \
-    "{ 'class': 'NotSupported', 'data': {} }"
+    -1, "{ 'class': 'NotSupported', 'data': {} }"
 
 #define QERR_OPEN_FILE_FAILED \
-    "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }"
+    -1, "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }"
 
 #define QERR_PERMISSION_DENIED \
-    "{ 'class': 'PermissionDenied', 'data': {} }"
+    -1, "{ 'class': 'PermissionDenied', 'data': {} }"
 
 #define QERR_PROPERTY_NOT_FOUND \
-    "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }"
+    -1, "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }"
 
 #define QERR_PROPERTY_VALUE_BAD \
-    "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+    -1, "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
 
 #define QERR_PROPERTY_VALUE_IN_USE \
-    "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+    -1, "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
 
 #define QERR_PROPERTY_VALUE_NOT_FOUND \
-    "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+    -1, "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
 
 #define QERR_PROPERTY_VALUE_NOT_POWER_OF_2 \
-    "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \
+    -1, "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \
     "'device': %s, 'property': %s, 'value': %"PRId64" } }"
 
 #define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
-    "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
+    -1, "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
 
 #define QERR_QGA_COMMAND_FAILED \
-    "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
+    -1, "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
 
 #define QERR_QGA_LOGGING_FAILED \
-    "{ 'class': 'QgaLoggingFailed', 'data': {} }"
+    -1, "{ 'class': 'QgaLoggingFailed', 'data': {} }"
 
 #define QERR_QMP_BAD_INPUT_OBJECT \
-    "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
+    -1, "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
 
 #define QERR_QMP_BAD_INPUT_OBJECT_MEMBER \
-    "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }"
+    -1, "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }"
 
 #define QERR_QMP_EXTRA_MEMBER \
-    "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }"
+    -1, "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }"
 
 #define QERR_RESET_REQUIRED \
-    "{ 'class': 'ResetRequired', 'data': {} }"
+    -1, "{ 'class': 'ResetRequired', 'data': {} }"
 
 #define QERR_SET_PASSWD_FAILED \
-    "{ 'class': 'SetPasswdFailed', 'data': {} }"
+    -1, "{ 'class': 'SetPasswdFailed', 'data': {} }"
 
 #define QERR_TOO_MANY_FILES \
-    "{ 'class': 'TooManyFiles', 'data': {} }"
+    -1, "{ 'class': 'TooManyFiles', 'data': {} }"
 
 #define QERR_UNDEFINED_ERROR \
-    "{ 'class': 'UndefinedError', 'data': {} }"
+    -1, "{ 'class': 'UndefinedError', 'data': {} }"
 
 #define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
-    "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
+    -1, "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
 
 #define QERR_UNSUPPORTED \
-    "{ 'class': 'Unsupported', 'data': {} }"
+    -1, "{ 'class': 'Unsupported', 'data': {} }"
 
 #define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
-    "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
+    -1, "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
 
 #define QERR_VNC_SERVER_FAILED \
-    "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
+    -1, "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
 
 #define QERR_SOCKET_CONNECT_FAILED \
-    "{ 'class': 'SockConnectFailed', 'data': {} }"
+    -1, "{ 'class': 'SockConnectFailed', 'data': {} }"
 
 #define QERR_SOCKET_LISTEN_FAILED \
-    "{ 'class': 'SockListenFailed', 'data': {} }"
+    -1, "{ 'class': 'SockListenFailed', 'data': {} }"
 
 #define QERR_SOCKET_BIND_FAILED \
-    "{ 'class': 'SockBindFailed', 'data': {} }"
+    -1, "{ 'class': 'SockBindFailed', 'data': {} }"
 
 #define QERR_SOCKET_CREATE_FAILED \
-    "{ 'class': 'SockCreateFailed', 'data': {} }"
+    -1, "{ 'class': 'SockCreateFailed', 'data': {} }"
 
 #endif /* QERROR_H */
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 27/34] qerror: add proper ErrorClass value for QERR_ macros
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (25 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 26/34] error, qerror: add ErrorClass argument to error functions Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 17:01   ` Markus Armbruster
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 28/34] error: add error_get_class() Luiz Capitulino
                   ` (8 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

This commit replaces the place holder value for the ErrorClass
argument with a proper ErrorClass value for all QERR_ macros.

All current errors are mapped to GenericError, except for errors
CommandNotFound, DeviceNotActive, DeviceNotFound, KVMMissingCap and
MigrationExpected, which are maintained as they are today.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qerror.h | 140 +++++++++++++++++++++++++++++++--------------------------------
 1 file changed, 70 insertions(+), 70 deletions(-)

diff --git a/qerror.h b/qerror.h
index bcc93f8..94346cb 100644
--- a/qerror.h
+++ b/qerror.h
@@ -45,214 +45,214 @@ char *qerror_format(const char *fmt, QDict *error);
  * Use scripts/check-qerror.sh to check.
  */
 #define QERR_ADD_CLIENT_FAILED \
-    -1, "{ 'class': 'AddClientFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'AddClientFailed', 'data': {} }"
 
 #define QERR_AMBIGUOUS_PATH \
-    -1, "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }"
 
 #define QERR_BAD_BUS_FOR_DEVICE \
-    -1, "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
 
 #define QERR_BASE_NOT_FOUND \
-    -1, "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }"
 
 #define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
-    -1, "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
 
 #define QERR_BUFFER_OVERRUN \
-    -1, "{ 'class': 'BufferOverrun', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BufferOverrun', 'data': {} }"
 
 #define QERR_BUS_NO_HOTPLUG \
-    -1, "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
 
 #define QERR_BUS_NOT_FOUND \
-    -1, "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
 
 #define QERR_COMMAND_DISABLED \
-    -1, "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
 
 #define QERR_COMMAND_NOT_FOUND \
-    -1, "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+    ERROR_CLASS_COMMAND_NOT_FOUND, "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
 
 #define QERR_DEVICE_ENCRYPTED \
-    -1, "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
 
 #define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
-    -1, "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
 
 #define QERR_DEVICE_HAS_NO_MEDIUM \
-    -1, "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_INIT_FAILED \
-    -1, "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_IN_USE \
-    -1, "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_IS_READ_ONLY \
-    -1, "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_LOCKED \
-    -1, "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_MULTIPLE_BUSSES \
-    -1, "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_NO_BUS \
-    -1, "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_NO_HOTPLUG \
-    -1, "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_NOT_ACTIVE \
-    -1, "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
+    ERROR_CLASS_DEVICE_NOT_ACTIVE, "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_NOT_ENCRYPTED \
-    -1, "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_NOT_FOUND \
-    -1, "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }"
+    ERROR_CLASS_DEVICE_NOT_FOUND, "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_NOT_REMOVABLE \
-    -1, "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
 
 #define QERR_DUPLICATE_ID \
-    -1, "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
 
 #define QERR_FD_NOT_FOUND \
-    -1, "{ 'class': 'FdNotFound', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'FdNotFound', 'data': { 'name': %s } }"
 
 #define QERR_FD_NOT_SUPPLIED \
-    -1, "{ 'class': 'FdNotSupplied', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'FdNotSupplied', 'data': {} }"
 
 #define QERR_FEATURE_DISABLED \
-    -1, "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
 
 #define QERR_INVALID_BLOCK_FORMAT \
-    -1, "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
 
 #define QERR_INVALID_OPTION_GROUP \
-    -1, "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }"
 
 #define QERR_INVALID_PARAMETER \
-    -1, "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
 
 #define QERR_INVALID_PARAMETER_COMBINATION \
-    -1, "{ 'class': 'InvalidParameterCombination', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameterCombination', 'data': {} }"
 
 #define QERR_INVALID_PARAMETER_TYPE \
-    -1, "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
 
 #define QERR_INVALID_PARAMETER_VALUE \
-    -1, "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }"
 
 #define QERR_INVALID_PASSWORD \
-    -1, "{ 'class': 'InvalidPassword', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidPassword', 'data': {} }"
 
 #define QERR_IO_ERROR \
-    -1, "{ 'class': 'IOError', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'IOError', 'data': {} }"
 
 #define QERR_JSON_PARSE_ERROR \
-    -1, "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
 
 #define QERR_JSON_PARSING \
-    -1, "{ 'class': 'JSONParsing', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'JSONParsing', 'data': {} }"
 
 #define QERR_KVM_MISSING_CAP \
-    -1, "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
+    ERROR_CLASS_K_V_M_MISSING_CAP, "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
 
 #define QERR_MIGRATION_ACTIVE \
-    -1, "{ 'class': 'MigrationActive', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'MigrationActive', 'data': {} }"
 
 #define QERR_MIGRATION_NOT_SUPPORTED \
-    -1, "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }"
 
 #define QERR_MIGRATION_EXPECTED \
-    -1, "{ 'class': 'MigrationExpected', 'data': {} }"
+    ERROR_CLASS_MIGRATION_EXPECTED, "{ 'class': 'MigrationExpected', 'data': {} }"
 
 #define QERR_MISSING_PARAMETER \
-    -1, "{ 'class': 'MissingParameter', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'MissingParameter', 'data': { 'name': %s } }"
 
 #define QERR_NO_BUS_FOR_DEVICE \
-    -1, "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }"
 
 #define QERR_NOT_SUPPORTED \
-    -1, "{ 'class': 'NotSupported', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'NotSupported', 'data': {} }"
 
 #define QERR_OPEN_FILE_FAILED \
-    -1, "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }"
 
 #define QERR_PERMISSION_DENIED \
-    -1, "{ 'class': 'PermissionDenied', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PermissionDenied', 'data': {} }"
 
 #define QERR_PROPERTY_NOT_FOUND \
-    -1, "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }"
 
 #define QERR_PROPERTY_VALUE_BAD \
-    -1, "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
 
 #define QERR_PROPERTY_VALUE_IN_USE \
-    -1, "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
 
 #define QERR_PROPERTY_VALUE_NOT_FOUND \
-    -1, "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
 
 #define QERR_PROPERTY_VALUE_NOT_POWER_OF_2 \
-    -1, "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \
     "'device': %s, 'property': %s, 'value': %"PRId64" } }"
 
 #define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
-    -1, "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
 
 #define QERR_QGA_COMMAND_FAILED \
-    -1, "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
 
 #define QERR_QGA_LOGGING_FAILED \
-    -1, "{ 'class': 'QgaLoggingFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QgaLoggingFailed', 'data': {} }"
 
 #define QERR_QMP_BAD_INPUT_OBJECT \
-    -1, "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
 
 #define QERR_QMP_BAD_INPUT_OBJECT_MEMBER \
-    -1, "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }"
 
 #define QERR_QMP_EXTRA_MEMBER \
-    -1, "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }"
 
 #define QERR_RESET_REQUIRED \
-    -1, "{ 'class': 'ResetRequired', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'ResetRequired', 'data': {} }"
 
 #define QERR_SET_PASSWD_FAILED \
-    -1, "{ 'class': 'SetPasswdFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SetPasswdFailed', 'data': {} }"
 
 #define QERR_TOO_MANY_FILES \
-    -1, "{ 'class': 'TooManyFiles', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'TooManyFiles', 'data': {} }"
 
 #define QERR_UNDEFINED_ERROR \
-    -1, "{ 'class': 'UndefinedError', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'UndefinedError', 'data': {} }"
 
 #define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
-    -1, "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
 
 #define QERR_UNSUPPORTED \
-    -1, "{ 'class': 'Unsupported', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'Unsupported', 'data': {} }"
 
 #define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
-    -1, "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
 
 #define QERR_VNC_SERVER_FAILED \
-    -1, "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
 
 #define QERR_SOCKET_CONNECT_FAILED \
-    -1, "{ 'class': 'SockConnectFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockConnectFailed', 'data': {} }"
 
 #define QERR_SOCKET_LISTEN_FAILED \
-    -1, "{ 'class': 'SockListenFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockListenFailed', 'data': {} }"
 
 #define QERR_SOCKET_BIND_FAILED \
-    -1, "{ 'class': 'SockBindFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockBindFailed', 'data': {} }"
 
 #define QERR_SOCKET_CREATE_FAILED \
-    -1, "{ 'class': 'SockCreateFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockCreateFailed', 'data': {} }"
 
 #endif /* QERROR_H */
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 28/34] error: add error_get_class()
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (26 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 27/34] qerror: add proper ErrorClass value for QERR_ macros Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 29/34] qmp: switch to the new error format on the wire Luiz Capitulino
                   ` (7 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 error.c | 5 +++++
 error.h | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/error.c b/error.c
index 6c8f7b8..15a2d06 100644
--- a/error.c
+++ b/error.c
@@ -69,6 +69,11 @@ const char *error_get_pretty(Error *err)
     return err->msg;
 }
 
+ErrorClass error_get_class(const Error *err)
+{
+    return err->err_class;
+}
+
 void error_free(Error *err)
 {
     if (err) {
diff --git a/error.h b/error.h
index 905613a..7b85b50 100644
--- a/error.h
+++ b/error.h
@@ -46,6 +46,11 @@ Error *error_copy(const Error *err);
 const char *error_get_pretty(Error *err);
 
 /**
+ * Get the error class of an error object.
+ */
+ErrorClass error_get_class(const Error *err);
+
+/**
  * Propagate an error to an indirect pointer to an error.  This function will
  * always transfer ownership of the error reference and handles the case where
  * dst_err is NULL correctly.  Errors after the first are discarded.
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 29/34] qmp: switch to the new error format on the wire
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (27 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 28/34] error: add error_get_class() Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 17:12   ` Markus Armbruster
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 30/34] qemu-ga: " Luiz Capitulino
                   ` (6 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

IMPORTANT: this BREAKS QMP's compatibility for the error response.

This commit changes QMP's wire protocol to make use of the simpler
error format introduced by previous commits.

There are two important (and mostly incompatible) changes:

 1. Almost all error classes have been replaced by GenericError. The
    only classes that are still supported for compatibility with
    libvirt are: CommandNotFound, DeviceNotActive, KVMMissingCap,
    DeviceNotFound and MigrationExpected

 2. The 'data' field of the error dictionary is gone

As an example, an error response like:

  { "error": { "class": "DeviceNotRemovable",
               "data": { "device": "virtio0" },
               "desc": "Device 'virtio0' is not removable" } }

Will now be emitted as:

  { "error": { "class": "GenericError",
               "desc": "Device 'virtio0' is not removable" } }

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 QMP/qmp-spec.txt | 10 +++-------
 monitor.c        | 18 +++++++++++++-----
 qmp-commands.hx  |  3 +--
 3 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt
index 1ba916c..a277896 100644
--- a/QMP/qmp-spec.txt
+++ b/QMP/qmp-spec.txt
@@ -106,14 +106,11 @@ completed because of an error condition.
 
 The format is:
 
-{ "error": { "class": json-string, "data": json-object, "desc": json-string },
-  "id": json-value }
+{ "error": { "class": json-string, "desc": json-string }, "id": json-value }
 
  Where,
 
-- The "class" member contains the error class name (eg. "ServiceUnavailable")
-- The "data" member contains specific error data and is defined in a
-  per-command basis, it will be an empty json-object if the error has no data
+- The "class" member contains the error class name (eg. "GenericError")
 - The "desc" member is a human-readable error message. Clients should
   not attempt to parse this message.
 - The "id" member contains the transaction identification associated with
@@ -173,8 +170,7 @@ S: {"return": {"enabled": true, "present": true}, "id": "example"}
 ------------------
 
 C: { "execute": }
-S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data":
-{}}}
+S: {"error": {"class": "GenericError", "desc": "Invalid JSON syntax" } }
 
 3.5 Powerdown event
 -------------------
diff --git a/monitor.c b/monitor.c
index aa57167..3694590 100644
--- a/monitor.c
+++ b/monitor.c
@@ -353,16 +353,26 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data)
     QDECREF(json);
 }
 
+static QDict *build_qmp_error_dict(const QError *err)
+{
+    QObject *obj;
+
+    obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %p } }",
+                             ErrorClass_lookup[err->err_class],
+                             qerror_human(err));
+
+    return qobject_to_qdict(obj);
+}
+
 static void monitor_protocol_emitter(Monitor *mon, QObject *data)
 {
     QDict *qmp;
 
     trace_monitor_protocol_emitter(mon);
 
-    qmp = qdict_new();
-
     if (!monitor_has_error(mon)) {
         /* success response */
+        qmp = qdict_new();
         if (data) {
             qobject_incref(data);
             qdict_put_obj(qmp, "return", data);
@@ -372,9 +382,7 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data)
         }
     } else {
         /* error response */
-        qdict_put(mon->error->error, "desc", qerror_human(mon->error));
-        qdict_put(qmp, "error", mon->error->error);
-        QINCREF(mon->error->error);
+        qmp = build_qmp_error_dict(mon->error);
         QDECREF(mon->error);
         mon->error = NULL;
     }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index e3cf3c5..e520b51 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -435,8 +435,7 @@ Example:
 -> { "execute": "inject-nmi" }
 <- { "return": {} }
 
-Note: inject-nmi is only supported for x86 guest currently, it will
-      returns "Unsupported" error for non-x86 guest.
+Note: inject-nmi is only supported for x86 guests.
 
 EQMP
 
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 30/34] qemu-ga: switch to the new error format on the wire
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (28 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 29/34] qmp: switch to the new error format on the wire Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-03 17:44   ` Michael Roth
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 31/34] error, qerror: pass desc string to error calls Luiz Capitulino
                   ` (5 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

IMPORTANT: this BREAKS qemu-ga compatibility for the error response.

Instead of returning something like:

{ "error": { "class": "InvalidParameterValue",
             "data": {"name": "mode", "expected": "halt|powerdown|reboot" } } }

qemu-ga now returns:

 { "error": { "class": "GenericError",
              "desc": "Parameter 'mode' expects halt|powerdown|reboot" } }

Notice that this is also a bug fix, as qemu-ga wasn't returning the
human message.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 Makefile.objs       |  2 +-
 qapi/qmp-core.h     |  1 +
 qapi/qmp-dispatch.c | 10 +++++++++-
 qemu-ga.c           |  4 ++--
 4 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/Makefile.objs b/Makefile.objs
index 5ebbcfa..cbfbba5 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -220,7 +220,7 @@ universal-obj-y += $(qapi-obj-y)
 ######################################################################
 # guest agent
 
-qga-obj-y = qga/ qemu-ga.o module.o
+qga-obj-y = qga/ qemu-ga.o module.o qapi-types.o qapi-visit.o
 qga-obj-$(CONFIG_WIN32) += oslib-win32.o
 qga-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-sockets.o qemu-option.o
 
diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
index b0f64ba..00446cf 100644
--- a/qapi/qmp-core.h
+++ b/qapi/qmp-core.h
@@ -49,6 +49,7 @@ void qmp_disable_command(const char *name);
 void qmp_enable_command(const char *name);
 bool qmp_command_is_enabled(const char *name);
 char **qmp_get_command_list(void);
+QObject *qmp_build_error_object(Error *errp);
 
 #endif
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 122c1a2..ec613f8 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -14,6 +14,7 @@
 #include "qemu-objects.h"
 #include "qapi/qmp-core.h"
 #include "json-parser.h"
+#include "qapi-types.h"
 #include "error.h"
 #include "error_int.h"
 #include "qerror.h"
@@ -109,6 +110,13 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp)
     return ret;
 }
 
+QObject *qmp_build_error_object(Error *errp)
+{
+    return qobject_from_jsonf("{ 'class': %s, 'desc': %s }",
+                              ErrorClass_lookup[error_get_class(errp)],
+                              error_get_pretty(errp));
+}
+
 QObject *qmp_dispatch(QObject *request)
 {
     Error *err = NULL;
@@ -119,7 +127,7 @@ QObject *qmp_dispatch(QObject *request)
 
     rsp = qdict_new();
     if (err) {
-        qdict_put_obj(rsp, "error", error_get_qobject(err));
+        qdict_put_obj(rsp, "error", qmp_build_error_object(err));
         error_free(err);
     } else if (ret) {
         qdict_put_obj(rsp, "return", ret);
diff --git a/qemu-ga.c b/qemu-ga.c
index 8199da7..f45bc61 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -515,7 +515,7 @@ static void process_event(JSONMessageParser *parser, QList *tokens)
         } else {
             g_warning("failed to parse event: %s", error_get_pretty(err));
         }
-        qdict_put_obj(qdict, "error", error_get_qobject(err));
+        qdict_put_obj(qdict, "error", qmp_build_error_object(err));
         error_free(err);
     } else {
         qdict = qobject_to_qdict(obj);
@@ -532,7 +532,7 @@ static void process_event(JSONMessageParser *parser, QList *tokens)
             qdict = qdict_new();
             g_warning("unrecognized payload format");
             error_set(&err, QERR_UNSUPPORTED);
-            qdict_put_obj(qdict, "error", error_get_qobject(err));
+            qdict_put_obj(qdict, "error", qmp_build_error_object(err));
             error_free(err);
         }
         ret = send_response(s, QOBJECT(qdict));
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 31/34] error, qerror: pass desc string to error calls
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (29 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 30/34] qemu-ga: " Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 17:19   ` Markus Armbruster
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 32/34] qerror: drop qerror_table and qerror_format() Luiz Capitulino
                   ` (4 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

This commit changes all QERR_ macros to contain a human message (ie.
the desc string found in qerr_table[]) instead of a json dictionary
in string format.

Before this commit, error_set() and qerror_report() would receive
a json dictionary in string format and build a qobject from it. Now,
both function receive a human message instead and the qobject is
not built anymore.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 error.c  |   5 ++-
 qerror.c |  44 ++------------------
 qerror.h | 141 +++++++++++++++++++++++++++++++--------------------------------
 3 files changed, 76 insertions(+), 114 deletions(-)

diff --git a/error.c b/error.c
index 15a2d06..740824c 100644
--- a/error.c
+++ b/error.c
@@ -29,6 +29,7 @@ void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...)
 {
     Error *err;
     va_list ap;
+    char msg[2048];
 
     if (errp == NULL) {
         return;
@@ -38,9 +39,9 @@ void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...)
     err = g_malloc0(sizeof(*err));
 
     va_start(ap, fmt);
-    err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap));
+    vsnprintf(msg, sizeof(msg), fmt, ap);
     va_end(ap);
-    err->msg = qerror_format(fmt, err->obj);
+    err->msg = g_strdup(msg);
     err->err_class = err_class;
 
     *errp = err;
diff --git a/qerror.c b/qerror.c
index 19a1902..db6bb47 100644
--- a/qerror.c
+++ b/qerror.c
@@ -342,45 +342,6 @@ static QError *qerror_new(void)
     return qerr;
 }
 
-static QDict *error_obj_from_fmt_no_fail(const char *fmt, va_list *va)
-{
-    QObject *obj;
-    QDict *ret;
-
-    obj = qobject_from_jsonv(fmt, va);
-    if (!obj) {
-        fprintf(stderr, "invalid json in error dict '%s'\n", fmt);
-        abort();
-    }
-    if (qobject_type(obj) != QTYPE_QDICT) {
-        fprintf(stderr, "error is not a dict '%s'\n", fmt);
-        abort();
-    }
-
-    ret = qobject_to_qdict(obj);
-    obj = qdict_get(ret, "class");
-    if (!obj) {
-        fprintf(stderr, "missing 'class' key in '%s'\n", fmt);
-        abort();
-    }
-    if (qobject_type(obj) != QTYPE_QSTRING) {
-        fprintf(stderr, "'class' key value should be a string in '%s'\n", fmt);
-        abort();
-    }
-
-    obj = qdict_get(ret, "data");
-    if (!obj) {
-        fprintf(stderr, "missing 'data' key in '%s'\n", fmt);
-        abort();
-    }
-    if (qobject_type(obj) != QTYPE_QDICT) {
-        fprintf(stderr, "'data' key value should be a dict in '%s'\n", fmt);
-        abort();
-    }
-
-    return ret;
-}
-
 /**
  * qerror_from_info(): Create a new QError from error information
  *
@@ -390,13 +351,14 @@ static QError *qerror_from_info(ErrorClass err_class, const char *fmt,
                                 va_list *va)
 {
     QError *qerr;
+    char msg[2048];
 
     qerr = qerror_new();
     loc_save(&qerr->loc);
 
     qerr->err_class = err_class;
-    qerr->error = error_obj_from_fmt_no_fail(fmt, va);
-    qerr->err_msg = qerror_format(fmt, qerr->error);
+    vsnprintf(msg, sizeof(msg), fmt, *va);
+    qerr->err_msg = g_strdup(msg);
 
     return qerr;
 }
diff --git a/qerror.h b/qerror.h
index 94346cb..475415e 100644
--- a/qerror.h
+++ b/qerror.h
@@ -45,214 +45,213 @@ char *qerror_format(const char *fmt, QDict *error);
  * Use scripts/check-qerror.sh to check.
  */
 #define QERR_ADD_CLIENT_FAILED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'AddClientFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Could not add client"
 
 #define QERR_AMBIGUOUS_PATH \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Path '%s' does not uniquely identify an object"
 
 #define QERR_BAD_BUS_FOR_DEVICE \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' can't go on a %s bus"
 
 #define QERR_BASE_NOT_FOUND \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Base '%s' not found"
 
 #define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Block format '%s' used by device '%s' does not support feature '%s'"
 
 #define QERR_BUFFER_OVERRUN \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BufferOverrun', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "An internal buffer overran"
 
 #define QERR_BUS_NO_HOTPLUG \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Bus '%s' does not support hotplugging"
 
 #define QERR_BUS_NOT_FOUND \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Bus '%s' not found"
 
 #define QERR_COMMAND_DISABLED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "The command %s has been disabled for this instance"
 
 #define QERR_COMMAND_NOT_FOUND \
-    ERROR_CLASS_COMMAND_NOT_FOUND, "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+    ERROR_CLASS_COMMAND_NOT_FOUND, "The command %s has not been found"
 
 #define QERR_DEVICE_ENCRYPTED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' is encrypted (filename=%s)"
 
 #define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Migration is disabled when using feature '%s' in device '%s'"
 
 #define QERR_DEVICE_HAS_NO_MEDIUM \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' has no medium"
 
 #define QERR_DEVICE_INIT_FAILED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' could not be initialized"
 
 #define QERR_DEVICE_IN_USE \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' is in use"
 
 #define QERR_DEVICE_IS_READ_ONLY \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' is read only"
 
 #define QERR_DEVICE_LOCKED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' is locked"
 
 #define QERR_DEVICE_MULTIPLE_BUSSES \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' has multiple child busses"
 
 #define QERR_DEVICE_NO_BUS \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' has no child bus"
 
 #define QERR_DEVICE_NO_HOTPLUG \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' does not support hotplugging"
 
 #define QERR_DEVICE_NOT_ACTIVE \
-    ERROR_CLASS_DEVICE_NOT_ACTIVE, "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
+    ERROR_CLASS_DEVICE_NOT_ACTIVE, "Device '%s' has not been activated"
 
 #define QERR_DEVICE_NOT_ENCRYPTED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' is not encrypted"
 
 #define QERR_DEVICE_NOT_FOUND \
-    ERROR_CLASS_DEVICE_NOT_FOUND, "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }"
+    ERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found"
 
 #define QERR_DEVICE_NOT_REMOVABLE \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' is not removable"
 
 #define QERR_DUPLICATE_ID \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Duplicate ID '%s' for %s"
 
 #define QERR_FD_NOT_FOUND \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'FdNotFound', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "File descriptor named '%s' not found"
 
 #define QERR_FD_NOT_SUPPLIED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'FdNotSupplied', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "No file descriptor supplied via SCM_RIGHTS"
 
 #define QERR_FEATURE_DISABLED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "The feature '%s' is not enabled"
 
 #define QERR_INVALID_BLOCK_FORMAT \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Invalid block format '%s'"
 
 #define QERR_INVALID_OPTION_GROUP \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "There is no option group '%s'"
 
 #define QERR_INVALID_PARAMETER \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Invalid parameter '%s'"
 
 #define QERR_INVALID_PARAMETER_COMBINATION \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameterCombination', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Invalid parameter combination"
 
 #define QERR_INVALID_PARAMETER_TYPE \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Invalid parameter type for '%s', expected: %s"
 
 #define QERR_INVALID_PARAMETER_VALUE \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Parameter '%s' expects %s"
 
 #define QERR_INVALID_PASSWORD \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidPassword', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Password incorrect"
 
 #define QERR_IO_ERROR \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'IOError', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "An IO error has occurred"
 
 #define QERR_JSON_PARSE_ERROR \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "JSON parse error, %s"
 
 #define QERR_JSON_PARSING \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'JSONParsing', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Invalid JSON syntax"
 
 #define QERR_KVM_MISSING_CAP \
-    ERROR_CLASS_K_V_M_MISSING_CAP, "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
+    ERROR_CLASS_K_V_M_MISSING_CAP, "Using KVM without %s, %s unavailable"
 
 #define QERR_MIGRATION_ACTIVE \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'MigrationActive', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "There's a migration process in progress"
 
 #define QERR_MIGRATION_NOT_SUPPORTED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }"
+    ERROR_CLASS_GENERIC_ERROR, "State blocked by non-migratable device '%s'"
 
 #define QERR_MIGRATION_EXPECTED \
-    ERROR_CLASS_MIGRATION_EXPECTED, "{ 'class': 'MigrationExpected', 'data': {} }"
+    ERROR_CLASS_MIGRATION_EXPECTED, "An incoming migration is expected before this command can be executed"
 
 #define QERR_MISSING_PARAMETER \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'MissingParameter', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Parameter '%s' is missing"
 
 #define QERR_NO_BUS_FOR_DEVICE \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "No '%s' bus found for device '%s'"
 
 #define QERR_NOT_SUPPORTED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'NotSupported', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Not supported"
 
 #define QERR_OPEN_FILE_FAILED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Could not open '%s'"
 
 #define QERR_PERMISSION_DENIED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PermissionDenied', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Insufficient permission to perform this operation"
 
 #define QERR_PROPERTY_NOT_FOUND \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' not found"
 
 #define QERR_PROPERTY_VALUE_BAD \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' doesn't take value '%s'"
 
 #define QERR_PROPERTY_VALUE_IN_USE \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' can't take value '%s', it's in use"
 
 #define QERR_PROPERTY_VALUE_NOT_FOUND \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' can't find value '%s'"
 
 #define QERR_PROPERTY_VALUE_NOT_POWER_OF_2 \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \
-    "'device': %s, 'property': %s, 'value': %"PRId64" } }"
+    ERROR_CLASS_GENERIC_ERROR, "Property %s.%s doesn't take value '%" PRId64 "', it's not a power of 2"
 
 #define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
+    ERROR_CLASS_GENERIC_ERROR, "Property %s.%s doesn't take value %" PRId64 " (minimum: %" PRId64 ", maximum: %" PRId64 ")"
 
 #define QERR_QGA_COMMAND_FAILED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Guest agent command failed, error was '%s'"
 
 #define QERR_QGA_LOGGING_FAILED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QgaLoggingFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Guest agent failed to log non-optional log statement"
 
 #define QERR_QMP_BAD_INPUT_OBJECT \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Expected '%s' in QMP input"
 
 #define QERR_QMP_BAD_INPUT_OBJECT_MEMBER \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "QMP input object member '%s' expects '%s'"
 
 #define QERR_QMP_EXTRA_MEMBER \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "QMP input object member '%s' is unexpected"
 
 #define QERR_RESET_REQUIRED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'ResetRequired', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Resetting the Virtual Machine is required"
 
 #define QERR_SET_PASSWD_FAILED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SetPasswdFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Could not set password"
 
 #define QERR_TOO_MANY_FILES \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'TooManyFiles', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Too many open files"
 
 #define QERR_UNDEFINED_ERROR \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'UndefinedError', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "An undefined error has occurred"
 
 #define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "'%s' uses a %s feature which is not supported by this qemu version: %s"
 
 #define QERR_UNSUPPORTED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'Unsupported', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "this feature or command is not currently supported"
 
 #define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'"
 
 #define QERR_VNC_SERVER_FAILED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Could not start VNC server on %s"
 
 #define QERR_SOCKET_CONNECT_FAILED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockConnectFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Failed to connect to socket"
 
 #define QERR_SOCKET_LISTEN_FAILED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockListenFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Failed to set socket to listening mode"
 
 #define QERR_SOCKET_BIND_FAILED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockBindFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Failed to bind socket"
 
 #define QERR_SOCKET_CREATE_FAILED \
-    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockCreateFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Failed to create socket"
 
 #endif /* QERROR_H */
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 32/34] qerror: drop qerror_table and qerror_format()
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (30 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 31/34] error, qerror: pass desc string to error calls Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 33/34] error: drop error_get_qobject()/error_set_qobject() Luiz Capitulino
                   ` (3 subsequent siblings)
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

They are unused since last commit.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qerror.c | 400 ---------------------------------------------------------------
 qerror.h |   7 --
 2 files changed, 407 deletions(-)

diff --git a/qerror.c b/qerror.c
index db6bb47..e1606d3 100644
--- a/qerror.c
+++ b/qerror.c
@@ -23,311 +23,6 @@ static const QType qerror_type = {
 };
 
 /**
- * The 'desc' parameter is a printf-like string, the format of the format
- * string is:
- *
- * %(KEY)
- *
- * Where KEY is a QDict key, which has to be passed to qerror_from_info().
- *
- * Example:
- *
- * "foo error on device: %(device) slot: %(slot_nr)"
- *
- * A single percent sign can be printed if followed by a second one,
- * for example:
- *
- * "running out of foo: %(foo)%%"
- *
- * Please keep the entries in alphabetical order.
- * Use scripts/check-qerror.sh to check.
- */
-static const QErrorStringTable qerror_table[] = {
-    {
-         QERR_ADD_CLIENT_FAILED,
-         "Could not add client",
-    },
-    {
-         QERR_AMBIGUOUS_PATH,
-         "Path '%(path)' does not uniquely identify an object"
-    },
-    {
-         QERR_BAD_BUS_FOR_DEVICE,
-         "Device '%(device)' can't go on a %(bad_bus_type) bus",
-    },
-    {
-         QERR_BASE_NOT_FOUND,
-         "Base '%(base)' not found",
-    },
-    {
-         QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
-         "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
-    },
-    {
-         QERR_BUS_NO_HOTPLUG,
-         "Bus '%(bus)' does not support hotplugging",
-    },
-    {
-         QERR_BUS_NOT_FOUND,
-         "Bus '%(bus)' not found",
-    },
-    {
-         QERR_COMMAND_DISABLED,
-         "The command %(name) has been disabled for this instance",
-    },
-    {
-         QERR_COMMAND_NOT_FOUND,
-         "The command %(name) has not been found",
-    },
-    {
-         QERR_DEVICE_ENCRYPTED,
-         "Device '%(device)' is encrypted (filename is '%(filename)')",
-    },
-    {
-         QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
-         "Migration is disabled when using feature '%(feature)' in device '%(device)'",
-    },
-    {
-         QERR_DEVICE_HAS_NO_MEDIUM,
-         "Device '%(device)' has no medium",
-    },
-    {
-         QERR_DEVICE_INIT_FAILED,
-         "Device '%(device)' could not be initialized",
-    },
-    {
-         QERR_DEVICE_IN_USE,
-         "Device '%(device)' is in use",
-    },
-    {
-         QERR_DEVICE_IS_READ_ONLY,
-         "Device '%(device)' is read only",
-    },
-    {
-         QERR_DEVICE_LOCKED,
-         "Device '%(device)' is locked",
-    },
-    {
-         QERR_DEVICE_MULTIPLE_BUSSES,
-         "Device '%(device)' has multiple child busses",
-    },
-    {
-         QERR_DEVICE_NO_BUS,
-         "Device '%(device)' has no child bus",
-    },
-    {
-         QERR_DEVICE_NO_HOTPLUG,
-         "Device '%(device)' does not support hotplugging",
-    },
-    {
-         QERR_DEVICE_NOT_ACTIVE,
-         "Device '%(device)' has not been activated",
-    },
-    {
-         QERR_DEVICE_NOT_ENCRYPTED,
-         "Device '%(device)' is not encrypted",
-    },
-    {
-         QERR_DEVICE_NOT_FOUND,
-         "Device '%(device)' not found",
-    },
-    {
-         QERR_DEVICE_NOT_REMOVABLE,
-         "Device '%(device)' is not removable",
-    },
-    {
-         QERR_DUPLICATE_ID,
-         "Duplicate ID '%(id)' for %(object)",
-    },
-    {
-         QERR_FD_NOT_FOUND,
-         "File descriptor named '%(name)' not found",
-    },
-    {
-         QERR_FD_NOT_SUPPLIED,
-         "No file descriptor supplied via SCM_RIGHTS",
-    },
-    {
-         QERR_FEATURE_DISABLED,
-         "The feature '%(name)' is not enabled",
-    },
-    {
-         QERR_INVALID_BLOCK_FORMAT,
-         "Invalid block format '%(name)'",
-    },
-    {
-         QERR_INVALID_OPTION_GROUP,
-         "There is no option group '%(group)'",
-    },
-    {
-         QERR_INVALID_PARAMETER,
-         "Invalid parameter '%(name)'",
-    },
-    {
-         QERR_INVALID_PARAMETER_COMBINATION,
-         "Invalid parameter combination",
-    },
-    {
-         QERR_INVALID_PARAMETER_TYPE,
-         "Invalid parameter type for '%(name)', expected: %(expected)",
-    },
-    {
-         QERR_INVALID_PARAMETER_VALUE,
-         "Parameter '%(name)' expects %(expected)",
-    },
-    {
-         QERR_INVALID_PASSWORD,
-         "Password incorrect",
-    },
-    {
-         QERR_IO_ERROR,
-         "An IO error has occurred",
-    },
-    {
-         QERR_JSON_PARSE_ERROR,
-         "JSON parse error, %(message)",
-
-    },
-    {
-         QERR_JSON_PARSING,
-         "Invalid JSON syntax",
-    },
-    {
-         QERR_KVM_MISSING_CAP,
-         "Using KVM without %(capability), %(feature) unavailable",
-    },
-    {
-         QERR_MIGRATION_ACTIVE,
-         "There's a migration process in progress",
-    },
-    {
-         QERR_MIGRATION_NOT_SUPPORTED,
-         "State blocked by non-migratable device '%(device)'",
-    },
-    {
-         QERR_MIGRATION_EXPECTED,
-         "An incoming migration is expected before this command can be executed",
-    },
-    {
-         QERR_MISSING_PARAMETER,
-         "Parameter '%(name)' is missing",
-    },
-    {
-         QERR_NO_BUS_FOR_DEVICE,
-         "No '%(bus)' bus found for device '%(device)'",
-    },
-    {
-         QERR_NOT_SUPPORTED,
-         "Not supported",
-    },
-    {
-         QERR_OPEN_FILE_FAILED,
-         "Could not open '%(filename)'",
-    },
-    {
-         QERR_PERMISSION_DENIED,
-         "Insufficient permission to perform this operation",
-    },
-    {
-         QERR_PROPERTY_NOT_FOUND,
-         "Property '%(device).%(property)' not found",
-    },
-    {
-         QERR_PROPERTY_VALUE_BAD,
-         "Property '%(device).%(property)' doesn't take value '%(value)'",
-    },
-    {
-         QERR_PROPERTY_VALUE_IN_USE,
-         "Property '%(device).%(property)' can't take value '%(value)', it's in use",
-    },
-    {
-         QERR_PROPERTY_VALUE_NOT_FOUND,
-         "Property '%(device).%(property)' can't find value '%(value)'",
-    },
-    {
-         QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
-         "Property '%(device).%(property)' doesn't take "
-                     "value '%(value)', it's not a power of 2",
-    },
-    {
-         QERR_PROPERTY_VALUE_OUT_OF_RANGE,
-         "Property '%(device).%(property)' doesn't take "
-                     "value %(value) (minimum: %(min), maximum: %(max))",
-    },
-    {
-         QERR_QGA_COMMAND_FAILED,
-         "Guest agent command failed, error was '%(message)'",
-    },
-    {
-         QERR_QGA_LOGGING_FAILED,
-         "Guest agent failed to log non-optional log statement",
-    },
-    {
-         QERR_QMP_BAD_INPUT_OBJECT,
-         "Expected '%(expected)' in QMP input",
-    },
-    {
-         QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
-         "QMP input object member '%(member)' expects '%(expected)'",
-    },
-    {
-         QERR_QMP_EXTRA_MEMBER,
-         "QMP input object member '%(member)' is unexpected",
-    },
-    {
-         QERR_RESET_REQUIRED,
-         "Resetting the Virtual Machine is required",
-    },
-    {
-         QERR_SET_PASSWD_FAILED,
-         "Could not set password",
-    },
-    {
-         QERR_TOO_MANY_FILES,
-         "Too many open files",
-    },
-    {
-         QERR_UNDEFINED_ERROR,
-         "An undefined error has occurred",
-    },
-    {
-         QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
-         "'%(device)' uses a %(format) feature which is not "
-                     "supported by this qemu version: %(feature)",
-    },
-    {
-         QERR_UNSUPPORTED,
-         "this feature or command is not currently supported",
-    },
-    {
-         QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
-         "Migration is disabled when VirtFS export path '%(path)' "
-                     "is mounted in the guest using mount_tag '%(tag)'",
-    },
-    {
-         QERR_VNC_SERVER_FAILED,
-         "Could not start VNC server on %(target)",
-    },
-    {
-         QERR_SOCKET_CONNECT_FAILED,
-         "Failed to connect to socket",
-    },
-    {
-         QERR_SOCKET_LISTEN_FAILED,
-         "Failed to set socket to listening mode",
-    },
-    {
-         QERR_SOCKET_BIND_FAILED,
-         "Failed to bind socket",
-    },
-    {
-         QERR_SOCKET_CREATE_FAILED,
-         "Failed to create socket",
-    },
-    {}
-};
-
-/**
  * qerror_new(): Create a new QError
  *
  * Return strong reference.
@@ -363,101 +58,6 @@ static QError *qerror_from_info(ErrorClass err_class, const char *fmt,
     return qerr;
 }
 
-static void parse_error(const QErrorStringTable *entry, int c)
-{
-    fprintf(stderr, "expected '%c' in '%s'", c, entry->desc);
-    abort();
-}
-
-static const char *append_field(QDict *error, QString *outstr,
-                                const QErrorStringTable *entry,
-                                const char *start)
-{
-    QObject *obj;
-    QDict *qdict;
-    QString *key_qs;
-    const char *end, *key;
-
-    if (*start != '%')
-        parse_error(entry, '%');
-    start++;
-    if (*start != '(')
-        parse_error(entry, '(');
-    start++;
-
-    end = strchr(start, ')');
-    if (!end)
-        parse_error(entry, ')');
-
-    key_qs = qstring_from_substr(start, 0, end - start - 1);
-    key = qstring_get_str(key_qs);
-
-    qdict = qobject_to_qdict(qdict_get(error, "data"));
-    obj = qdict_get(qdict, key);
-    if (!obj) {
-        abort();
-    }
-
-    switch (qobject_type(obj)) {
-        case QTYPE_QSTRING:
-            qstring_append(outstr, qdict_get_str(qdict, key));
-            break;
-        case QTYPE_QINT:
-            qstring_append_int(outstr, qdict_get_int(qdict, key));
-            break;
-        default:
-            abort();
-    }
-
-    QDECREF(key_qs);
-    return ++end;
-}
-
-static QString *qerror_format_desc(QDict *error,
-                                   const QErrorStringTable *entry)
-{
-    QString *qstring;
-    const char *p;
-
-    assert(entry != NULL);
-
-    qstring = qstring_new();
-
-    for (p = entry->desc; *p != '\0';) {
-        if (*p != '%') {
-            qstring_append_chr(qstring, *p++);
-        } else if (*(p + 1) == '%') {
-            qstring_append_chr(qstring, '%');
-            p += 2;
-        } else {
-            p = append_field(error, qstring, entry, p);
-        }
-    }
-
-    return qstring;
-}
-
-char *qerror_format(const char *fmt, QDict *error)
-{
-    const QErrorStringTable *entry = NULL;
-    QString *qstr;
-    char *ret;
-    int i;
-
-    for (i = 0; qerror_table[i].error_fmt; i++) {
-        if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
-            entry = &qerror_table[i];
-            break;
-        }
-    }
-
-    qstr = qerror_format_desc(error, entry);
-    ret = g_strdup(qstring_get_str(qstr));
-    QDECREF(qstr);
-
-    return ret;
-}
-
 /**
  * qerror_human(): Format QError data into human-readable string.
  */
diff --git a/qerror.h b/qerror.h
index 475415e..2299e00 100644
--- a/qerror.h
+++ b/qerror.h
@@ -19,12 +19,6 @@
 #include "qapi-types.h"
 #include <stdarg.h>
 
-typedef struct QErrorStringTable {
-    ErrorClass err_class;
-    const char *error_fmt;
-    const char *desc;
-} QErrorStringTable;
-
 typedef struct QError {
     QObject_HEAD;
     QDict *error;
@@ -37,7 +31,6 @@ QString *qerror_human(const QError *qerror);
 void qerror_report(ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
 void qerror_report_err(Error *err);
 void assert_no_error(Error *err);
-char *qerror_format(const char *fmt, QDict *error);
 
 /*
  * QError class list
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 33/34] error: drop error_get_qobject()/error_set_qobject()
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (31 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 32/34] qerror: drop qerror_table and qerror_format() Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 17:20   ` Markus Armbruster
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 34/34] error, qerror: drop QDict member Luiz Capitulino
                   ` (2 subsequent siblings)
  35 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

They are not used anymore. Also drops error_int.h.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 error.c             | 20 --------------------
 error_int.h         | 28 ----------------------------
 qapi/qmp-dispatch.c |  1 -
 qemu-ga.c           |  1 -
 4 files changed, 50 deletions(-)
 delete mode 100644 error_int.h

diff --git a/error.c b/error.c
index 740824c..5c6c90f 100644
--- a/error.c
+++ b/error.c
@@ -15,7 +15,6 @@
 #include "qjson.h"
 #include "qdict.h"
 #include "qapi-types.h"
-#include "error_int.h"
 #include "qerror.h"
 
 struct Error
@@ -92,22 +91,3 @@ void error_propagate(Error **dst_err, Error *local_err)
         error_free(local_err);
     }
 }
-
-QObject *error_get_qobject(Error *err)
-{
-    QINCREF(err->obj);
-    return QOBJECT(err->obj);
-}
-
-void error_set_qobject(Error **errp, QObject *obj)
-{
-    Error *err;
-    if (errp == NULL) {
-        return;
-    }
-    err = g_malloc0(sizeof(*err));
-    err->obj = qobject_to_qdict(obj);
-    qobject_incref(obj);
-
-    *errp = err;
-}
diff --git a/error_int.h b/error_int.h
deleted file mode 100644
index 4b00d08..0000000
--- a/error_int.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * QEMU Error Objects
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.  See
- * the COPYING.LIB file in the top-level directory.
- */
-#ifndef QEMU_ERROR_INT_H
-#define QEMU_ERROR_INT_H
-
-#include "qemu-common.h"
-#include "qobject.h"
-#include "qdict.h"
-#include "error.h"
-
-/**
- * Internal QEMU functions for working with Error.
- *
- * These are used to convert QErrors to Errors
- */
-QObject *error_get_qobject(Error *err);
-void error_set_qobject(Error **errp, QObject *obj);
-  
-#endif
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index ec613f8..4085994 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -16,7 +16,6 @@
 #include "json-parser.h"
 #include "qapi-types.h"
 #include "error.h"
-#include "error_int.h"
 #include "qerror.h"
 
 static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
diff --git a/qemu-ga.c b/qemu-ga.c
index f45bc61..cd61527 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -28,7 +28,6 @@
 #include "module.h"
 #include "signal.h"
 #include "qerror.h"
-#include "error_int.h"
 #include "qapi/qmp-core.h"
 #include "qga/channel.h"
 #ifdef _WIN32
-- 
1.7.11.2.249.g31c7954.dirty

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

* [Qemu-devel] [PATCH 34/34] error, qerror: drop QDict member
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (32 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 33/34] error: drop error_get_qobject()/error_set_qobject() Luiz Capitulino
@ 2012-08-02  1:02 ` Luiz Capitulino
  2012-08-02 13:41 ` [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
  2012-08-02 17:22 ` Markus Armbruster
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02  1:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, aliguori, armbru, mdroth, pbonzini, eblake

Used to store error information, but it's unused now.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 error.c  | 4 ----
 qerror.c | 4 ----
 qerror.h | 1 -
 3 files changed, 9 deletions(-)

diff --git a/error.c b/error.c
index 5c6c90f..b07ffa0 100644
--- a/error.c
+++ b/error.c
@@ -19,7 +19,6 @@
 
 struct Error
 {
-    QDict *obj;
     char *msg;
     ErrorClass err_class;
 };
@@ -53,8 +52,6 @@ Error *error_copy(const Error *err)
     err_new = g_malloc0(sizeof(*err));
     err_new->msg = g_strdup(err->msg);
     err_new->err_class = err->err_class;
-    err_new->obj = err->obj;
-    QINCREF(err_new->obj);
 
     return err_new;
 }
@@ -77,7 +74,6 @@ ErrorClass error_get_class(const Error *err)
 void error_free(Error *err)
 {
     if (err) {
-        QDECREF(err->obj);
         g_free(err->msg);
         g_free(err);
     }
diff --git a/qerror.c b/qerror.c
index e1606d3..6d924fb 100644
--- a/qerror.c
+++ b/qerror.c
@@ -102,7 +102,6 @@ void qerror_report(ErrorClass eclass, const char *fmt, ...)
 /* Evil... */
 struct Error
 {
-    QDict *obj;
     char *msg;
     ErrorClass err_class;
 };
@@ -113,8 +112,6 @@ void qerror_report_err(Error *err)
 
     qerr = qerror_new();
     loc_save(&qerr->loc);
-    QINCREF(err->obj);
-    qerr->error = err->obj;
     qerr->err_msg = g_strdup(err->msg);
     qerr->err_class = err->err_class;
 
@@ -156,7 +153,6 @@ static void qerror_destroy_obj(QObject *obj)
     assert(obj != NULL);
     qerr = qobject_to_qerror(obj);
 
-    QDECREF(qerr->error);
     g_free(qerr->err_msg);
     g_free(qerr);
 }
diff --git a/qerror.h b/qerror.h
index 2299e00..3f17c52 100644
--- a/qerror.h
+++ b/qerror.h
@@ -21,7 +21,6 @@
 
 typedef struct QError {
     QObject_HEAD;
-    QDict *error;
     Location loc;
     char *err_msg;
     ErrorClass err_class;
-- 
1.7.11.2.249.g31c7954.dirty

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

* Re: [Qemu-devel] [PATCH 06/34] qerror: avoid passing qerr pointer
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 06/34] qerror: avoid passing qerr pointer Luiz Capitulino
@ 2012-08-02 11:23   ` Markus Armbruster
  2012-08-02 13:44     ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 11:23 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> Helps dropping/modifying qerror functions.
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  qerror.c | 24 ++++++++++++------------
>  1 file changed, 12 insertions(+), 12 deletions(-)
>
> diff --git a/qerror.c b/qerror.c
> index 5efccec..59025ea 100644
> --- a/qerror.c
> +++ b/qerror.c
> @@ -346,10 +346,10 @@ static QError *qerror_new(void)
>      return qerr;
>  }
>  
> -static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
> -                                               const char *fmt, va_list *va)
> +static QDict *error_obj_from_fmt_no_fail(const char *fmt, va_list *va)

Elsewhere, we use FOO_nofail() for a variant of FOO() that must not
fail.

Call this function just error_obj_from_fmt()?

Or if you think the name must convey it can't fail:
error_obj_from_fmt_nofail()?

>  {
>      QObject *obj;
> +    QDict *ret;
>  
>      obj = qobject_from_jsonv(fmt, va);
>      if (!obj) {
> @@ -361,9 +361,8 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
>          abort();
>      }
>  
> -    qerr->error = qobject_to_qdict(obj);
> -
> -    obj = qdict_get(qerr->error, "class");
> +    ret = qobject_to_qdict(obj);
> +    obj = qdict_get(ret, "class");
>      if (!obj) {
>          fprintf(stderr, "missing 'class' key in '%s'\n", fmt);
>          abort();
> @@ -372,8 +371,8 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
>          fprintf(stderr, "'class' key value should be a string in '%s'\n", fmt);
>          abort();
>      }
> -    
> -    obj = qdict_get(qerr->error, "data");
> +
> +    obj = qdict_get(ret, "data");
>      if (!obj) {
>          fprintf(stderr, "missing 'data' key in '%s'\n", fmt);
>          abort();
> @@ -382,9 +381,11 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
>          fprintf(stderr, "'data' key value should be a dict in '%s'\n", fmt);
>          abort();
>      }
> +
> +    return ret;
>  }
>  
> -static void qerror_set_desc(QError *qerr, const char *fmt)
> +static const QErrorStringTable *get_desc_no_fail(const char *fmt)

Likewise.

>  {
>      int i;
>  
> @@ -392,8 +393,7 @@ static void qerror_set_desc(QError *qerr, const char *fmt)
>  
>      for (i = 0; qerror_table[i].error_fmt; i++) {
>          if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
> -            qerr->entry = &qerror_table[i];
> -            return;
> +            return &qerror_table[i];
>          }
>      }
>  
> @@ -426,8 +426,8 @@ static QError *qerror_from_info(const char *file, int linenr, const char *func,
>      qerr->file = file;
>      qerr->func = func;
>  
> -    qerror_set_data(qerr, fmt, va);
> -    qerror_set_desc(qerr, fmt);
> +    qerr->error = error_obj_from_fmt_no_fail(fmt, va);
> +    qerr->entry = get_desc_no_fail(fmt);
>  
>      return qerr;
>  }

Turns side effects on qerr into a nice clean return values.  Good!

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

* Re: [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field Luiz Capitulino
@ 2012-08-02 11:35   ` Markus Armbruster
  2012-08-02 13:54     ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 11:35 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  block.c          | 1 +
>  qapi-schema.json | 7 +++++--
>  2 files changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/block.c b/block.c
> index b38940b..9c113b8 100644
> --- a/block.c
> +++ b/block.c
> @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
>              info->value->inserted->ro = bs->read_only;
>              info->value->inserted->drv = g_strdup(bs->drv->format_name);
>              info->value->inserted->encrypted = bs->encrypted;
> +            info->value->inserted->valid_encryption_key = bs->valid_key;
>              if (bs->backing_file[0]) {
>                  info->value->inserted->has_backing_file = true;
>                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
> diff --git a/qapi-schema.json b/qapi-schema.json
> index bc55ed2..1b2d7f5 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -400,6 +400,8 @@
>  #
>  # @encrypted: true if the backing device is encrypted
>  #
> +# @valid_encryption_key: true if a valid encryption key has been set
> +#
>  # @bps: total throughput limit in bytes per second is specified
>  #
>  # @bps_rd: read throughput limit in bytes per second is specified
> @@ -419,8 +421,9 @@
>  { 'type': 'BlockDeviceInfo',
>    'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
>              '*backing_file': 'str', 'encrypted': 'bool',
> -            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
> -            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
> +            'valid_encryption_key': 'bool', 'bps': 'int',
> +            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
> +            'iops_rd': 'int', 'iops_wr': 'int'} }
>  
>  ##
>  # @BlockDeviceIoStatus:

BlockDeviceInfo is API, isn't it?

Note that bs->valid_key currently implies bs->encrypted.  bs->valid_key
&& !bs->encrypted is impossible.  Should we make valid_encryption_key
only available when encrypted?

valid_encryption_key is a bit long for my taste.  Yours may be
different.

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

* Re: [Qemu-devel] [PATCH 12/34] hmp: hmp_cont(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 12/34] hmp: hmp_cont(): don't rely on QERR_DEVICE_ENCRYPTED Luiz Capitulino
@ 2012-08-02 11:53   ` Markus Armbruster
  2012-08-02 14:22     ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 11:53 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> This commit changes hmp_cont() to loop through all block devices
> and proactively set an encryption key for any encrypted device
> without a valid one.
>
> This change is needed because QERR_DEVICE_ENCRYPTED is going to be
> dropped by a future commit.
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  hmp.c | 43 +++++++++++++++++++++++++------------------
>  1 file changed, 25 insertions(+), 18 deletions(-)
>
> diff --git a/hmp.c b/hmp.c
> index 6b72a64..1ebeb63 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -610,34 +610,41 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
>  
>  static void hmp_cont_cb(void *opaque, int err)
>  {
> -    Monitor *mon = opaque;
> -
>      if (!err) {
> -        hmp_cont(mon, NULL);
> +        qmp_cont(NULL);
>      }
>  }
>  
> -void hmp_cont(Monitor *mon, const QDict *qdict)
> +static bool blockinfo_is_encrypted(const BlockInfo *bdev)
>  {
> -    Error *errp = NULL;
> -
> -    qmp_cont(&errp);
> -    if (error_is_set(&errp)) {
> -        if (error_is_type(errp, QERR_DEVICE_ENCRYPTED)) {
> -            const char *device;
> +    return (bdev->inserted && bdev->inserted->encrypted);
> +}
>  
> -            /* The device is encrypted. Ask the user for the password
> -               and retry */
> +static bool blockinfo_key_is_set(const BlockInfo *bdev)
> +{
> +    return (bdev->inserted && bdev->inserted->valid_encryption_key);
> +}
>  
> -            device = error_get_field(errp, "device");
> -            assert(device != NULL);
> +void hmp_cont(Monitor *mon, const QDict *qdict)
> +{
> +    BlockInfoList *bdev_list, *bdev;
> +    Error *errp = NULL;
>  
> -            monitor_read_block_device_key(mon, device, hmp_cont_cb, mon);
> -            error_free(errp);
> -            return;
> +    bdev_list = qmp_query_block(NULL);
> +    for (bdev = bdev_list; bdev; bdev = bdev->next) {
> +        if (blockinfo_is_encrypted(bdev->value) &&
> +            !blockinfo_key_is_set(bdev->value)) {
> +                monitor_read_block_device_key(mon, bdev->value->device,
> +                                              hmp_cont_cb, NULL);
> +                goto out;
>          }
> -        hmp_handle_error(mon, &errp);
>      }
> +
> +    qmp_cont(&errp);
> +    hmp_handle_error(mon, &errp);
> +
> +out:
> +    qapi_free_BlockInfoList(bdev_list);
>  }
>  
>  void hmp_system_wakeup(Monitor *mon, const QDict *qdict)

Quote my previous analysis:

Diff makes this change look worse than it is.  Odd: M-x ediff gets it
right.  Anyway, here's how I think it works:

Unchanged qmp_cont(): search the bdrv_states for the first encrypted one
without a key.  If found, set err argument to QERR_DEVICE_ENCRYPTED.
Other errors unrelated to encrypted devices are also possible.

hmp_cont() before: try qmp_cont().  If we get QERR_DEVICE_ENCRYPTED,
extract the device from the error object, and prompt for its key, with a
callback that retries hmp_cont() if the key was provided.

After: search the bdrv_states for an encrypted one without a key.  If
there is none, qmp_cont(), no special error handling.  If there is one,
prompt for its key, with a callback that runs qmp_cont() if the key was
provided.

End quote.

Two observations:

1. I don't understand how this works for multiple encrypted BDSs without
keys.  If there are any, hmp_cont() starts reading the first one's key,
then returns.  But the callback doesn't start reading the next one's
key.  Please explain.

2. qmp_cont() uses bdrv_key_required() to test whether a BDS lacks a
key.  Your new hmp_cont() uses blockinfo_is_encrypted() &&
!blockinfo_key_is_set().  Not obvious that the two are equivalent.

I'm afraid they are not.  bdrv_key_required() checks the backing image
first:

    int bdrv_key_required(BlockDriverState *bs)
    {
        BlockDriverState *backing_hd = bs->backing_hd;

        if (backing_hd && backing_hd->encrypted && !backing_hd->valid_key)
            return 1;
        return (bs->encrypted && !bs->valid_key);
    }

Your code doesn't:

    static bool blockinfo_is_encrypted(const BlockInfo *bdev)
    {
        return (bdev->inserted && bdev->inserted->encrypted);
    }

    static bool blockinfo_key_is_set(const BlockInfo *bdev)
    {
        return (bdev->inserted && bdev->inserted->valid_encryption_key);
    }

    BlockInfoList *qmp_query_block(Error **errp)
    {
        BlockInfoList *head = NULL, *cur_item = NULL;
        BlockDriverState *bs;

        QTAILQ_FOREACH(bs, &bdrv_states, list) {
            BlockInfoList *info = g_malloc0(sizeof(*info));
[...]
            if (bs->drv) {
                info->value->has_inserted = true;
                info->value->inserted = g_malloc0(sizeof(*info->value->inserted));
[...]
                info->value->inserted->encrypted = bs->encrypted;
                info->value->inserted->valid_encryption_key = bs->valid_key;
[...]

Are you sure this is correct?

I understand we require HMP code to go via QMP for everything, to keep
HMP honest.  This case shows a drawback: duplicated code, leading to
inconsistencies.

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

* Re: [Qemu-devel] [PATCH 13/34] hmp: hmp_change(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 13/34] hmp: hmp_change(): " Luiz Capitulino
@ 2012-08-02 13:27   ` Markus Armbruster
  2012-08-02 13:46     ` Paolo Bonzini
  2012-08-02 14:42     ` Luiz Capitulino
  0 siblings, 2 replies; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 13:27 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> This commit changes the way hmp_change() checks if an encryption key
> is required for the device to be inserted.
>
> Instead of checking for QERR_DEVICE_ENCRYPTED, hmp_change() now checks
> if the device was successfully inserted, is encrypted and is missing
> an encryption key.
>
> This change is needed because QERR_DEVICE_ENCRYPTED is going to be
> dropped by a future commit.
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  hmp.c | 54 ++++++++++++++++++++++++++++++++++++++----------------
>  1 file changed, 38 insertions(+), 16 deletions(-)
>
> diff --git a/hmp.c b/hmp.c
> index 1ebeb63..ea21cf7 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -783,17 +783,29 @@ static void hmp_change_read_arg(Monitor *mon, const char *password,
>  static void cb_hmp_change_bdrv_pwd(Monitor *mon, const char *password,
>                                     void *opaque)
>  {
> -    Error *encryption_err = opaque;
> +    char *device = opaque;
>      Error *err = NULL;
> -    const char *device;
> -
> -    device = error_get_field(encryption_err, "device");
>  
>      qmp_block_passwd(device, password, &err);
>      hmp_handle_error(mon, &err);
> -    error_free(encryption_err);
>  
>      monitor_read_command(mon, 1);
> +    g_free(device);
> +}
> +
> +static void hmp_change_ask_user_key(Monitor *mon, const BlockInfo *binfo)
> +{
> +    monitor_printf(mon, "%s (%s) is encrypted.\n", binfo->device,
> +                   binfo->inserted->file);
> +
> +    if (!monitor_get_rs(mon)) {
> +        monitor_printf(mon,
> +                "terminal does not support password prompting\n");
> +        return;
> +    }
> +
> +    readline_start(monitor_get_rs(mon), "Password: ", 1,
> +                   cb_hmp_change_bdrv_pwd, g_strdup(binfo->device));

Why can't you use monitor_read_password() here?  Or even
monitor_read_bdrv_key_start()?

>  }
>  
>  void hmp_change(Monitor *mon, const QDict *qdict)
> @@ -801,6 +813,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
>      const char *device = qdict_get_str(qdict, "device");
>      const char *target = qdict_get_str(qdict, "target");
>      const char *arg = qdict_get_try_str(qdict, "arg");
> +    BlockInfoList *bdev_list = NULL, *bdev;
>      Error *err = NULL;
>  
>      if (strcmp(device, "vnc") == 0 &&
> @@ -813,21 +826,30 @@ void hmp_change(Monitor *mon, const QDict *qdict)
>      }
>  
>      qmp_change(device, target, !!arg, arg, &err);
> -    if (error_is_type(err, QERR_DEVICE_ENCRYPTED)) {
> -        monitor_printf(mon, "%s (%s) is encrypted.\n",
> -                       error_get_field(err, "device"),
> -                       error_get_field(err, "filename"));
> -        if (!monitor_get_rs(mon)) {
> -            monitor_printf(mon,
> -                    "terminal does not support password prompting\n");
> +    if (error_is_set(&err)) {
> +        /* qmp_change() failed. If 'device' is returned by qmp_query_block(),
> +         * is encrypted and doesn't have a valid encryption key set, then
> +         * either the user passed an invalid key or didn't pass one at all.
> +         * Ask the user for the key.
> +         */

Is it even possible to pass a key?

> +        bdev_list = qmp_query_block(NULL);
> +        for (bdev = bdev_list; bdev; bdev = bdev->next) {
> +            if (!strcmp(bdev->value->device, device) &&
> +                blockinfo_is_encrypted(bdev->value) &&
> +                !blockinfo_key_is_set(bdev->value)) {
> +                hmp_change_ask_user_key(mon, bdev->value);
> +                break;
> +            }
> +        }
> +
> +        if (bdev) {
>              error_free(err);
> -            return;
> +            err = NULL;
>          }
> -        readline_start(monitor_get_rs(mon), "Password: ", 1,
> -                       cb_hmp_change_bdrv_pwd, err);
> -        return;
>      }
> +
>      hmp_handle_error(mon, &err);
> +    qapi_free_BlockInfoList(bdev_list);
>  }
>  
>  void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)

Ourside the scope of this patch, but here goes anyway: I wonder what
happens when you enter an incorrect key.

If bdrv_set_key() fails, it returns

1. -EINVAL if the image isn't encrypted

2. -ENOMEDIUM under conditions that look like they shouldn't happen

   Possibly a bug.

3. Whatever the block driver's bdrv_set_key() methods returned

   Both existing methods qcow2_set_key() and qcow_set_key() return -1 on
   failure, not a negative errno.  Bug.

   I believe they can fail only when passed invalid parameters, which
   isn't the case.  In other words, they both accept *any* key.  If it's
   wrong, reads will produce garbage, and writes will destroy the image.

qmp_block_passwd() sets QERR_DEVICE_ENCRYPTED on -EINVAL, else
QERR_INVALID_PASSWORD.

hmp_handle_error() prints the message.

The media change takes effect regardless of bdrv_set_key() failures!  I
believe it takes effect first thing in qmp_bdrv_open_encrypted(), before
we even check whether a key is required, let alone prompt for it.

If the guest is running, I suspect it'll happily read and write with a
zero AES_KEY.  Reads produce garbarge, and writes destroy the image.

Problem exists both in HMP (which asks for password) and QMP (which
doesn't even try to supply one).  change with a block device argument is
unsafe unless the guest is stopped.

Encryption is yet another half-baked feature that shouldn't have been
committed.

And I hate the change command, too.

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

* Re: [Qemu-devel] [PATCH v1 00/34]: add new error format
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (33 preceding siblings ...)
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 34/34] error, qerror: drop QDict member Luiz Capitulino
@ 2012-08-02 13:41 ` Luiz Capitulino
  2012-08-02 17:22 ` Markus Armbruster
  35 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02 13:41 UTC (permalink / raw)
  To: Luiz Capitulino
  Cc: kwolf, aliguori, armbru, mdroth, qemu-devel, pbonzini, eblake

On Wed,  1 Aug 2012 22:02:20 -0300
Luiz Capitulino <lcapitulino@redhat.com> wrote:

> Quick summary first, long introduction afterwards.
> 
> From the rfc:
> 
>  o rebased on top of master
>  o dropped patch "qapi: qapi.py: allow the "'" character be escaped"
>  o split patch "qerror: drop qerror_abort()" into two patches
>  o fixed tcp_start_outgoing_migration() not to use QERR_ macros
>  o fixed qemu-ga to use the new error format
>  o dropped more unused stuff
>  o improved several changelogs
> 
> Btw, please take a special look in patches 14/34, 15/34 and 16/34.

I forgot saying here that this actually doesn't when building all targets:

LINK  i386-linux-user/qemu-i386
../qapi/qmp-dispatch.o: In function `qmp_build_error_object':
/home/lcapitulino/work/src/qmp-unstable/qapi/qmp-dispatch.c:114: undefined reference to `ErrorClass_lookup'
collect2: ld returned 1 exit status

This problem was introduced by patch 30/34, but I seem to get a different
build breakage whenever I try to fix it...

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

* Re: [Qemu-devel] [PATCH 15/34] net: inet_connect(), inet_connect_opts(): return -errno
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 15/34] net: inet_connect(), inet_connect_opts(): return -errno Luiz Capitulino
@ 2012-08-02 13:41   ` Luiz Capitulino
  2012-08-02 15:50     ` Markus Armbruster
  0 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02 13:41 UTC (permalink / raw)
  To: Luiz Capitulino
  Cc: kwolf, aliguori, armbru, mdroth, qemu-devel, pbonzini, eblake

On Wed,  1 Aug 2012 22:02:35 -0300
Luiz Capitulino <lcapitulino@redhat.com> wrote:

> Next commit wants to use this.
> 
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
> 
> This patch is an interesting case, because one of the goal of the error
> format that's being replaced was that callers could use it to know the
> error cause (with error_is_type().
> 
> However, the new error format doesn't allow this as most errors are
> class GenericError. So, we'll have to use errno to know the error cause,
> this is the case of inet_connect() when called by
> tcp_start_outgoing_migration().

I'm thinking in doing this differently. Instead of returning errno, we
could have:

 error_sete(Error **err, ErrorClass err_class, int err_no,
            const char *fmt, ...);

Then we store err_no in Error, and also add error_get_errno().

Comments?

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

* Re: [Qemu-devel] [PATCH 06/34] qerror: avoid passing qerr pointer
  2012-08-02 11:23   ` Markus Armbruster
@ 2012-08-02 13:44     ` Luiz Capitulino
  0 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02 13:44 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

On Thu, 02 Aug 2012 13:23:58 +0200
Markus Armbruster <armbru@redhat.com> wrote:

> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > Helps dropping/modifying qerror functions.
> >
> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> > ---
> >  qerror.c | 24 ++++++++++++------------
> >  1 file changed, 12 insertions(+), 12 deletions(-)
> >
> > diff --git a/qerror.c b/qerror.c
> > index 5efccec..59025ea 100644
> > --- a/qerror.c
> > +++ b/qerror.c
> > @@ -346,10 +346,10 @@ static QError *qerror_new(void)
> >      return qerr;
> >  }
> >  
> > -static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
> > -                                               const char *fmt, va_list *va)
> > +static QDict *error_obj_from_fmt_no_fail(const char *fmt, va_list *va)
> 
> Elsewhere, we use FOO_nofail() for a variant of FOO() that must not
> fail.
> 
> Call this function just error_obj_from_fmt()?
> 
> Or if you think the name must convey it can't fail:
> error_obj_from_fmt_nofail()?

It's worth it, this function is dropped later on.

> 
> >  {
> >      QObject *obj;
> > +    QDict *ret;
> >  
> >      obj = qobject_from_jsonv(fmt, va);
> >      if (!obj) {
> > @@ -361,9 +361,8 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
> >          abort();
> >      }
> >  
> > -    qerr->error = qobject_to_qdict(obj);
> > -
> > -    obj = qdict_get(qerr->error, "class");
> > +    ret = qobject_to_qdict(obj);
> > +    obj = qdict_get(ret, "class");
> >      if (!obj) {
> >          fprintf(stderr, "missing 'class' key in '%s'\n", fmt);
> >          abort();
> > @@ -372,8 +371,8 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
> >          fprintf(stderr, "'class' key value should be a string in '%s'\n", fmt);
> >          abort();
> >      }
> > -    
> > -    obj = qdict_get(qerr->error, "data");
> > +
> > +    obj = qdict_get(ret, "data");
> >      if (!obj) {
> >          fprintf(stderr, "missing 'data' key in '%s'\n", fmt);
> >          abort();
> > @@ -382,9 +381,11 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
> >          fprintf(stderr, "'data' key value should be a dict in '%s'\n", fmt);
> >          abort();
> >      }
> > +
> > +    return ret;
> >  }
> >  
> > -static void qerror_set_desc(QError *qerr, const char *fmt)
> > +static const QErrorStringTable *get_desc_no_fail(const char *fmt)
> 
> Likewise.
> 
> >  {
> >      int i;
> >  
> > @@ -392,8 +393,7 @@ static void qerror_set_desc(QError *qerr, const char *fmt)
> >  
> >      for (i = 0; qerror_table[i].error_fmt; i++) {
> >          if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
> > -            qerr->entry = &qerror_table[i];
> > -            return;
> > +            return &qerror_table[i];
> >          }
> >      }
> >  
> > @@ -426,8 +426,8 @@ static QError *qerror_from_info(const char *file, int linenr, const char *func,
> >      qerr->file = file;
> >      qerr->func = func;
> >  
> > -    qerror_set_data(qerr, fmt, va);
> > -    qerror_set_desc(qerr, fmt);
> > +    qerr->error = error_obj_from_fmt_no_fail(fmt, va);
> > +    qerr->entry = get_desc_no_fail(fmt);
> >  
> >      return qerr;
> >  }
> 
> Turns side effects on qerr into a nice clean return values.  Good!
> 

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

* Re: [Qemu-devel] [PATCH 13/34] hmp: hmp_change(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-02 13:27   ` Markus Armbruster
@ 2012-08-02 13:46     ` Paolo Bonzini
  2012-08-02 13:53       ` Markus Armbruster
  2012-08-02 14:51       ` Luiz Capitulino
  2012-08-02 14:42     ` Luiz Capitulino
  1 sibling, 2 replies; 85+ messages in thread
From: Paolo Bonzini @ 2012-08-02 13:46 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: kwolf, aliguori, mdroth, qemu-devel, Luiz Capitulino, eblake

Il 02/08/2012 15:27, Markus Armbruster ha scritto:
>> > +        bdev_list = qmp_query_block(NULL);
>> > +        for (bdev = bdev_list; bdev; bdev = bdev->next) {
>> > +            if (!strcmp(bdev->value->device, device) &&
>> > +                blockinfo_is_encrypted(bdev->value) &&
>> > +                !blockinfo_key_is_set(bdev->value)) {
>> > +                hmp_change_ask_user_key(mon, bdev->value);
>> > +                break;
>> > +            }
>> > +        }

Is this anything that an external application can reproduce?

Perhaps we need to keep QERR_DEVICE_ENCRYPTED even if libvirt does not
use it, or at least provide an alternative mechanism (e.g. an event) to
realize its effect.

Paolo

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

* Re: [Qemu-devel] [PATCH 13/34] hmp: hmp_change(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-02 13:46     ` Paolo Bonzini
@ 2012-08-02 13:53       ` Markus Armbruster
  2012-08-02 13:57         ` Paolo Bonzini
  2012-08-02 14:51       ` Luiz Capitulino
  1 sibling, 1 reply; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 13:53 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: kwolf, aliguori, qemu-devel, mdroth, Luiz Capitulino, eblake

Paolo Bonzini <pbonzini@redhat.com> writes:

> Il 02/08/2012 15:27, Markus Armbruster ha scritto:
>>> > +        bdev_list = qmp_query_block(NULL);
>>> > +        for (bdev = bdev_list; bdev; bdev = bdev->next) {
>>> > +            if (!strcmp(bdev->value->device, device) &&
>>> > +                blockinfo_is_encrypted(bdev->value) &&
>>> > +                !blockinfo_key_is_set(bdev->value)) {
>>> > +                hmp_change_ask_user_key(mon, bdev->value);
>>> > +                break;
>>> > +            }
>>> > +        }
>
> Is this anything that an external application can reproduce?
>
> Perhaps we need to keep QERR_DEVICE_ENCRYPTED even if libvirt does not
> use it, or at least provide an alternative mechanism (e.g. an event) to
> realize its effect.

Not sure I get you.

External applications should use QMP.

A sane way to change media in QMP needs to provide the key as argument.
If the key is wrong, fail the change cleanly.  In particular, don't
eject then.

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

* Re: [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-02 11:35   ` Markus Armbruster
@ 2012-08-02 13:54     ` Luiz Capitulino
  2012-08-10  7:56       ` Markus Armbruster
  0 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02 13:54 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

On Thu, 02 Aug 2012 13:35:54 +0200
Markus Armbruster <armbru@redhat.com> wrote:

> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> > ---
> >  block.c          | 1 +
> >  qapi-schema.json | 7 +++++--
> >  2 files changed, 6 insertions(+), 2 deletions(-)
> >
> > diff --git a/block.c b/block.c
> > index b38940b..9c113b8 100644
> > --- a/block.c
> > +++ b/block.c
> > @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
> >              info->value->inserted->ro = bs->read_only;
> >              info->value->inserted->drv = g_strdup(bs->drv->format_name);
> >              info->value->inserted->encrypted = bs->encrypted;
> > +            info->value->inserted->valid_encryption_key = bs->valid_key;
> >              if (bs->backing_file[0]) {
> >                  info->value->inserted->has_backing_file = true;
> >                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
> > diff --git a/qapi-schema.json b/qapi-schema.json
> > index bc55ed2..1b2d7f5 100644
> > --- a/qapi-schema.json
> > +++ b/qapi-schema.json
> > @@ -400,6 +400,8 @@
> >  #
> >  # @encrypted: true if the backing device is encrypted
> >  #
> > +# @valid_encryption_key: true if a valid encryption key has been set
> > +#
> >  # @bps: total throughput limit in bytes per second is specified
> >  #
> >  # @bps_rd: read throughput limit in bytes per second is specified
> > @@ -419,8 +421,9 @@
> >  { 'type': 'BlockDeviceInfo',
> >    'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
> >              '*backing_file': 'str', 'encrypted': 'bool',
> > -            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
> > -            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
> > +            'valid_encryption_key': 'bool', 'bps': 'int',
> > +            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
> > +            'iops_rd': 'int', 'iops_wr': 'int'} }
> >  
> >  ##
> >  # @BlockDeviceIoStatus:
> 
> BlockDeviceInfo is API, isn't it?

Yes.

> Note that bs->valid_key currently implies bs->encrypted.  bs->valid_key
> && !bs->encrypted is impossible.  Should we make valid_encryption_key
> only available when encrypted?

I don't think so. It's a bool, so it's ok for it to be false when
encrypted is false.

> valid_encryption_key is a bit long for my taste.  Yours may be
> different.

We should choose more descriptive and self-documenting names for the
protocol. Besides, I can't think of anything shorter that won't get
cryptic.

Suggestions are always welcome though :)

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

* Re: [Qemu-devel] [PATCH 13/34] hmp: hmp_change(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-02 13:53       ` Markus Armbruster
@ 2012-08-02 13:57         ` Paolo Bonzini
  2012-08-02 14:53           ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Paolo Bonzini @ 2012-08-02 13:57 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: kwolf, aliguori, qemu-devel, mdroth, Luiz Capitulino, eblake

Il 02/08/2012 15:53, Markus Armbruster ha scritto:
>> > Is this anything that an external application can reproduce?
>> >
>> > Perhaps we need to keep QERR_DEVICE_ENCRYPTED even if libvirt does not
>> > use it, or at least provide an alternative mechanism (e.g. an event) to
>> > realize its effect.
> Not sure I get you.
> 
> External applications should use QMP.

Yes.  Is there a conceivable scenario in which a QMP client needs to
look at QERR_DEVICE_ENCRYPTED?

> A sane way to change media in QMP needs to provide the key as argument.

How does the QMP client know that the device is encrypted, and thus they
have to ask for the key and retry?

Same for hmp_cont, by the way.

> If the key is wrong, fail the change cleanly.  In particular, don't
> eject then.

Agreed on not ejecting, but this is orthogonal.

Paolo

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

* Re: [Qemu-devel] [PATCH 12/34] hmp: hmp_cont(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-02 11:53   ` Markus Armbruster
@ 2012-08-02 14:22     ` Luiz Capitulino
  2012-08-10  8:42       ` Markus Armbruster
  0 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02 14:22 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

On Thu, 02 Aug 2012 13:53:08 +0200
Markus Armbruster <armbru@redhat.com> wrote:

> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > This commit changes hmp_cont() to loop through all block devices
> > and proactively set an encryption key for any encrypted device
> > without a valid one.
> >
> > This change is needed because QERR_DEVICE_ENCRYPTED is going to be
> > dropped by a future commit.
> >
> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> > ---
> >  hmp.c | 43 +++++++++++++++++++++++++------------------
> >  1 file changed, 25 insertions(+), 18 deletions(-)
> >
> > diff --git a/hmp.c b/hmp.c
> > index 6b72a64..1ebeb63 100644
> > --- a/hmp.c
> > +++ b/hmp.c
> > @@ -610,34 +610,41 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
> >  
> >  static void hmp_cont_cb(void *opaque, int err)
> >  {
> > -    Monitor *mon = opaque;
> > -
> >      if (!err) {
> > -        hmp_cont(mon, NULL);
> > +        qmp_cont(NULL);
> >      }
> >  }
> >  
> > -void hmp_cont(Monitor *mon, const QDict *qdict)
> > +static bool blockinfo_is_encrypted(const BlockInfo *bdev)
> >  {
> > -    Error *errp = NULL;
> > -
> > -    qmp_cont(&errp);
> > -    if (error_is_set(&errp)) {
> > -        if (error_is_type(errp, QERR_DEVICE_ENCRYPTED)) {
> > -            const char *device;
> > +    return (bdev->inserted && bdev->inserted->encrypted);
> > +}
> >  
> > -            /* The device is encrypted. Ask the user for the password
> > -               and retry */
> > +static bool blockinfo_key_is_set(const BlockInfo *bdev)
> > +{
> > +    return (bdev->inserted && bdev->inserted->valid_encryption_key);
> > +}
> >  
> > -            device = error_get_field(errp, "device");
> > -            assert(device != NULL);
> > +void hmp_cont(Monitor *mon, const QDict *qdict)
> > +{
> > +    BlockInfoList *bdev_list, *bdev;
> > +    Error *errp = NULL;
> >  
> > -            monitor_read_block_device_key(mon, device, hmp_cont_cb, mon);
> > -            error_free(errp);
> > -            return;
> > +    bdev_list = qmp_query_block(NULL);
> > +    for (bdev = bdev_list; bdev; bdev = bdev->next) {
> > +        if (blockinfo_is_encrypted(bdev->value) &&
> > +            !blockinfo_key_is_set(bdev->value)) {
> > +                monitor_read_block_device_key(mon, bdev->value->device,
> > +                                              hmp_cont_cb, NULL);
> > +                goto out;
> >          }
> > -        hmp_handle_error(mon, &errp);
> >      }
> > +
> > +    qmp_cont(&errp);
> > +    hmp_handle_error(mon, &errp);
> > +
> > +out:
> > +    qapi_free_BlockInfoList(bdev_list);
> >  }
> >  
> >  void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
> 
> Quote my previous analysis:
> 
> Diff makes this change look worse than it is.  Odd: M-x ediff gets it
> right.  Anyway, here's how I think it works:
> 
> Unchanged qmp_cont(): search the bdrv_states for the first encrypted one
> without a key.  If found, set err argument to QERR_DEVICE_ENCRYPTED.
> Other errors unrelated to encrypted devices are also possible.
> 
> hmp_cont() before: try qmp_cont().  If we get QERR_DEVICE_ENCRYPTED,
> extract the device from the error object, and prompt for its key, with a
> callback that retries hmp_cont() if the key was provided.
> 
> After: search the bdrv_states for an encrypted one without a key.  If
> there is none, qmp_cont(), no special error handling.  If there is one,
> prompt for its key, with a callback that runs qmp_cont() if the key was
> provided.
> 
> End quote.
> 
> Two observations:
> 
> 1. I don't understand how this works for multiple encrypted BDSs without
> keys.  If there are any, hmp_cont() starts reading the first one's key,
> then returns.  But the callback doesn't start reading the next one's
> key.  Please explain.

The callback calls qmp_cont(), which will fail. Then the user will enter
cont again, and the loop on BlockInfos will run again and the user will
be asked for the password of the next image.

IOW, each time cont is issued by the user it will ask for the password
of a different device.

That's the current behavior, and I believe it was also the behavior before
I converted cont to the qapi.

> 2. qmp_cont() uses bdrv_key_required() to test whether a BDS lacks a
> key.  Your new hmp_cont() uses blockinfo_is_encrypted() &&
> !blockinfo_key_is_set().  Not obvious that the two are equivalent.
> 
> I'm afraid they are not.  bdrv_key_required() checks the backing image
> first:
> 
>     int bdrv_key_required(BlockDriverState *bs)
>     {
>         BlockDriverState *backing_hd = bs->backing_hd;
> 
>         if (backing_hd && backing_hd->encrypted && !backing_hd->valid_key)
>             return 1;
>         return (bs->encrypted && !bs->valid_key);
>     }
> 
> Your code doesn't:
> 
>     static bool blockinfo_is_encrypted(const BlockInfo *bdev)
>     {
>         return (bdev->inserted && bdev->inserted->encrypted);
>     }
> 
>     static bool blockinfo_key_is_set(const BlockInfo *bdev)
>     {
>         return (bdev->inserted && bdev->inserted->valid_encryption_key);
>     }
> 
>     BlockInfoList *qmp_query_block(Error **errp)
>     {
>         BlockInfoList *head = NULL, *cur_item = NULL;
>         BlockDriverState *bs;
> 
>         QTAILQ_FOREACH(bs, &bdrv_states, list) {
>             BlockInfoList *info = g_malloc0(sizeof(*info));
> [...]
>             if (bs->drv) {
>                 info->value->has_inserted = true;
>                 info->value->inserted = g_malloc0(sizeof(*info->value->inserted));
> [...]
>                 info->value->inserted->encrypted = bs->encrypted;
>                 info->value->inserted->valid_encryption_key = bs->valid_key;
> [...]
> 
> Are you sure this is correct?

Is it actually possible for backing_hd to be false and valid_key to be true?

> I understand we require HMP code to go via QMP for everything, to keep
> HMP honest.  This case shows a drawback: duplicated code, leading to
> inconsistencies.

Keeping DeviceEncrypted would solve this.

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

* Re: [Qemu-devel] [PATCH 13/34] hmp: hmp_change(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-02 13:27   ` Markus Armbruster
  2012-08-02 13:46     ` Paolo Bonzini
@ 2012-08-02 14:42     ` Luiz Capitulino
  1 sibling, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02 14:42 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

On Thu, 02 Aug 2012 15:27:33 +0200
Markus Armbruster <armbru@redhat.com> wrote:

> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > This commit changes the way hmp_change() checks if an encryption key
> > is required for the device to be inserted.
> >
> > Instead of checking for QERR_DEVICE_ENCRYPTED, hmp_change() now checks
> > if the device was successfully inserted, is encrypted and is missing
> > an encryption key.
> >
> > This change is needed because QERR_DEVICE_ENCRYPTED is going to be
> > dropped by a future commit.
> >
> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> > ---
> >  hmp.c | 54 ++++++++++++++++++++++++++++++++++++++----------------
> >  1 file changed, 38 insertions(+), 16 deletions(-)
> >
> > diff --git a/hmp.c b/hmp.c
> > index 1ebeb63..ea21cf7 100644
> > --- a/hmp.c
> > +++ b/hmp.c
> > @@ -783,17 +783,29 @@ static void hmp_change_read_arg(Monitor *mon, const char *password,
> >  static void cb_hmp_change_bdrv_pwd(Monitor *mon, const char *password,
> >                                     void *opaque)
> >  {
> > -    Error *encryption_err = opaque;
> > +    char *device = opaque;
> >      Error *err = NULL;
> > -    const char *device;
> > -
> > -    device = error_get_field(encryption_err, "device");
> >  
> >      qmp_block_passwd(device, password, &err);
> >      hmp_handle_error(mon, &err);
> > -    error_free(encryption_err);
> >  
> >      monitor_read_command(mon, 1);
> > +    g_free(device);
> > +}
> > +
> > +static void hmp_change_ask_user_key(Monitor *mon, const BlockInfo *binfo)
> > +{
> > +    monitor_printf(mon, "%s (%s) is encrypted.\n", binfo->device,
> > +                   binfo->inserted->file);
> > +
> > +    if (!monitor_get_rs(mon)) {
> > +        monitor_printf(mon,
> > +                "terminal does not support password prompting\n");
> > +        return;
> > +    }
> > +
> > +    readline_start(monitor_get_rs(mon), "Password: ", 1,
> > +                   cb_hmp_change_bdrv_pwd, g_strdup(binfo->device));
> 
> Why can't you use monitor_read_password() here?  Or even
> monitor_read_bdrv_key_start()?

Should be possible, I just did what the current version does.

> 
> >  }
> >  
> >  void hmp_change(Monitor *mon, const QDict *qdict)
> > @@ -801,6 +813,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
> >      const char *device = qdict_get_str(qdict, "device");
> >      const char *target = qdict_get_str(qdict, "target");
> >      const char *arg = qdict_get_try_str(qdict, "arg");
> > +    BlockInfoList *bdev_list = NULL, *bdev;
> >      Error *err = NULL;
> >  
> >      if (strcmp(device, "vnc") == 0 &&
> > @@ -813,21 +826,30 @@ void hmp_change(Monitor *mon, const QDict *qdict)
> >      }
> >  
> >      qmp_change(device, target, !!arg, arg, &err);
> > -    if (error_is_type(err, QERR_DEVICE_ENCRYPTED)) {
> > -        monitor_printf(mon, "%s (%s) is encrypted.\n",
> > -                       error_get_field(err, "device"),
> > -                       error_get_field(err, "filename"));
> > -        if (!monitor_get_rs(mon)) {
> > -            monitor_printf(mon,
> > -                    "terminal does not support password prompting\n");
> > +    if (error_is_set(&err)) {
> > +        /* qmp_change() failed. If 'device' is returned by qmp_query_block(),
> > +         * is encrypted and doesn't have a valid encryption key set, then
> > +         * either the user passed an invalid key or didn't pass one at all.
> > +         * Ask the user for the key.
> > +         */
> 
> Is it even possible to pass a key?

Looks like you can't, I think I confused myself with change vnc.

> 
> > +        bdev_list = qmp_query_block(NULL);
> > +        for (bdev = bdev_list; bdev; bdev = bdev->next) {
> > +            if (!strcmp(bdev->value->device, device) &&
> > +                blockinfo_is_encrypted(bdev->value) &&
> > +                !blockinfo_key_is_set(bdev->value)) {
> > +                hmp_change_ask_user_key(mon, bdev->value);
> > +                break;
> > +            }
> > +        }
> > +
> > +        if (bdev) {
> >              error_free(err);
> > -            return;
> > +            err = NULL;
> >          }
> > -        readline_start(monitor_get_rs(mon), "Password: ", 1,
> > -                       cb_hmp_change_bdrv_pwd, err);
> > -        return;
> >      }
> > +
> >      hmp_handle_error(mon, &err);
> > +    qapi_free_BlockInfoList(bdev_list);
> >  }
> >  
> >  void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
> 
> Ourside the scope of this patch, but here goes anyway: I wonder what
> happens when you enter an incorrect key.

I remember testing this ages ago (even before QMP if my memory is not failing
me) and no error is reported.

> If bdrv_set_key() fails, it returns
> 
> 1. -EINVAL if the image isn't encrypted
> 
> 2. -ENOMEDIUM under conditions that look like they shouldn't happen
> 
>    Possibly a bug.
> 
> 3. Whatever the block driver's bdrv_set_key() methods returned
> 
>    Both existing methods qcow2_set_key() and qcow_set_key() return -1 on
>    failure, not a negative errno.  Bug.
> 
>    I believe they can fail only when passed invalid parameters, which
>    isn't the case.  In other words, they both accept *any* key.  If it's
>    wrong, reads will produce garbage, and writes will destroy the image.
> 
> qmp_block_passwd() sets QERR_DEVICE_ENCRYPTED on -EINVAL, else
> QERR_INVALID_PASSWORD.
> 
> hmp_handle_error() prints the message.
> 
> The media change takes effect regardless of bdrv_set_key() failures!  I
> believe it takes effect first thing in qmp_bdrv_open_encrypted(), before
> we even check whether a key is required, let alone prompt for it.

Not sure I follow you, as far as I understand it the problem is that
bdrv_set_key() doesn't return an error for an invalid key.

> 
> If the guest is running, I suspect it'll happily read and write with a
> zero AES_KEY.  Reads produce garbarge, and writes destroy the image.
> 
> Problem exists both in HMP (which asks for password) and QMP (which
> doesn't even try to supply one).  change with a block device argument is
> unsafe unless the guest is stopped.
> 
> Encryption is yet another half-baked feature that shouldn't have been
> committed.
> 
> And I hate the change command, too.
> 

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

* Re: [Qemu-devel] [PATCH 13/34] hmp: hmp_change(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-02 13:46     ` Paolo Bonzini
  2012-08-02 13:53       ` Markus Armbruster
@ 2012-08-02 14:51       ` Luiz Capitulino
  1 sibling, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02 14:51 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: kwolf, aliguori, qemu-devel, mdroth, Markus Armbruster, eblake

On Thu, 02 Aug 2012 15:46:48 +0200
Paolo Bonzini <pbonzini@redhat.com> wrote:

> Il 02/08/2012 15:27, Markus Armbruster ha scritto:
> >> > +        bdev_list = qmp_query_block(NULL);
> >> > +        for (bdev = bdev_list; bdev; bdev = bdev->next) {
> >> > +            if (!strcmp(bdev->value->device, device) &&
> >> > +                blockinfo_is_encrypted(bdev->value) &&
> >> > +                !blockinfo_key_is_set(bdev->value)) {
> >> > +                hmp_change_ask_user_key(mon, bdev->value);
> >> > +                break;
> >> > +            }
> >> > +        }
> 
> Is this anything that an external application can reproduce?

Yes, that should be possible.

But thinking a bit more about this, the real question is whether we want
them to do it. I guess not, as the fact that qmp_bdrv_open_encrypted()
doesn't close the bs on error is probably a bug.

> Perhaps we need to keep QERR_DEVICE_ENCRYPTED even if libvirt does not
> use it, or at least provide an alternative mechanism (e.g. an event) to
> realize its effect.

Yes, maybe that's better. hmp_cont() wouldn't change much though, as
it still needs to figure out which device needs a key.

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

* Re: [Qemu-devel] [PATCH 13/34] hmp: hmp_change(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-02 13:57         ` Paolo Bonzini
@ 2012-08-02 14:53           ` Luiz Capitulino
  0 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02 14:53 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: kwolf, aliguori, mdroth, qemu-devel, Markus Armbruster, eblake

On Thu, 02 Aug 2012 15:57:24 +0200
Paolo Bonzini <pbonzini@redhat.com> wrote:

> Il 02/08/2012 15:53, Markus Armbruster ha scritto:
> >> > Is this anything that an external application can reproduce?
> >> >
> >> > Perhaps we need to keep QERR_DEVICE_ENCRYPTED even if libvirt does not
> >> > use it, or at least provide an alternative mechanism (e.g. an event) to
> >> > realize its effect.
> > Not sure I get you.
> > 
> > External applications should use QMP.
> 
> Yes.  Is there a conceivable scenario in which a QMP client needs to
> look at QERR_DEVICE_ENCRYPTED?
> 
> > A sane way to change media in QMP needs to provide the key as argument.
> 
> How does the QMP client know that the device is encrypted, and thus they
> have to ask for the key and retry?

It would be interesting to know how libvirt handles this.

> 
> Same for hmp_cont, by the way.
> 
> > If the key is wrong, fail the change cleanly.  In particular, don't
> > eject then.
> 
> Agreed on not ejecting, but this is orthogonal.
> 
> Paolo
> 

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

* Re: [Qemu-devel] [PATCH 14/34] net: inet_connect(), inet_connect_opts(): add in_progress argument
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 14/34] net: inet_connect(), inet_connect_opts(): add in_progress argument Luiz Capitulino
@ 2012-08-02 15:12   ` Markus Armbruster
  0 siblings, 0 replies; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 15:12 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> It's used to indicate the special case where a valid file-descriptor
> is returned (ie. success) but the connection can't be completed
> w/o blocking.

Why callers need that isn't obvious from this patch.  I assume it
becomes obvious later in this series.  A hint in the commit message
would be nice.

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

* Re: [Qemu-devel] [PATCH 15/34] net: inet_connect(), inet_connect_opts(): return -errno
  2012-08-02 13:41   ` Luiz Capitulino
@ 2012-08-02 15:50     ` Markus Armbruster
  2012-08-02 16:49       ` Luiz Capitulino
  2012-08-06  6:52       ` Amos Kong
  0 siblings, 2 replies; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 15:50 UTC (permalink / raw)
  To: Luiz Capitulino
  Cc: kwolf, aliguori, Juan Quintela, mdroth, qemu-devel, pbonzini,
	Amos Kong, eblake

[cc: Juan & Amos]

Luiz Capitulino <lcapitulino@redhat.com> writes:

> On Wed,  1 Aug 2012 22:02:35 -0300
> Luiz Capitulino <lcapitulino@redhat.com> wrote:
>
>> Next commit wants to use this.
>> 
>> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
>> ---
>> 
>> This patch is an interesting case, because one of the goal of the error
>> format that's being replaced was that callers could use it to know the
>> error cause (with error_is_type().
>> 
>> However, the new error format doesn't allow this as most errors are
>> class GenericError. So, we'll have to use errno to know the error cause,
>> this is the case of inet_connect() when called by
>> tcp_start_outgoing_migration().
>
> I'm thinking in doing this differently. Instead of returning errno, we
> could have:
>
>  error_sete(Error **err, ErrorClass err_class, int err_no,
>             const char *fmt, ...);
>
> Then we store err_no in Error, and also add error_get_errno().
>
> Comments?

Maybe that'll turn out to be useful elsewhere, but not here.

The purpose of PATCH 14+15 is to permit purging error_is_type() from
tcp_start_outgoing_migration() in PATCH 16.  Let's have a look at all
three patches together.

This is tcp_start_outgoing_migration() now:

    int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
                                     Error **errp)
    {
        s->get_error = socket_errno;
        s->write = socket_write;
        s->close = tcp_close;

        s->fd = inet_connect(host_port, false, errp);

        if (!error_is_set(errp)) {
            migrate_fd_connect(s);
        } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_IN_PROGRESS)) {
            DPRINTF("connect in progress\n");
            qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
        } else if (error_is_type(*errp, QERR_SOCKET_CREATE_FAILED)) {
            DPRINTF("connect failed\n");
            return -1;
        } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_FAILED)) {
            DPRINTF("connect failed\n");
            migrate_fd_error(s);
            return -1;
        } else {
            DPRINTF("unknown error\n");
            return -1;
        }

        return 0;
    }

Cases:

1. Success

   Proceeed to migrate_fd_connect().

2. QERR_SOCKET_CONNECT_IN_PROGRESS

   connect() failed with -EINPROGRESS.  Not actually an error.  Set up
   appropriate callback.

3. QERR_SOCKET_CONNECT_FAILED

   getaddrinfo() succeeded, but could not connect() to any of the
   addresses.  Fail migration with migrate_fd_error().

4. QERR_SOCKET_CREATE_FAILED

   The error grabbag:

   * inet_parse() failed, or

   * inet_connect_opts() misses host and/or port (should never happen)

   * getaddrinfo() failed

   Bug: neglects to migrate_fd_error()!  Broken in commit d5c5dacc.

5. Anything else

   Should never happen.  Handled exactly like 4.

If I undo d5c5dacc's damage (untested), it looks like this:

    int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
                                     Error **errp)
    {
        s->get_error = socket_errno;
        s->write = socket_write;
        s->close = tcp_close;

        s->fd = inet_connect(host_port, false, errp);

        if (!error_is_set(errp)) {
            migrate_fd_connect(s);
        } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_IN_PROGRESS)) {
            DPRINTF("connect in progress\n");
            qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
        } else {
            DPRINTF("connect failed\n");
            migrate_fd_error(s);
            return -1;
        }

        return 0;
    }

Et voilà, the only error_is_type() is the non-error "in progress", and
your new in_progress covers that already, no need for an errno.

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

* Re: [Qemu-devel] [PATCH 17/34] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 17/34] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS Luiz Capitulino
@ 2012-08-02 15:58   ` Markus Armbruster
  2012-08-06  7:04     ` Amos Kong
  2012-08-02 16:54   ` Michael Roth
  1 sibling, 1 reply; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 15:58 UTC (permalink / raw)
  To: Luiz Capitulino
  Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, Amos Kong, eblake

[cc: Amos]

Luiz Capitulino <lcapitulino@redhat.com> writes:

> This error is currently returned by inet_connect_opts(), however
> it causes the follow spurious message on HMP:
>
>     (qemu) migrate tcp:0:4444
>     migrate: Connection can not be completed immediately
>     (qemu)
>
> But migration succeeds.

Broken in commit d5c5dacc.

Commit a6ba35b3 earlier in the same series might have broken other users
of inet_connect() and inet_connect_opts() similarly.  Would be nice to
know.  Whatever was brolen, your patch fixes it, too.

> inet_connect_opts() has a 'in_progress' argument that callers can
> use to check whether a connection is in progress. The QERR_ macro
> is not needed anymore.
>
> PS: I didn't test with QMP, but I guess the migrate command will
>     return an error response.

Plausible.

I'd squash this into PATCH 14, because the purpose of the combined patch
will be obvious.  Right now, 14's isn't.

>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  qemu-sockets.c | 2 --
>  qerror.c       | 4 ----
>  qerror.h       | 3 ---
>  3 files changed, 9 deletions(-)
>
> diff --git a/qemu-sockets.c b/qemu-sockets.c
> index 82f4736..7196c5f 100644
> --- a/qemu-sockets.c
> +++ b/qemu-sockets.c
> @@ -284,8 +284,6 @@ int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp)
>              if (in_progress) {
>                  *in_progress = true;
>              }
> -
> -            error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS);
>          } else if (rc < 0) {
>              if (NULL == e->ai_next)
>                  fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
> diff --git a/qerror.c b/qerror.c
> index 691d8a8..33b8780 100644
> --- a/qerror.c
> +++ b/qerror.c
> @@ -309,10 +309,6 @@ static const QErrorStringTable qerror_table[] = {
>          .desc      = "Could not start VNC server on %(target)",
>      },
>      {
> -        .error_fmt = QERR_SOCKET_CONNECT_IN_PROGRESS,
> -        .desc      = "Connection can not be completed immediately",
> -    },
> -    {
>          .error_fmt = QERR_SOCKET_CONNECT_FAILED,
>          .desc      = "Failed to connect to socket",
>      },
> diff --git a/qerror.h b/qerror.h
> index de8497d..52ce58d 100644
> --- a/qerror.h
> +++ b/qerror.h
> @@ -240,9 +240,6 @@ char *qerror_format(const char *fmt, QDict *error);
>  #define QERR_VNC_SERVER_FAILED \
>      "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
>  
> -#define QERR_SOCKET_CONNECT_IN_PROGRESS \
> -    "{ 'class': 'SockConnectInprogress', 'data': {} }"
> -
>  #define QERR_SOCKET_CONNECT_FAILED \
>      "{ 'class': 'SockConnectFailed', 'data': {} }"

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

* Re: [Qemu-devel] [PATCH 25/34] qerror: qerror_table: don't use C99 struct initializers
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 25/34] qerror: qerror_table: don't use C99 struct initializers Luiz Capitulino
@ 2012-08-02 16:48   ` Markus Armbruster
  0 siblings, 0 replies; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 16:48 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> This allows for changing QERR_ macros to initialize two struct members
> at the same time. See next commit for more details.
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  qerror.c | 276 +++++++++++++++++++++++++++++++--------------------------------
>  qerror.h |   2 +-
>  2 files changed, 139 insertions(+), 139 deletions(-)
>
> diff --git a/qerror.c b/qerror.c
> index 33b8780..664efb3 100644
> --- a/qerror.c
> +++ b/qerror.c
> @@ -44,285 +44,285 @@ static const QType qerror_type = {
>   */
>  static const QErrorStringTable qerror_table[] = {
>      {
> -        .error_fmt = QERR_ADD_CLIENT_FAILED,
> -        .desc      = "Could not add client",
> +         QERR_ADD_CLIENT_FAILED,
> +         "Could not add client",
>      },

Okay, as qerror_table[] goes away in PATCH 32 anyway.

[...]

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

* Re: [Qemu-devel] [PATCH 15/34] net: inet_connect(), inet_connect_opts(): return -errno
  2012-08-02 15:50     ` Markus Armbruster
@ 2012-08-02 16:49       ` Luiz Capitulino
  2012-08-06  6:52       ` Amos Kong
  1 sibling, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02 16:49 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: kwolf, aliguori, Juan Quintela, mdroth, qemu-devel, pbonzini,
	Amos Kong, eblake

On Thu, 02 Aug 2012 17:50:30 +0200
Markus Armbruster <armbru@redhat.com> wrote:

> [cc: Juan & Amos]
> 
> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > On Wed,  1 Aug 2012 22:02:35 -0300
> > Luiz Capitulino <lcapitulino@redhat.com> wrote:
> >
> >> Next commit wants to use this.
> >> 
> >> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> >> ---
> >> 
> >> This patch is an interesting case, because one of the goal of the error
> >> format that's being replaced was that callers could use it to know the
> >> error cause (with error_is_type().
> >> 
> >> However, the new error format doesn't allow this as most errors are
> >> class GenericError. So, we'll have to use errno to know the error cause,
> >> this is the case of inet_connect() when called by
> >> tcp_start_outgoing_migration().
> >
> > I'm thinking in doing this differently. Instead of returning errno, we
> > could have:
> >
> >  error_sete(Error **err, ErrorClass err_class, int err_no,
> >             const char *fmt, ...);
> >
> > Then we store err_no in Error, and also add error_get_errno().
> >
> > Comments?
> 
> Maybe that'll turn out to be useful elsewhere, but not here.
> 
> The purpose of PATCH 14+15 is to permit purging error_is_type() from
> tcp_start_outgoing_migration() in PATCH 16.  Let's have a look at all
> three patches together.
> 
> This is tcp_start_outgoing_migration() now:
> 
>     int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
>                                      Error **errp)
>     {
>         s->get_error = socket_errno;
>         s->write = socket_write;
>         s->close = tcp_close;
> 
>         s->fd = inet_connect(host_port, false, errp);
> 
>         if (!error_is_set(errp)) {
>             migrate_fd_connect(s);
>         } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_IN_PROGRESS)) {
>             DPRINTF("connect in progress\n");
>             qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
>         } else if (error_is_type(*errp, QERR_SOCKET_CREATE_FAILED)) {
>             DPRINTF("connect failed\n");
>             return -1;
>         } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_FAILED)) {
>             DPRINTF("connect failed\n");
>             migrate_fd_error(s);
>             return -1;
>         } else {
>             DPRINTF("unknown error\n");
>             return -1;
>         }
> 
>         return 0;
>     }
> 
> Cases:
> 
> 1. Success
> 
>    Proceeed to migrate_fd_connect().
> 
> 2. QERR_SOCKET_CONNECT_IN_PROGRESS
> 
>    connect() failed with -EINPROGRESS.  Not actually an error.  Set up
>    appropriate callback.
> 
> 3. QERR_SOCKET_CONNECT_FAILED
> 
>    getaddrinfo() succeeded, but could not connect() to any of the
>    addresses.  Fail migration with migrate_fd_error().
> 
> 4. QERR_SOCKET_CREATE_FAILED
> 
>    The error grabbag:
> 
>    * inet_parse() failed, or
> 
>    * inet_connect_opts() misses host and/or port (should never happen)
> 
>    * getaddrinfo() failed
> 
>    Bug: neglects to migrate_fd_error()!  Broken in commit d5c5dacc.
> 
> 5. Anything else
> 
>    Should never happen.  Handled exactly like 4.
> 
> If I undo d5c5dacc's damage (untested), it looks like this:
> 
>     int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
>                                      Error **errp)
>     {
>         s->get_error = socket_errno;
>         s->write = socket_write;
>         s->close = tcp_close;
> 
>         s->fd = inet_connect(host_port, false, errp);
> 
>         if (!error_is_set(errp)) {
>             migrate_fd_connect(s);
>         } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_IN_PROGRESS)) {
>             DPRINTF("connect in progress\n");
>             qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
>         } else {
>             DPRINTF("connect failed\n");
>             migrate_fd_error(s);
>             return -1;
>         }
> 
>         return 0;
>     }
> 
> Et voilà, the only error_is_type() is the non-error "in progress", and
> your new in_progress covers that already, no need for an errno.

You seem to be right. When I cooked these patches I thought that the
missing call to migrate_fd_error() was intentional, but now I see it's a bug.

I'll do what you suggest.

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

* Re: [Qemu-devel] [PATCH 17/34] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 17/34] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS Luiz Capitulino
  2012-08-02 15:58   ` Markus Armbruster
@ 2012-08-02 16:54   ` Michael Roth
  2012-08-02 17:08     ` Luiz Capitulino
  1 sibling, 1 reply; 85+ messages in thread
From: Michael Roth @ 2012-08-02 16:54 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, armbru, pbonzini, eblake

On Wed, Aug 01, 2012 at 10:02:37PM -0300, Luiz Capitulino wrote:
> This error is currently returned by inet_connect_opts(), however
> it causes the follow spurious message on HMP:
> 
>     (qemu) migrate tcp:0:4444
>     migrate: Connection can not be completed immediately
>     (qemu)
> 
> But migration succeeds.

I think the core issue is that inet_connect_opts() passes back the
QERR_SOCKET_CONNECT_IN_PROGRESS via Error (which is fine), but that
we have users that erroneous pass this error up the stack, when really,
when specifying blocking=on as one of the options, they should be
expecting and doing specific handling for this error.

So if we fix that (by simply using a local Error when doing the call and
using error_propagate() for non QSCIP errors), I think we can basically
drop patches 14-17 by fixing the callers in that manner and just giving QSCIP
it's own error class.

Relying on the errno result was something these socket errors were
specifically meant to fix, since errno is set multiple times
throughout the function and extracting an errno reliably requires
callers to examine all the possible error paths and errno setters. So I
think it's a regression to go back to the old behavior, and these were
issues found in inet_connect() when we attempted to generalize it's
usage for non-blocking connections.

> 
> inet_connect_opts() has a 'in_progress' argument that callers can
> use to check whether a connection is in progress. The QERR_ macro
> is not needed anymore.
> 
> PS: I didn't test with QMP, but I guess the migrate command will
>     return an error response.
> 
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  qemu-sockets.c | 2 --
>  qerror.c       | 4 ----
>  qerror.h       | 3 ---
>  3 files changed, 9 deletions(-)
> 
> diff --git a/qemu-sockets.c b/qemu-sockets.c
> index 82f4736..7196c5f 100644
> --- a/qemu-sockets.c
> +++ b/qemu-sockets.c
> @@ -284,8 +284,6 @@ int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp)
>              if (in_progress) {
>                  *in_progress = true;
>              }
> -
> -            error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS);
>          } else if (rc < 0) {
>              if (NULL == e->ai_next)
>                  fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
> diff --git a/qerror.c b/qerror.c
> index 691d8a8..33b8780 100644
> --- a/qerror.c
> +++ b/qerror.c
> @@ -309,10 +309,6 @@ static const QErrorStringTable qerror_table[] = {
>          .desc      = "Could not start VNC server on %(target)",
>      },
>      {
> -        .error_fmt = QERR_SOCKET_CONNECT_IN_PROGRESS,
> -        .desc      = "Connection can not be completed immediately",
> -    },
> -    {
>          .error_fmt = QERR_SOCKET_CONNECT_FAILED,
>          .desc      = "Failed to connect to socket",
>      },
> diff --git a/qerror.h b/qerror.h
> index de8497d..52ce58d 100644
> --- a/qerror.h
> +++ b/qerror.h
> @@ -240,9 +240,6 @@ char *qerror_format(const char *fmt, QDict *error);
>  #define QERR_VNC_SERVER_FAILED \
>      "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
> 
> -#define QERR_SOCKET_CONNECT_IN_PROGRESS \
> -    "{ 'class': 'SockConnectInprogress', 'data': {} }"
> -
>  #define QERR_SOCKET_CONNECT_FAILED \
>      "{ 'class': 'SockConnectFailed', 'data': {} }"
> 
> -- 
> 1.7.11.2.249.g31c7954.dirty
> 

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

* Re: [Qemu-devel] [PATCH 26/34] error, qerror: add ErrorClass argument to error functions
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 26/34] error, qerror: add ErrorClass argument to error functions Luiz Capitulino
@ 2012-08-02 16:57   ` Markus Armbruster
  0 siblings, 0 replies; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 16:57 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> The new argument is added to functions qerror_report() and error_set().
> It's stored in Error and QError. qerror_report_err() is also updated to
> take care of it.
>
> The QERR_ macros are changed to contain a place holder value for the
> new argument, so that the value is used on all current calls to
> qerror_report() and error_set() (and also to initialize qerror_table[]).
>
> Next commit will update the QERR_ macros with a proper ErrorClass
> value.
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  error.c  |   6 ++-
>  error.h  |   3 +-
>  qerror.c |  10 +++--
>  qerror.h | 145 ++++++++++++++++++++++++++++++++-------------------------------
>  4 files changed, 88 insertions(+), 76 deletions(-)
>
> diff --git a/error.c b/error.c
> index 216cb08..6c8f7b8 100644
> --- a/error.c
> +++ b/error.c
> @@ -14,6 +14,7 @@
>  #include "error.h"
>  #include "qjson.h"
>  #include "qdict.h"
> +#include "qapi-types.h"
>  #include "error_int.h"
>  #include "qerror.h"
>  
> @@ -21,9 +22,10 @@ struct Error
>  {
>      QDict *obj;
>      char *msg;
> +    ErrorClass err_class;
>  };
>  
> -void error_set(Error **errp, const char *fmt, ...)
> +void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...)
>  {
>      Error *err;
>      va_list ap;
> @@ -39,6 +41,7 @@ void error_set(Error **errp, const char *fmt, ...)
>      err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap));
>      va_end(ap);
>      err->msg = qerror_format(fmt, err->obj);
> +    err->err_class = err_class;
>  
>      *errp = err;
>  }
> @@ -49,6 +52,7 @@ Error *error_copy(const Error *err)
>  
>      err_new = g_malloc0(sizeof(*err));
>      err_new->msg = g_strdup(err->msg);
> +    err_new->err_class = err->err_class;
>      err_new->obj = err->obj;
>      QINCREF(err_new->obj);
>  
> diff --git a/error.h b/error.h
> index 3d038a5..905613a 100644
> --- a/error.h
> +++ b/error.h
> @@ -13,6 +13,7 @@
>  #define ERROR_H
>  
>  #include "compiler.h"
> +#include "qapi-types.h"
>  #include <stdbool.h>
>  
>  /**
> @@ -26,7 +27,7 @@ typedef struct Error Error;
>   * Currently, qerror.h defines these error formats.  This function is not
>   * meant to be used outside of QEMU.
>   */
> -void error_set(Error **err, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
> +void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(3, 4);
>  
>  /**
>   * Returns true if an indirect pointer to an error is pointing to a valid
> diff --git a/qerror.c b/qerror.c
> index 664efb3..19a1902 100644
> --- a/qerror.c
> +++ b/qerror.c
> @@ -386,13 +386,15 @@ static QDict *error_obj_from_fmt_no_fail(const char *fmt, va_list *va)
>   *
>   * Return strong reference.
>   */
> -static QError *qerror_from_info(const char *fmt, va_list *va)
> +static QError *qerror_from_info(ErrorClass err_class, const char *fmt,
> +                                va_list *va)
>  {
>      QError *qerr;
>  
>      qerr = qerror_new();
>      loc_save(&qerr->loc);
>  
> +    qerr->err_class = err_class;
>      qerr->error = error_obj_from_fmt_no_fail(fmt, va);
>      qerr->err_msg = qerror_format(fmt, qerr->error);
>  
> @@ -518,13 +520,13 @@ static void qerror_print(QError *qerror)
>      QDECREF(qstring);
>  }
>  
> -void qerror_report(const char *fmt, ...)
> +void qerror_report(ErrorClass eclass, const char *fmt, ...)
>  {
>      va_list va;
>      QError *qerror;
>  
>      va_start(va, fmt);
> -    qerror = qerror_from_info(fmt, &va);
> +    qerror = qerror_from_info(eclass, fmt, &va);
>      va_end(va);
>  
>      if (monitor_cur_is_qmp()) {
> @@ -540,6 +542,7 @@ struct Error
   /* Evil... */
   struct Error
>  {
>      QDict *obj;
>      char *msg;
> +    ErrorClass err_class;
>  };

Evil indeed.

>  
>  void qerror_report_err(Error *err)
> @@ -551,6 +554,7 @@ void qerror_report_err(Error *err)
>      QINCREF(err->obj);
>      qerr->error = err->obj;
>      qerr->err_msg = g_strdup(err->msg);
> +    qerr->err_class = err->err_class;
>  
>      if (monitor_cur_is_qmp()) {
>          monitor_set_error(cur_mon, qerr);
> diff --git a/qerror.h b/qerror.h
> index 2e6a49d..bcc93f8 100644
> --- a/qerror.h
> +++ b/qerror.h
> @@ -16,9 +16,11 @@
>  #include "qstring.h"
>  #include "qemu-error.h"
>  #include "error.h"
> +#include "qapi-types.h"
>  #include <stdarg.h>
>  
>  typedef struct QErrorStringTable {
> +    ErrorClass err_class;
>      const char *error_fmt;
>      const char *desc;
>  } QErrorStringTable;
> @@ -28,10 +30,11 @@ typedef struct QError {
>      QDict *error;
>      Location loc;
>      char *err_msg;
> +    ErrorClass err_class;
>  } QError;
>  
>  QString *qerror_human(const QError *qerror);
> -void qerror_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
> +void qerror_report(ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
>  void qerror_report_err(Error *err);
>  void assert_no_error(Error *err);
>  char *qerror_format(const char *fmt, QDict *error);
> @@ -42,214 +45,214 @@ char *qerror_format(const char *fmt, QDict *error);
>   * Use scripts/check-qerror.sh to check.
>   */
>  #define QERR_ADD_CLIENT_FAILED \
> -    "{ 'class': 'AddClientFailed', 'data': {} }"
> +    -1, "{ 'class': 'AddClientFailed', 'data': {} }"

The QERR_ macros now expand into two arguments, which isn't nice.  But
it avoids a lot of churn.

I hope further clean up of the error reporting can get rid of the
macros.

[...]

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

* Re: [Qemu-devel] [PATCH 27/34] qerror: add proper ErrorClass value for QERR_ macros
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 27/34] qerror: add proper ErrorClass value for QERR_ macros Luiz Capitulino
@ 2012-08-02 17:01   ` Markus Armbruster
  0 siblings, 0 replies; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 17:01 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> This commit replaces the place holder value for the ErrorClass
> argument with a proper ErrorClass value for all QERR_ macros.
>
> All current errors are mapped to GenericError, except for errors
> CommandNotFound, DeviceNotActive, DeviceNotFound, KVMMissingCap and
> MigrationExpected, which are maintained as they are today.
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  qerror.h | 140 +++++++++++++++++++++++++++++++--------------------------------
>  1 file changed, 70 insertions(+), 70 deletions(-)
>
> diff --git a/qerror.h b/qerror.h
> index bcc93f8..94346cb 100644
> --- a/qerror.h
> +++ b/qerror.h
> @@ -45,214 +45,214 @@ char *qerror_format(const char *fmt, QDict *error);
>   * Use scripts/check-qerror.sh to check.
>   */
>  #define QERR_ADD_CLIENT_FAILED \
> -    -1, "{ 'class': 'AddClientFailed', 'data': {} }"
> +    ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'AddClientFailed', 'data': {} }"

Now we have two different things called "class" here.  Ugly.  But only
until PATCH 31 gets rid of the old one.  Okay.

[...]

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

* Re: [Qemu-devel] [PATCH 17/34] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS
  2012-08-02 16:54   ` Michael Roth
@ 2012-08-02 17:08     ` Luiz Capitulino
  2012-08-03 18:26       ` Michael Roth
  0 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02 17:08 UTC (permalink / raw)
  To: Michael Roth; +Cc: kwolf, aliguori, qemu-devel, armbru, pbonzini, eblake

On Thu, 2 Aug 2012 11:54:11 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> On Wed, Aug 01, 2012 at 10:02:37PM -0300, Luiz Capitulino wrote:
> > This error is currently returned by inet_connect_opts(), however
> > it causes the follow spurious message on HMP:
> > 
> >     (qemu) migrate tcp:0:4444
> >     migrate: Connection can not be completed immediately
> >     (qemu)
> > 
> > But migration succeeds.
> 
> I think the core issue is that inet_connect_opts() passes back the
> QERR_SOCKET_CONNECT_IN_PROGRESS via Error (which is fine), but that
> we have users that erroneous pass this error up the stack, when really,
> when specifying blocking=on as one of the options, they should be
> expecting and doing specific handling for this error.

You're right here.

> So if we fix that (by simply using a local Error when doing the call and
> using error_propagate() for non QSCIP errors), I think we can basically
> drop patches 14-17 by fixing the callers in that manner and just giving QSCIP
> it's own error class.

I don't think QSCIP errors is something we should report to QMP clients, at
least not for the use-case this patch is about, hence we should not have
a specific error class for this.

As pointed out by Markus in his review, keeping the in_progress flag introduced
by patch 14/34 should be enough to drop patches 15 and 16.

> Relying on the errno result was something these socket errors were
> specifically meant to fix, since errno is set multiple times
> throughout the function and extracting an errno reliably requires
> callers to examine all the possible error paths and errno setters. So I
> think it's a regression to go back to the old behavior, and these were
> issues found in inet_connect() when we attempted to generalize it's
> usage for non-blocking connections.

I'm not completely sure I agree because the new error format doesn't allow
callers to programatically know the cause of an failure. That's what errno
is for, though.

But I'll drop the patch that changes inet_connect() to return errno,
so it's not worth it to discuss this specific case.

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

* Re: [Qemu-devel] [PATCH 29/34] qmp: switch to the new error format on the wire
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 29/34] qmp: switch to the new error format on the wire Luiz Capitulino
@ 2012-08-02 17:12   ` Markus Armbruster
  2012-08-02 17:19     ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 17:12 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> IMPORTANT: this BREAKS QMP's compatibility for the error response.
>
> This commit changes QMP's wire protocol to make use of the simpler
> error format introduced by previous commits.
>
> There are two important (and mostly incompatible) changes:
>
>  1. Almost all error classes have been replaced by GenericError. The
>     only classes that are still supported for compatibility with
>     libvirt are: CommandNotFound, DeviceNotActive, KVMMissingCap,
>     DeviceNotFound and MigrationExpected
>
>  2. The 'data' field of the error dictionary is gone

Making use of license from qmp-commands.hx:

    3. Errors, in special, are not documented. Applications should NOT check
       for specific errors classes or data (it's strongly recommended to only
       check for the "error" key)

> As an example, an error response like:
>
>   { "error": { "class": "DeviceNotRemovable",
>                "data": { "device": "virtio0" },
>                "desc": "Device 'virtio0' is not removable" } }
>
> Will now be emitted as:
>
>   { "error": { "class": "GenericError",
>                "desc": "Device 'virtio0' is not removable" } }
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  QMP/qmp-spec.txt | 10 +++-------
>  monitor.c        | 18 +++++++++++++-----
>  qmp-commands.hx  |  3 +--
>  3 files changed, 17 insertions(+), 14 deletions(-)

Doesn't qapi-schema.json need updating, too?  It mentions specific error
classes that go away in this patch, such as IOError.

>
> diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt
> index 1ba916c..a277896 100644
> --- a/QMP/qmp-spec.txt
> +++ b/QMP/qmp-spec.txt
> @@ -106,14 +106,11 @@ completed because of an error condition.
>  
>  The format is:
>  
> -{ "error": { "class": json-string, "data": json-object, "desc": json-string },
> -  "id": json-value }
> +{ "error": { "class": json-string, "desc": json-string }, "id": json-value }
>  
>   Where,
>  
> -- The "class" member contains the error class name (eg. "ServiceUnavailable")
> -- The "data" member contains specific error data and is defined in a
> -  per-command basis, it will be an empty json-object if the error has no data
> +- The "class" member contains the error class name (eg. "GenericError")
>  - The "desc" member is a human-readable error message. Clients should
>    not attempt to parse this message.
>  - The "id" member contains the transaction identification associated with
> @@ -173,8 +170,7 @@ S: {"return": {"enabled": true, "present": true}, "id": "example"}
>  ------------------
>  
>  C: { "execute": }
> -S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data":
> -{}}}
> +S: {"error": {"class": "GenericError", "desc": "Invalid JSON syntax" } }
>  
>  3.5 Powerdown event
>  -------------------
> diff --git a/monitor.c b/monitor.c
> index aa57167..3694590 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -353,16 +353,26 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data)
>      QDECREF(json);
>  }
>  
> +static QDict *build_qmp_error_dict(const QError *err)
> +{
> +    QObject *obj;
> +
> +    obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %p } }",
> +                             ErrorClass_lookup[err->err_class],
> +                             qerror_human(err));
> +
> +    return qobject_to_qdict(obj);
> +}
> +
>  static void monitor_protocol_emitter(Monitor *mon, QObject *data)
>  {
>      QDict *qmp;
>  
>      trace_monitor_protocol_emitter(mon);
>  
> -    qmp = qdict_new();
> -
>      if (!monitor_has_error(mon)) {
>          /* success response */
> +        qmp = qdict_new();
>          if (data) {
>              qobject_incref(data);
>              qdict_put_obj(qmp, "return", data);
> @@ -372,9 +382,7 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data)
>          }
>      } else {
>          /* error response */
> -        qdict_put(mon->error->error, "desc", qerror_human(mon->error));
> -        qdict_put(qmp, "error", mon->error->error);
> -        QINCREF(mon->error->error);
> +        qmp = build_qmp_error_dict(mon->error);
>          QDECREF(mon->error);
>          mon->error = NULL;
>      }
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index e3cf3c5..e520b51 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -435,8 +435,7 @@ Example:
>  -> { "execute": "inject-nmi" }
>  <- { "return": {} }
>  
> -Note: inject-nmi is only supported for x86 guest currently, it will
> -      returns "Unsupported" error for non-x86 guest.
> +Note: inject-nmi is only supported for x86 guests.
>  
>  EQMP

Suggest:

    Note: inject-nmi fails when the guest doesn't support injecting.
    Currently, only x86 guests do.

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

* Re: [Qemu-devel] [PATCH 31/34] error, qerror: pass desc string to error calls
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 31/34] error, qerror: pass desc string to error calls Luiz Capitulino
@ 2012-08-02 17:19   ` Markus Armbruster
  0 siblings, 0 replies; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 17:19 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> This commit changes all QERR_ macros to contain a human message (ie.
> the desc string found in qerr_table[]) instead of a json dictionary
> in string format.
>
> Before this commit, error_set() and qerror_report() would receive
> a json dictionary in string format and build a qobject from it. Now,
> both function receive a human message instead and the qobject is
> not built anymore.
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  error.c  |   5 ++-
>  qerror.c |  44 ++------------------
>  qerror.h | 141 +++++++++++++++++++++++++++++++--------------------------------
>  3 files changed, 76 insertions(+), 114 deletions(-)
>
> diff --git a/error.c b/error.c
> index 15a2d06..740824c 100644
> --- a/error.c
> +++ b/error.c
> @@ -29,6 +29,7 @@ void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...)
>  {
>      Error *err;
>      va_list ap;
> +    char msg[2048];
>  
>      if (errp == NULL) {
>          return;
> @@ -38,9 +39,9 @@ void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...)
>      err = g_malloc0(sizeof(*err));
>  
>      va_start(ap, fmt);
> -    err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap));
> +    vsnprintf(msg, sizeof(msg), fmt, ap);
>      va_end(ap);
> -    err->msg = qerror_format(fmt, err->obj);
> +    err->msg = g_strdup(msg);

Suggest

       err->msg = g_strdup_vprintf(fmt, ap);

>      err->err_class = err_class;
>  
>      *errp = err;
> diff --git a/qerror.c b/qerror.c
> index 19a1902..db6bb47 100644
> --- a/qerror.c
> +++ b/qerror.c
> @@ -342,45 +342,6 @@ static QError *qerror_new(void)
>      return qerr;
>  }
>  
> -static QDict *error_obj_from_fmt_no_fail(const char *fmt, va_list *va)
> -{
> -    QObject *obj;
> -    QDict *ret;
> -
> -    obj = qobject_from_jsonv(fmt, va);
> -    if (!obj) {
> -        fprintf(stderr, "invalid json in error dict '%s'\n", fmt);
> -        abort();
> -    }
> -    if (qobject_type(obj) != QTYPE_QDICT) {
> -        fprintf(stderr, "error is not a dict '%s'\n", fmt);
> -        abort();
> -    }
> -
> -    ret = qobject_to_qdict(obj);
> -    obj = qdict_get(ret, "class");
> -    if (!obj) {
> -        fprintf(stderr, "missing 'class' key in '%s'\n", fmt);
> -        abort();
> -    }
> -    if (qobject_type(obj) != QTYPE_QSTRING) {
> -        fprintf(stderr, "'class' key value should be a string in '%s'\n", fmt);
> -        abort();
> -    }
> -
> -    obj = qdict_get(ret, "data");
> -    if (!obj) {
> -        fprintf(stderr, "missing 'data' key in '%s'\n", fmt);
> -        abort();
> -    }
> -    if (qobject_type(obj) != QTYPE_QDICT) {
> -        fprintf(stderr, "'data' key value should be a dict in '%s'\n", fmt);
> -        abort();
> -    }
> -
> -    return ret;
> -}
> -
>  /**
>   * qerror_from_info(): Create a new QError from error information
>   *
> @@ -390,13 +351,14 @@ static QError *qerror_from_info(ErrorClass err_class, const char *fmt,
>                                  va_list *va)
>  {
>      QError *qerr;
> +    char msg[2048];
>  
>      qerr = qerror_new();
>      loc_save(&qerr->loc);
>  
>      qerr->err_class = err_class;
> -    qerr->error = error_obj_from_fmt_no_fail(fmt, va);
> -    qerr->err_msg = qerror_format(fmt, qerr->error);
> +    vsnprintf(msg, sizeof(msg), fmt, *va);
> +    qerr->err_msg = g_strdup(msg);

Suggest

       qerr->err_msg = g_strdup_vprintf(fmt, *va);

>  
>      return qerr;
>  }
[...]

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

* Re: [Qemu-devel] [PATCH 29/34] qmp: switch to the new error format on the wire
  2012-08-02 17:12   ` Markus Armbruster
@ 2012-08-02 17:19     ` Luiz Capitulino
  0 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-02 17:19 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

On Thu, 02 Aug 2012 19:12:03 +0200
Markus Armbruster <armbru@redhat.com> wrote:

> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > IMPORTANT: this BREAKS QMP's compatibility for the error response.
> >
> > This commit changes QMP's wire protocol to make use of the simpler
> > error format introduced by previous commits.
> >
> > There are two important (and mostly incompatible) changes:
> >
> >  1. Almost all error classes have been replaced by GenericError. The
> >     only classes that are still supported for compatibility with
> >     libvirt are: CommandNotFound, DeviceNotActive, KVMMissingCap,
> >     DeviceNotFound and MigrationExpected
> >
> >  2. The 'data' field of the error dictionary is gone
> 
> Making use of license from qmp-commands.hx:
> 
>     3. Errors, in special, are not documented. Applications should NOT check
>        for specific errors classes or data (it's strongly recommended to only
>        check for the "error" key)
> 
> > As an example, an error response like:
> >
> >   { "error": { "class": "DeviceNotRemovable",
> >                "data": { "device": "virtio0" },
> >                "desc": "Device 'virtio0' is not removable" } }
> >
> > Will now be emitted as:
> >
> >   { "error": { "class": "GenericError",
> >                "desc": "Device 'virtio0' is not removable" } }
> >
> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> > ---
> >  QMP/qmp-spec.txt | 10 +++-------
> >  monitor.c        | 18 +++++++++++++-----
> >  qmp-commands.hx  |  3 +--
> >  3 files changed, 17 insertions(+), 14 deletions(-)
> 
> Doesn't qapi-schema.json need updating, too?  It mentions specific error
> classes that go away in this patch, such as IOError.

Oh, true. I remembered about that when I started working on v1 but then
forgot about doing it. It would be also nice to add some examples to
docs/writing-qmp-commands.txt.

> 
> >
> > diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt
> > index 1ba916c..a277896 100644
> > --- a/QMP/qmp-spec.txt
> > +++ b/QMP/qmp-spec.txt
> > @@ -106,14 +106,11 @@ completed because of an error condition.
> >  
> >  The format is:
> >  
> > -{ "error": { "class": json-string, "data": json-object, "desc": json-string },
> > -  "id": json-value }
> > +{ "error": { "class": json-string, "desc": json-string }, "id": json-value }
> >  
> >   Where,
> >  
> > -- The "class" member contains the error class name (eg. "ServiceUnavailable")
> > -- The "data" member contains specific error data and is defined in a
> > -  per-command basis, it will be an empty json-object if the error has no data
> > +- The "class" member contains the error class name (eg. "GenericError")
> >  - The "desc" member is a human-readable error message. Clients should
> >    not attempt to parse this message.
> >  - The "id" member contains the transaction identification associated with
> > @@ -173,8 +170,7 @@ S: {"return": {"enabled": true, "present": true}, "id": "example"}
> >  ------------------
> >  
> >  C: { "execute": }
> > -S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data":
> > -{}}}
> > +S: {"error": {"class": "GenericError", "desc": "Invalid JSON syntax" } }
> >  
> >  3.5 Powerdown event
> >  -------------------
> > diff --git a/monitor.c b/monitor.c
> > index aa57167..3694590 100644
> > --- a/monitor.c
> > +++ b/monitor.c
> > @@ -353,16 +353,26 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data)
> >      QDECREF(json);
> >  }
> >  
> > +static QDict *build_qmp_error_dict(const QError *err)
> > +{
> > +    QObject *obj;
> > +
> > +    obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %p } }",
> > +                             ErrorClass_lookup[err->err_class],
> > +                             qerror_human(err));
> > +
> > +    return qobject_to_qdict(obj);
> > +}
> > +
> >  static void monitor_protocol_emitter(Monitor *mon, QObject *data)
> >  {
> >      QDict *qmp;
> >  
> >      trace_monitor_protocol_emitter(mon);
> >  
> > -    qmp = qdict_new();
> > -
> >      if (!monitor_has_error(mon)) {
> >          /* success response */
> > +        qmp = qdict_new();
> >          if (data) {
> >              qobject_incref(data);
> >              qdict_put_obj(qmp, "return", data);
> > @@ -372,9 +382,7 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data)
> >          }
> >      } else {
> >          /* error response */
> > -        qdict_put(mon->error->error, "desc", qerror_human(mon->error));
> > -        qdict_put(qmp, "error", mon->error->error);
> > -        QINCREF(mon->error->error);
> > +        qmp = build_qmp_error_dict(mon->error);
> >          QDECREF(mon->error);
> >          mon->error = NULL;
> >      }
> > diff --git a/qmp-commands.hx b/qmp-commands.hx
> > index e3cf3c5..e520b51 100644
> > --- a/qmp-commands.hx
> > +++ b/qmp-commands.hx
> > @@ -435,8 +435,7 @@ Example:
> >  -> { "execute": "inject-nmi" }
> >  <- { "return": {} }
> >  
> > -Note: inject-nmi is only supported for x86 guest currently, it will
> > -      returns "Unsupported" error for non-x86 guest.
> > +Note: inject-nmi is only supported for x86 guests.
> >  
> >  EQMP
> 
> Suggest:
> 
>     Note: inject-nmi fails when the guest doesn't support injecting.
>     Currently, only x86 guests do.
> 

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

* Re: [Qemu-devel] [PATCH 33/34] error: drop error_get_qobject()/error_set_qobject()
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 33/34] error: drop error_get_qobject()/error_set_qobject() Luiz Capitulino
@ 2012-08-02 17:20   ` Markus Armbruster
  0 siblings, 0 replies; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 17:20 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> They are not used anymore. Also drops error_int.h.

Squash into PATCH 32?

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

* Re: [Qemu-devel] [PATCH v1 00/34]: add new error format
  2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
                   ` (34 preceding siblings ...)
  2012-08-02 13:41 ` [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
@ 2012-08-02 17:22 ` Markus Armbruster
  35 siblings, 0 replies; 85+ messages in thread
From: Markus Armbruster @ 2012-08-02 17:22 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> Quick summary first, long introduction afterwards.
>
>>From the rfc:
>
>  o rebased on top of master
>  o dropped patch "qapi: qapi.py: allow the "'" character be escaped"
>  o split patch "qerror: drop qerror_abort()" into two patches
>  o fixed tcp_start_outgoing_migration() not to use QERR_ macros
>  o fixed qemu-ga to use the new error format
>  o dropped more unused stuff
>  o improved several changelogs
>
> Btw, please take a special look in patches 14/34, 15/34 and 16/34.
>
>
> This series implements the 'Plan for error handling in QMP' as described
> by Anthony in this email:
>
>     http://lists.gnu.org/archive/html/qemu-devel/2012-07/msg03764.html
>
> Basically, this replaces almost all error classes by GenericError (the
> exception are a few error classes used by libvirt) and drops the error
> data memeber. This also adds a free form string to error_set().
>
> On the wire, we go from:
>
>     { "error": { "class": "DeviceNotRemovable",
>                  "data": { "device": "virtio0" },
>                  "desc": "Device 'virtio0' is not removable" } }
>
> to:
>
>      { "error": { "class": "GenericError",
>                   "desc": "Device 'virtio0' is not removable" } }
>
> Internally, we go from:
>
>   void error_set(Error **err, const char *fmt, ...);
>
> to:
>
>   void error_set(Error **err, ErrorClass err_class, const char *fmt, ...);

Good stuff overall.  Last but not least:

[...]
>  25 files changed, 284 insertions(+), 880 deletions(-)

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

* Re: [Qemu-devel] [PATCH 30/34] qemu-ga: switch to the new error format on the wire
  2012-08-02  1:02 ` [Qemu-devel] [PATCH 30/34] qemu-ga: " Luiz Capitulino
@ 2012-08-03 17:44   ` Michael Roth
  2012-08-03 17:56     ` Eric Blake
  0 siblings, 1 reply; 85+ messages in thread
From: Michael Roth @ 2012-08-03 17:44 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, armbru, pbonzini, eblake

On Wed, Aug 01, 2012 at 10:02:50PM -0300, Luiz Capitulino wrote:
> IMPORTANT: this BREAKS qemu-ga compatibility for the error response.
> 
> Instead of returning something like:
> 
> { "error": { "class": "InvalidParameterValue",
>              "data": {"name": "mode", "expected": "halt|powerdown|reboot" } } }
> 
> qemu-ga now returns:
> 
>  { "error": { "class": "GenericError",
>               "desc": "Parameter 'mode' expects halt|powerdown|reboot" } }

Specific error responses weren't part of the documented API, so I think
anything reliant on those is making invalid assumptions; there
should always be a catch-all for unknown/unexpected error
messages/error payloads.

> 
> Notice that this is also a bug fix, as qemu-ga wasn't returning the
> human message.
> 
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>

So, if the libvirt folks are okay with it:

Acked-by: Michael Roth <mdroth@linux.vnet.ibm.com>

> ---
>  Makefile.objs       |  2 +-
>  qapi/qmp-core.h     |  1 +
>  qapi/qmp-dispatch.c | 10 +++++++++-
>  qemu-ga.c           |  4 ++--
>  4 files changed, 13 insertions(+), 4 deletions(-)
> 
> diff --git a/Makefile.objs b/Makefile.objs
> index 5ebbcfa..cbfbba5 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -220,7 +220,7 @@ universal-obj-y += $(qapi-obj-y)
>  ######################################################################
>  # guest agent
> 
> -qga-obj-y = qga/ qemu-ga.o module.o
> +qga-obj-y = qga/ qemu-ga.o module.o qapi-types.o qapi-visit.o
>  qga-obj-$(CONFIG_WIN32) += oslib-win32.o
>  qga-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-sockets.o qemu-option.o
> 
> diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
> index b0f64ba..00446cf 100644
> --- a/qapi/qmp-core.h
> +++ b/qapi/qmp-core.h
> @@ -49,6 +49,7 @@ void qmp_disable_command(const char *name);
>  void qmp_enable_command(const char *name);
>  bool qmp_command_is_enabled(const char *name);
>  char **qmp_get_command_list(void);
> +QObject *qmp_build_error_object(Error *errp);
> 
>  #endif
> 
> diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
> index 122c1a2..ec613f8 100644
> --- a/qapi/qmp-dispatch.c
> +++ b/qapi/qmp-dispatch.c
> @@ -14,6 +14,7 @@
>  #include "qemu-objects.h"
>  #include "qapi/qmp-core.h"
>  #include "json-parser.h"
> +#include "qapi-types.h"
>  #include "error.h"
>  #include "error_int.h"
>  #include "qerror.h"
> @@ -109,6 +110,13 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp)
>      return ret;
>  }
> 
> +QObject *qmp_build_error_object(Error *errp)
> +{
> +    return qobject_from_jsonf("{ 'class': %s, 'desc': %s }",
> +                              ErrorClass_lookup[error_get_class(errp)],
> +                              error_get_pretty(errp));
> +}
> +
>  QObject *qmp_dispatch(QObject *request)
>  {
>      Error *err = NULL;
> @@ -119,7 +127,7 @@ QObject *qmp_dispatch(QObject *request)
> 
>      rsp = qdict_new();
>      if (err) {
> -        qdict_put_obj(rsp, "error", error_get_qobject(err));
> +        qdict_put_obj(rsp, "error", qmp_build_error_object(err));
>          error_free(err);
>      } else if (ret) {
>          qdict_put_obj(rsp, "return", ret);
> diff --git a/qemu-ga.c b/qemu-ga.c
> index 8199da7..f45bc61 100644
> --- a/qemu-ga.c
> +++ b/qemu-ga.c
> @@ -515,7 +515,7 @@ static void process_event(JSONMessageParser *parser, QList *tokens)
>          } else {
>              g_warning("failed to parse event: %s", error_get_pretty(err));
>          }
> -        qdict_put_obj(qdict, "error", error_get_qobject(err));
> +        qdict_put_obj(qdict, "error", qmp_build_error_object(err));
>          error_free(err);
>      } else {
>          qdict = qobject_to_qdict(obj);
> @@ -532,7 +532,7 @@ static void process_event(JSONMessageParser *parser, QList *tokens)
>              qdict = qdict_new();
>              g_warning("unrecognized payload format");
>              error_set(&err, QERR_UNSUPPORTED);
> -            qdict_put_obj(qdict, "error", error_get_qobject(err));
> +            qdict_put_obj(qdict, "error", qmp_build_error_object(err));
>              error_free(err);
>          }
>          ret = send_response(s, QOBJECT(qdict));
> -- 
> 1.7.11.2.249.g31c7954.dirty
> 

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

* Re: [Qemu-devel] [PATCH 30/34] qemu-ga: switch to the new error format on the wire
  2012-08-03 17:44   ` Michael Roth
@ 2012-08-03 17:56     ` Eric Blake
  2012-08-03 18:02       ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Eric Blake @ 2012-08-03 17:56 UTC (permalink / raw)
  To: Michael Roth
  Cc: kwolf, aliguori, armbru, qemu-devel, pbonzini, Luiz Capitulino

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

On 08/03/2012 11:44 AM, Michael Roth wrote:
> On Wed, Aug 01, 2012 at 10:02:50PM -0300, Luiz Capitulino wrote:
>> IMPORTANT: this BREAKS qemu-ga compatibility for the error response.
>>
>> Instead of returning something like:
>>
>> { "error": { "class": "InvalidParameterValue",
>>              "data": {"name": "mode", "expected": "halt|powerdown|reboot" } } }
>>
>> qemu-ga now returns:
>>
>>  { "error": { "class": "GenericError",
>>               "desc": "Parameter 'mode' expects halt|powerdown|reboot" } }
> 

>>
>> Notice that this is also a bug fix, as qemu-ga wasn't returning the
>> human message.
>>
>> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> 
> So, if the libvirt folks are okay with it:

The only use libvirt made of existing qemu-ga errors was to stringify
them in order to pass on an error message to the user when a command
failed.  Existing libvirt attempts to look up the 'desc' field, and when
it is lacking, then attempts to stringify the 'class' field based on a
finite list of known classes.  Qemu is now shrinking the list of known
classes but providing a 'desc' field, so the error message quality in
libvirt will actually improve.  After reading libvirt's
src/qemu/qemu_agent.c, I don't see any problem with this patch from
libvirt's point of view.

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: 620 bytes --]

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

* Re: [Qemu-devel] [PATCH 30/34] qemu-ga: switch to the new error format on the wire
  2012-08-03 17:56     ` Eric Blake
@ 2012-08-03 18:02       ` Luiz Capitulino
  0 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-03 18:02 UTC (permalink / raw)
  To: Eric Blake; +Cc: kwolf, aliguori, qemu-devel, armbru, Michael Roth, pbonzini

On Fri, 03 Aug 2012 11:56:29 -0600
Eric Blake <eblake@redhat.com> wrote:

> On 08/03/2012 11:44 AM, Michael Roth wrote:
> > On Wed, Aug 01, 2012 at 10:02:50PM -0300, Luiz Capitulino wrote:
> >> IMPORTANT: this BREAKS qemu-ga compatibility for the error response.
> >>
> >> Instead of returning something like:
> >>
> >> { "error": { "class": "InvalidParameterValue",
> >>              "data": {"name": "mode", "expected": "halt|powerdown|reboot" } } }
> >>
> >> qemu-ga now returns:
> >>
> >>  { "error": { "class": "GenericError",
> >>               "desc": "Parameter 'mode' expects halt|powerdown|reboot" } }
> > 
> 
> >>
> >> Notice that this is also a bug fix, as qemu-ga wasn't returning the
> >> human message.
> >>
> >> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> > 
> > So, if the libvirt folks are okay with it:
> 
> The only use libvirt made of existing qemu-ga errors was to stringify
> them in order to pass on an error message to the user when a command
> failed.  Existing libvirt attempts to look up the 'desc' field, and when
> it is lacking, then attempts to stringify the 'class' field based on a
> finite list of known classes.  Qemu is now shrinking the list of known
> classes but providing a 'desc' field, so the error message quality in
> libvirt will actually improve.  After reading libvirt's
> src/qemu/qemu_agent.c, I don't see any problem with this patch from
> libvirt's point of view.

Yeah, I actually have a request from Michal to do just that (add 'desc'
to qemu-ga's errors).

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

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

* Re: [Qemu-devel] [PATCH 17/34] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS
  2012-08-02 17:08     ` Luiz Capitulino
@ 2012-08-03 18:26       ` Michael Roth
  2012-08-03 20:31         ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Michael Roth @ 2012-08-03 18:26 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, armbru, pbonzini, eblake

On Thu, Aug 02, 2012 at 02:08:48PM -0300, Luiz Capitulino wrote:
> On Thu, 2 Aug 2012 11:54:11 -0500
> Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> 
> > On Wed, Aug 01, 2012 at 10:02:37PM -0300, Luiz Capitulino wrote:
> > > This error is currently returned by inet_connect_opts(), however
> > > it causes the follow spurious message on HMP:
> > > 
> > >     (qemu) migrate tcp:0:4444
> > >     migrate: Connection can not be completed immediately
> > >     (qemu)
> > > 
> > > But migration succeeds.
> > 
> > I think the core issue is that inet_connect_opts() passes back the
> > QERR_SOCKET_CONNECT_IN_PROGRESS via Error (which is fine), but that
> > we have users that erroneous pass this error up the stack, when really,
> > when specifying blocking=on as one of the options, they should be
> > expecting and doing specific handling for this error.
> 
> You're right here.
> 
> > So if we fix that (by simply using a local Error when doing the call and
> > using error_propagate() for non QSCIP errors), I think we can basically
> > drop patches 14-17 by fixing the callers in that manner and just giving QSCIP
> > it's own error class.
> 
> I don't think QSCIP errors is something we should report to QMP clients, at
> least not for the use-case this patch is about, hence we should not have
> a specific error class for this.

But we do have internal users besides QMP, and in this case they're
interested in a specific error. What if we generalized it to EAGAIN or
something? It's seems to me a fairly reasonable exception since it's one
of the few errno-style errors that we don't generally propagate up the
stack and need to check for explicitly...

> 
> As pointed out by Markus in his review, keeping the in_progress flag introduced
> by patch 14/34 should be enough to drop patches 15 and 16.

Although, being an exceptional case I guess having an "in_progress" field
to functions would use it is reasonable...

I think I'd still prefer a class for QSCIP/EAGAIN that we could use for
socket utility functions, but I'm okay with an in_progress param.

> 
> > Relying on the errno result was something these socket errors were
> > specifically meant to fix, since errno is set multiple times
> > throughout the function and extracting an errno reliably requires
> > callers to examine all the possible error paths and errno setters. So I
> > think it's a regression to go back to the old behavior, and these were
> > issues found in inet_connect() when we attempted to generalize it's
> > usage for non-blocking connections.
> 
> I'm not completely sure I agree because the new error format doesn't allow
> callers to programatically know the cause of an failure. That's what errno

Is error_get_class() not to be used for this purpose? It seems like a
good thing to allow for in the odd circumstances where we do end up
adding new error classes (unless the notion of error classes is purely
legacy support for ones that libvirt is dependent on, and new ones will
never be added?)

> callers to programatically know the cause of an failure. That's what errno
> is for, though.

But it's just simply unusable when calling into a function that has
multiple paths that can set it (or clobber it). Errno values frequently
require the context of the function that set it to do anything intelligent,
which is why QSCIP was added to remove that burden from users of
inet_connect_opts() and friends.

It's good that errors are no longer tethered to the errors
descriptions/parameters and that that has amounted to a big reduction
in the number of error classes we have, but that doesn't mean we shouldn't
be open to added new error classes in the future, where it makes sense.

But, again, an in_progress param seems like a workable compromise here, I
just think prefering this approach over new error classes may lead to
unecessary code churn in the future.

> 
> But I'll drop the patch that changes inet_connect() to return errno,
> so it's not worth it to discuss this specific case.
> 

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

* Re: [Qemu-devel] [PATCH 17/34] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS
  2012-08-03 18:26       ` Michael Roth
@ 2012-08-03 20:31         ` Luiz Capitulino
  0 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-03 20:31 UTC (permalink / raw)
  To: Michael Roth; +Cc: kwolf, aliguori, qemu-devel, armbru, pbonzini, eblake

On Fri, 3 Aug 2012 13:26:27 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> On Thu, Aug 02, 2012 at 02:08:48PM -0300, Luiz Capitulino wrote:
> > On Thu, 2 Aug 2012 11:54:11 -0500
> > Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> > 
> > > On Wed, Aug 01, 2012 at 10:02:37PM -0300, Luiz Capitulino wrote:
> > > > This error is currently returned by inet_connect_opts(), however
> > > > it causes the follow spurious message on HMP:
> > > > 
> > > >     (qemu) migrate tcp:0:4444
> > > >     migrate: Connection can not be completed immediately
> > > >     (qemu)
> > > > 
> > > > But migration succeeds.
> > > 
> > > I think the core issue is that inet_connect_opts() passes back the
> > > QERR_SOCKET_CONNECT_IN_PROGRESS via Error (which is fine), but that
> > > we have users that erroneous pass this error up the stack, when really,
> > > when specifying blocking=on as one of the options, they should be
> > > expecting and doing specific handling for this error.
> > 
> > You're right here.
> > 
> > > So if we fix that (by simply using a local Error when doing the call and
> > > using error_propagate() for non QSCIP errors), I think we can basically
> > > drop patches 14-17 by fixing the callers in that manner and just giving QSCIP
> > > it's own error class.
> > 
> > I don't think QSCIP errors is something we should report to QMP clients, at
> > least not for the use-case this patch is about, hence we should not have
> > a specific error class for this.
> 
> But we do have internal users besides QMP, and in this case they're
> interested in a specific error. What if we generalized it to EAGAIN or
> something? It's seems to me a fairly reasonable exception since it's one
> of the few errno-style errors that we don't generally propagate up the
> stack and need to check for explicitly...

The fact that we don't propagate it up and that this is used only for
communication between two functions are the reasons for not creating an
error class for it.

For this specific case, my in_progress change is a better solution IMO.

> > As pointed out by Markus in his review, keeping the in_progress flag introduced
> > by patch 14/34 should be enough to drop patches 15 and 16.
> 
> Although, being an exceptional case I guess having an "in_progress" field
> to functions would use it is reasonable...
> 
> I think I'd still prefer a class for QSCIP/EAGAIN that we could use for
> socket utility functions, but I'm okay with an in_progress param.
> 
> > 
> > > Relying on the errno result was something these socket errors were
> > > specifically meant to fix, since errno is set multiple times
> > > throughout the function and extracting an errno reliably requires
> > > callers to examine all the possible error paths and errno setters. So I
> > > think it's a regression to go back to the old behavior, and these were
> > > issues found in inet_connect() when we attempted to generalize it's
> > > usage for non-blocking connections.
> > 
> > I'm not completely sure I agree because the new error format doesn't allow
> > callers to programatically know the cause of an failure. That's what errno
> 
> Is error_get_class() not to be used for this purpose? It seems like a
> good thing to allow for in the odd circumstances where we do end up
> adding new error classes (unless the notion of error classes is purely
> legacy support for ones that libvirt is dependent on, and new ones will
> never be added?)

I think I didn't express myself correctly here.

Yes, it's possible to use error_get_class() to programatically check for an
error class. There's nothing wrong with that.

The problem though, is that this series shrinks the number of errors classes
from 70+ to a few. So, most errors causes will be GenericError.

Take the block layer for example. Several block layer functions check for
errno and take different actions depending on the error cause. When we
Errorify the block layer (and we'll do it to propagate the error cause to
users) we won't be able to drop errno in favor of error_get_class(), otherwise
we'll be back to dozens of error classes (worse, most of them will only
be useful for the block layer or any subsystem doing similar things).

For the block layer case, I think we'll need to introduce error_sete() and
error_get_errno().

> > callers to programatically know the cause of an failure. That's what errno
> > is for, though.
> 
> But it's just simply unusable when calling into a function that has
> multiple paths that can set it (or clobber it). Errno values frequently
> require the context of the function that set it to do anything intelligent,
> which is why QSCIP was added to remove that burden from users of
> inet_connect_opts() and friends.

That's case by case. If there's a case where adding a new class make sense,
then we can do it. I don't think this is the case, though. Besides, the current
usage of QSCIP is buggy.

> It's good that errors are no longer tethered to the errors
> descriptions/parameters and that that has amounted to a big reduction
> in the number of error classes we have, but that doesn't mean we shouldn't
> be open to added new error classes in the future, where it makes sense.
> 
> But, again, an in_progress param seems like a workable compromise here, I
> just think prefering this approach over new error classes may lead to
> unecessary code churn in the future.
> 
> > 
> > But I'll drop the patch that changes inet_connect() to return errno,
> > so it's not worth it to discuss this specific case.
> > 
> 

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

* Re: [Qemu-devel] [PATCH 15/34] net: inet_connect(), inet_connect_opts(): return -errno
  2012-08-02 15:50     ` Markus Armbruster
  2012-08-02 16:49       ` Luiz Capitulino
@ 2012-08-06  6:52       ` Amos Kong
  2012-08-06 19:59         ` Luiz Capitulino
  1 sibling, 1 reply; 85+ messages in thread
From: Amos Kong @ 2012-08-06  6:52 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: kwolf, aliguori, Juan Quintela, mdroth, qemu-devel, pbonzini,
	Luiz Capitulino, eblake



----- Original Message -----
> [cc: Juan & Amos]
> 
> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > On Wed,  1 Aug 2012 22:02:35 -0300
> > Luiz Capitulino <lcapitulino@redhat.com> wrote:
> >
> >> Next commit wants to use this.
> >> 
> >> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> >> ---
> >> 
> >> This patch is an interesting case, because one of the goal of the
> >> error
> >> format that's being replaced was that callers could use it to know
> >> the
> >> error cause (with error_is_type().
> >> 
> >> However, the new error format doesn't allow this as most errors
> >> are
> >> class GenericError. So, we'll have to use errno to know the error
> >> cause,
> >> this is the case of inet_connect() when called by
> >> tcp_start_outgoing_migration().
> >
> > I'm thinking in doing this differently. Instead of returning errno,
> > we
> > could have:
> >
> >  error_sete(Error **err, ErrorClass err_class, int err_no,
> >             const char *fmt, ...);
> >
> > Then we store err_no in Error, and also add error_get_errno().
> >
> > Comments?
> 
> Maybe that'll turn out to be useful elsewhere, but not here.
> 
> The purpose of PATCH 14+15 is to permit purging error_is_type() from
> tcp_start_outgoing_migration() in PATCH 16.  Let's have a look at all
> three patches together.
> 
> This is tcp_start_outgoing_migration() now:
> 
>     int tcp_start_outgoing_migration(MigrationState *s, const char
>     *host_port,
>                                      Error **errp)
>     {
>         s->get_error = socket_errno;
>         s->write = socket_write;
>         s->close = tcp_close;
> 
>         s->fd = inet_connect(host_port, false, errp);
> 
>         if (!error_is_set(errp)) {
>             migrate_fd_connect(s);
>         } else if (error_is_type(*errp,
>         QERR_SOCKET_CONNECT_IN_PROGRESS)) {
>             DPRINTF("connect in progress\n");
>             qemu_set_fd_handler2(s->fd, NULL, NULL,
>             tcp_wait_for_connect, s);
>         } else if (error_is_type(*errp, QERR_SOCKET_CREATE_FAILED)) {
>             DPRINTF("connect failed\n");
>             return -1;
>         } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_FAILED))
>         {
>             DPRINTF("connect failed\n");
>             migrate_fd_error(s);
>             return -1;
>         } else {
>             DPRINTF("unknown error\n");
>             return -1;
>         }
> 
>         return 0;
>     }
> 
> Cases:
> 
> 1. Success
> 
>    Proceeed to migrate_fd_connect().
> 
> 2. QERR_SOCKET_CONNECT_IN_PROGRESS
> 
>    connect() failed with -EINPROGRESS.  Not actually an error.  Set
>    up
>    appropriate callback.
> 
> 3. QERR_SOCKET_CONNECT_FAILED
> 
>    getaddrinfo() succeeded, but could not connect() to any of the
>    addresses.  Fail migration with migrate_fd_error().
> 
> 4. QERR_SOCKET_CREATE_FAILED
> 
>    The error grabbag:
> 
>    * inet_parse() failed, or
> 
>    * inet_connect_opts() misses host and/or port (should never
>    happen)
> 
>    * getaddrinfo() failed
> 
>    Bug: neglects to migrate_fd_error()!  Broken in commit d5c5dacc.


Before commit d5c5dacc,  migrate_fd_error() would not be called
when fail to create socket.

-    s->fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
-    if (s->fd == -1) {
-        DPRINTF("Unable to open socket");
-        return -socket_error();
-    }


If you call migrate_fd_error() in this situation, qemu would hang.


> 5. Anything else
> 
>    Should never happen.  Handled exactly like 4.
> 
> If I undo d5c5dacc's damage (untested), it looks like this:
> 
>     int tcp_start_outgoing_migration(MigrationState *s, const char
>     *host_port,
>                                      Error **errp)
>     {
>         s->get_error = socket_errno;
>         s->write = socket_write;
>         s->close = tcp_close;
> 
>         s->fd = inet_connect(host_port, false, errp);
> 
>         if (!error_is_set(errp)) {
>             migrate_fd_connect(s);
>         } else if (error_is_type(*errp,
>         QERR_SOCKET_CONNECT_IN_PROGRESS)) {
>             DPRINTF("connect in progress\n");
>             qemu_set_fd_handler2(s->fd, NULL, NULL,
>             tcp_wait_for_connect, s);
>         } else {
>             DPRINTF("connect failed\n");
>             migrate_fd_error(s);

qemu would hang if socket isn't created successfully.

>             return -1;
>         }
> 
>         return 0;
>     }
> 
> Et voilà, the only error_is_type() is the non-error "in progress",
> and
> your new in_progress covers that already, no need for an errno.
>

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

* Re: [Qemu-devel] [PATCH 17/34] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS
  2012-08-02 15:58   ` Markus Armbruster
@ 2012-08-06  7:04     ` Amos Kong
  0 siblings, 0 replies; 85+ messages in thread
From: Amos Kong @ 2012-08-06  7:04 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, Luiz Capitulino,
	eblake

----- Original Message -----
> [cc: Amos]
> 
> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > This error is currently returned by inet_connect_opts(), however
> > it causes the follow spurious message on HMP:
> >
> >     (qemu) migrate tcp:0:4444
> >     migrate: Connection can not be completed immediately

We use non-block socket for migration, connect() might return
before connection complete.

However, I agree with remove this note.


> >     (qemu)
> >
> > But migration succeeds.
>
> Broken in commit d5c5dacc.
> 
> Commit a6ba35b3 earlier in the same series might have broken other
> users
> of inet_connect() and inet_connect_opts() similarly.  Would be nice
> to
> know.  Whatever was brolen, your patch fixes it, too.


INPROGRESS 'error' will only be returned for non-block socket.
Other users(vnc, nbd) use block socket, and they pass a 'NULL'
to second argument of inet_connect(QemuOpts *opts, Error **errp),
so this Error doesn't effect them.


> > inet_connect_opts() has a 'in_progress' argument that callers can
> > use to check whether a connection is in progress. The QERR_ macro
> > is not needed anymore.
> >
> > PS: I didn't test with QMP, but I guess the migrate command will
> >     return an error response.
> 
> Plausible.
> 
> I'd squash this into PATCH 14, because the purpose of the combined
> patch
> will be obvious.  Right now, 14's isn't.
> 
> >
> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> > ---
> >  qemu-sockets.c | 2 --
> >  qerror.c       | 4 ----
> >  qerror.h       | 3 ---
> >  3 files changed, 9 deletions(-)
> >
> > diff --git a/qemu-sockets.c b/qemu-sockets.c
> > index 82f4736..7196c5f 100644
> > --- a/qemu-sockets.c
> > +++ b/qemu-sockets.c
> > @@ -284,8 +284,6 @@ int inet_connect_opts(QemuOpts *opts, bool
> > *in_progress, Error **errp)
> >              if (in_progress) {
> >                  *in_progress = true;
> >              }
> > -
> > -            error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS);
> >          } else if (rc < 0) {
> >              if (NULL == e->ai_next)
> >                  fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n",
> >                  __FUNCTION__,
> > diff --git a/qerror.c b/qerror.c
> > index 691d8a8..33b8780 100644
> > --- a/qerror.c
> > +++ b/qerror.c
> > @@ -309,10 +309,6 @@ static const QErrorStringTable qerror_table[]
> > = {
> >          .desc      = "Could not start VNC server on %(target)",
> >      },
> >      {
> > -        .error_fmt = QERR_SOCKET_CONNECT_IN_PROGRESS,
> > -        .desc      = "Connection can not be completed
> > immediately",
> > -    },
> > -    {
> >          .error_fmt = QERR_SOCKET_CONNECT_FAILED,
> >          .desc      = "Failed to connect to socket",
> >      },
> > diff --git a/qerror.h b/qerror.h
> > index de8497d..52ce58d 100644
> > --- a/qerror.h
> > +++ b/qerror.h
> > @@ -240,9 +240,6 @@ char *qerror_format(const char *fmt, QDict
> > *error);
> >  #define QERR_VNC_SERVER_FAILED \
> >      "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
> >  
> > -#define QERR_SOCKET_CONNECT_IN_PROGRESS \
> > -    "{ 'class': 'SockConnectInprogress', 'data': {} }"
> > -
> >  #define QERR_SOCKET_CONNECT_FAILED \
> >      "{ 'class': 'SockConnectFailed', 'data': {} }"
> 

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

* Re: [Qemu-devel] [PATCH 15/34] net: inet_connect(), inet_connect_opts(): return -errno
  2012-08-06  6:52       ` Amos Kong
@ 2012-08-06 19:59         ` Luiz Capitulino
  0 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-06 19:59 UTC (permalink / raw)
  To: Amos Kong
  Cc: kwolf, aliguori, Juan Quintela, Markus Armbruster, mdroth,
	qemu-devel, pbonzini, eblake

On Mon, 6 Aug 2012 02:52:24 -0400 (EDT)
Amos Kong <akong@redhat.com> wrote:

> 
> 
> ----- Original Message -----
> > [cc: Juan & Amos]
> > 
> > Luiz Capitulino <lcapitulino@redhat.com> writes:
> > 
> > > On Wed,  1 Aug 2012 22:02:35 -0300
> > > Luiz Capitulino <lcapitulino@redhat.com> wrote:
> > >
> > >> Next commit wants to use this.
> > >> 
> > >> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> > >> ---
> > >> 
> > >> This patch is an interesting case, because one of the goal of the
> > >> error
> > >> format that's being replaced was that callers could use it to know
> > >> the
> > >> error cause (with error_is_type().
> > >> 
> > >> However, the new error format doesn't allow this as most errors
> > >> are
> > >> class GenericError. So, we'll have to use errno to know the error
> > >> cause,
> > >> this is the case of inet_connect() when called by
> > >> tcp_start_outgoing_migration().
> > >
> > > I'm thinking in doing this differently. Instead of returning errno,
> > > we
> > > could have:
> > >
> > >  error_sete(Error **err, ErrorClass err_class, int err_no,
> > >             const char *fmt, ...);
> > >
> > > Then we store err_no in Error, and also add error_get_errno().
> > >
> > > Comments?
> > 
> > Maybe that'll turn out to be useful elsewhere, but not here.
> > 
> > The purpose of PATCH 14+15 is to permit purging error_is_type() from
> > tcp_start_outgoing_migration() in PATCH 16.  Let's have a look at all
> > three patches together.
> > 
> > This is tcp_start_outgoing_migration() now:
> > 
> >     int tcp_start_outgoing_migration(MigrationState *s, const char
> >     *host_port,
> >                                      Error **errp)
> >     {
> >         s->get_error = socket_errno;
> >         s->write = socket_write;
> >         s->close = tcp_close;
> > 
> >         s->fd = inet_connect(host_port, false, errp);
> > 
> >         if (!error_is_set(errp)) {
> >             migrate_fd_connect(s);
> >         } else if (error_is_type(*errp,
> >         QERR_SOCKET_CONNECT_IN_PROGRESS)) {
> >             DPRINTF("connect in progress\n");
> >             qemu_set_fd_handler2(s->fd, NULL, NULL,
> >             tcp_wait_for_connect, s);
> >         } else if (error_is_type(*errp, QERR_SOCKET_CREATE_FAILED)) {
> >             DPRINTF("connect failed\n");
> >             return -1;
> >         } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_FAILED))
> >         {
> >             DPRINTF("connect failed\n");
> >             migrate_fd_error(s);
> >             return -1;
> >         } else {
> >             DPRINTF("unknown error\n");
> >             return -1;
> >         }
> > 
> >         return 0;
> >     }
> > 
> > Cases:
> > 
> > 1. Success
> > 
> >    Proceeed to migrate_fd_connect().
> > 
> > 2. QERR_SOCKET_CONNECT_IN_PROGRESS
> > 
> >    connect() failed with -EINPROGRESS.  Not actually an error.  Set
> >    up
> >    appropriate callback.
> > 
> > 3. QERR_SOCKET_CONNECT_FAILED
> > 
> >    getaddrinfo() succeeded, but could not connect() to any of the
> >    addresses.  Fail migration with migrate_fd_error().
> > 
> > 4. QERR_SOCKET_CREATE_FAILED
> > 
> >    The error grabbag:
> > 
> >    * inet_parse() failed, or
> > 
> >    * inet_connect_opts() misses host and/or port (should never
> >    happen)
> > 
> >    * getaddrinfo() failed
> > 
> >    Bug: neglects to migrate_fd_error()!  Broken in commit d5c5dacc.
> 
> 
> Before commit d5c5dacc,  migrate_fd_error() would not be called
> when fail to create socket.
> 
> -    s->fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
> -    if (s->fd == -1) {
> -        DPRINTF("Unable to open socket");
> -        return -socket_error();
> -    }
> 
> 
> If you call migrate_fd_error() in this situation, qemu would hang.

How did you test this?

I've added the call to migrate_fd_error() as Markus suggests above and
tested it by changing inet_connect_opts() to trigger all possible errors
and everything seems to work fine.

> 
> 
> > 5. Anything else
> > 
> >    Should never happen.  Handled exactly like 4.
> > 
> > If I undo d5c5dacc's damage (untested), it looks like this:
> > 
> >     int tcp_start_outgoing_migration(MigrationState *s, const char
> >     *host_port,
> >                                      Error **errp)
> >     {
> >         s->get_error = socket_errno;
> >         s->write = socket_write;
> >         s->close = tcp_close;
> > 
> >         s->fd = inet_connect(host_port, false, errp);
> > 
> >         if (!error_is_set(errp)) {
> >             migrate_fd_connect(s);
> >         } else if (error_is_type(*errp,
> >         QERR_SOCKET_CONNECT_IN_PROGRESS)) {
> >             DPRINTF("connect in progress\n");
> >             qemu_set_fd_handler2(s->fd, NULL, NULL,
> >             tcp_wait_for_connect, s);
> >         } else {
> >             DPRINTF("connect failed\n");
> >             migrate_fd_error(s);
> 
> qemu would hang if socket isn't created successfully.
> 
> >             return -1;
> >         }
> > 
> >         return 0;
> >     }
> > 
> > Et voilà, the only error_is_type() is the non-error "in progress",
> > and
> > your new in_progress covers that already, no need for an errno.
> >
> 

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

* Re: [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-02 13:54     ` Luiz Capitulino
@ 2012-08-10  7:56       ` Markus Armbruster
  2012-08-10 13:33         ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Markus Armbruster @ 2012-08-10  7:56 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Revisited this one on review of v2, replying here for context.

Luiz Capitulino <lcapitulino@redhat.com> writes:

> On Thu, 02 Aug 2012 13:35:54 +0200
> Markus Armbruster <armbru@redhat.com> wrote:
>
>> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> 
>> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
>> > ---
>> >  block.c          | 1 +
>> >  qapi-schema.json | 7 +++++--
>> >  2 files changed, 6 insertions(+), 2 deletions(-)
>> >
>> > diff --git a/block.c b/block.c
>> > index b38940b..9c113b8 100644
>> > --- a/block.c
>> > +++ b/block.c
>> > @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
>> >              info->value->inserted->ro = bs->read_only;
>> >              info->value->inserted->drv = g_strdup(bs->drv->format_name);
>> >              info->value->inserted->encrypted = bs->encrypted;
>> > +            info->value->inserted->valid_encryption_key = bs->valid_key;
>> >              if (bs->backing_file[0]) {
>> >                  info->value->inserted->has_backing_file = true;
>> >                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
>> > diff --git a/qapi-schema.json b/qapi-schema.json
>> > index bc55ed2..1b2d7f5 100644
>> > --- a/qapi-schema.json
>> > +++ b/qapi-schema.json
>> > @@ -400,6 +400,8 @@
>> >  #
>> >  # @encrypted: true if the backing device is encrypted
>> >  #
>> > +# @valid_encryption_key: true if a valid encryption key has been set
>> > +#
>> >  # @bps: total throughput limit in bytes per second is specified
>> >  #
>> >  # @bps_rd: read throughput limit in bytes per second is specified
>> > @@ -419,8 +421,9 @@
>> >  { 'type': 'BlockDeviceInfo',
>> >    'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
>> >              '*backing_file': 'str', 'encrypted': 'bool',
>> > -            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
>> > -            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
>> > +            'valid_encryption_key': 'bool', 'bps': 'int',
>> > +            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
>> > +            'iops_rd': 'int', 'iops_wr': 'int'} }
>> >  
>> >  ##
>> >  # @BlockDeviceIoStatus:
>> 
>> BlockDeviceInfo is API, isn't it?
>
> Yes.
>
>> Note that bs->valid_key currently implies bs->encrypted.  bs->valid_key
>> && !bs->encrypted is impossible.  Should we make valid_encryption_key
>> only available when encrypted?
>
> I don't think so. It's a bool, so it's ok for it to be false when
> encrypted is false.

What bothers me is encrypted=false, valid_encryption_key=true.

>> valid_encryption_key is a bit long for my taste.  Yours may be
>> different.
>
> We should choose more descriptive and self-documenting names for the
> protocol. Besides, I can't think of anything shorter that won't get
> cryptic.
>
> Suggestions are always welcome though :)

valid_encryption_key sounds like the value is the valid key.

got_crypt_key?  Also avoids "valid".  Good, because current encrypted
formats don't actually validate the key; they happily accept any key.
GIGO.  In theory, you can trash a disk that way.  In practice, we can
hope the guest will refuse to touch the disk, because it can't recognize
partition table / filesystems.

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

* Re: [Qemu-devel] [PATCH 12/34] hmp: hmp_cont(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-02 14:22     ` Luiz Capitulino
@ 2012-08-10  8:42       ` Markus Armbruster
  2012-08-10 14:22         ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Markus Armbruster @ 2012-08-10  8:42 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> On Thu, 02 Aug 2012 13:53:08 +0200
> Markus Armbruster <armbru@redhat.com> wrote:
>
>> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> 
>> > This commit changes hmp_cont() to loop through all block devices
>> > and proactively set an encryption key for any encrypted device
>> > without a valid one.
>> >
>> > This change is needed because QERR_DEVICE_ENCRYPTED is going to be
>> > dropped by a future commit.
>> >
>> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
>> > ---
>> >  hmp.c | 43 +++++++++++++++++++++++++------------------
>> >  1 file changed, 25 insertions(+), 18 deletions(-)
>> >
>> > diff --git a/hmp.c b/hmp.c
>> > index 6b72a64..1ebeb63 100644
>> > --- a/hmp.c
>> > +++ b/hmp.c
>> > @@ -610,34 +610,41 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
>> >  
>> >  static void hmp_cont_cb(void *opaque, int err)
>> >  {
>> > -    Monitor *mon = opaque;
>> > -
>> >      if (!err) {
>> > -        hmp_cont(mon, NULL);
>> > +        qmp_cont(NULL);
>> >      }
>> >  }
>> >  
>> > -void hmp_cont(Monitor *mon, const QDict *qdict)
>> > +static bool blockinfo_is_encrypted(const BlockInfo *bdev)
>> >  {
>> > -    Error *errp = NULL;
>> > -
>> > -    qmp_cont(&errp);
>> > -    if (error_is_set(&errp)) {
>> > -        if (error_is_type(errp, QERR_DEVICE_ENCRYPTED)) {
>> > -            const char *device;
>> > +    return (bdev->inserted && bdev->inserted->encrypted);
>> > +}
>> >  
>> > -            /* The device is encrypted. Ask the user for the password
>> > -               and retry */
>> > +static bool blockinfo_key_is_set(const BlockInfo *bdev)
>> > +{
>> > +    return (bdev->inserted && bdev->inserted->valid_encryption_key);
>> > +}
>> >  
>> > -            device = error_get_field(errp, "device");
>> > -            assert(device != NULL);
>> > +void hmp_cont(Monitor *mon, const QDict *qdict)
>> > +{
>> > +    BlockInfoList *bdev_list, *bdev;
>> > +    Error *errp = NULL;
>> >  
>> > -            monitor_read_block_device_key(mon, device, hmp_cont_cb, mon);
>> > -            error_free(errp);
>> > -            return;
>> > +    bdev_list = qmp_query_block(NULL);
>> > +    for (bdev = bdev_list; bdev; bdev = bdev->next) {
>> > +        if (blockinfo_is_encrypted(bdev->value) &&
>> > +            !blockinfo_key_is_set(bdev->value)) {
>> > +                monitor_read_block_device_key(mon, bdev->value->device,
>> > +                                              hmp_cont_cb, NULL);
>> > +                goto out;
>> >          }
>> > -        hmp_handle_error(mon, &errp);
>> >      }
>> > +
>> > +    qmp_cont(&errp);
>> > +    hmp_handle_error(mon, &errp);
>> > +
>> > +out:
>> > +    qapi_free_BlockInfoList(bdev_list);
>> >  }
>> >  
>> >  void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
>> 
>> Quote my previous analysis:
>> 
>> Diff makes this change look worse than it is.  Odd: M-x ediff gets it
>> right.  Anyway, here's how I think it works:
>> 
>> Unchanged qmp_cont(): search the bdrv_states for the first encrypted one
>> without a key.  If found, set err argument to QERR_DEVICE_ENCRYPTED.
>> Other errors unrelated to encrypted devices are also possible.
>> 
>> hmp_cont() before: try qmp_cont().  If we get QERR_DEVICE_ENCRYPTED,
>> extract the device from the error object, and prompt for its key, with a
>> callback that retries hmp_cont() if the key was provided.
>> 
>> After: search the bdrv_states for an encrypted one without a key.  If
>> there is none, qmp_cont(), no special error handling.  If there is one,
>> prompt for its key, with a callback that runs qmp_cont() if the key was
>> provided.
>> 
>> End quote.
>> 
>> Two observations:
>> 
>> 1. I don't understand how this works for multiple encrypted BDSs without
>> keys.  If there are any, hmp_cont() starts reading the first one's key,
>> then returns.  But the callback doesn't start reading the next one's
>> key.  Please explain.
>
> The callback calls qmp_cont(), which will fail. Then the user will enter
> cont again, and the loop on BlockInfos will run again and the user will
> be asked for the password of the next image.
>
> IOW, each time cont is issued by the user it will ask for the password
> of a different device.
>
> That's the current behavior, and I believe it was also the behavior before
> I converted cont to the qapi.

Ugh.  Clunky even for QEMU standards.

cont gives no indication that the run state change didn't happen.

>> 2. qmp_cont() uses bdrv_key_required() to test whether a BDS lacks a
>> key.  Your new hmp_cont() uses blockinfo_is_encrypted() &&
>> !blockinfo_key_is_set().  Not obvious that the two are equivalent.
>> 
>> I'm afraid they are not.  bdrv_key_required() checks the backing image
>> first:
>> 
>>     int bdrv_key_required(BlockDriverState *bs)
>>     {
>>         BlockDriverState *backing_hd = bs->backing_hd;
>> 
>>         if (backing_hd && backing_hd->encrypted && !backing_hd->valid_key)
>>             return 1;
>>         return (bs->encrypted && !bs->valid_key);
>>     }
>> 
>> Your code doesn't:
>> 
>>     static bool blockinfo_is_encrypted(const BlockInfo *bdev)
>>     {
>>         return (bdev->inserted && bdev->inserted->encrypted);
>>     }
>> 
>>     static bool blockinfo_key_is_set(const BlockInfo *bdev)
>>     {
>>         return (bdev->inserted && bdev->inserted->valid_encryption_key);
>>     }
>> 
>>     BlockInfoList *qmp_query_block(Error **errp)
>>     {
>>         BlockInfoList *head = NULL, *cur_item = NULL;
>>         BlockDriverState *bs;
>> 
>>         QTAILQ_FOREACH(bs, &bdrv_states, list) {
>>             BlockInfoList *info = g_malloc0(sizeof(*info));
>> [...]
>>             if (bs->drv) {
>>                 info->value->has_inserted = true;
>>                 info->value->inserted = g_malloc0(sizeof(*info->value->inserted));
>> [...]
>>                 info->value->inserted->encrypted = bs->encrypted;
>>                 info->value->inserted->valid_encryption_key = bs->valid_key;
>> [...]
>> 
>> Are you sure this is correct?
>
> Is it actually possible for backing_hd to be false and valid_key to be true?

Yes.  Let's create an encrypted QCOW2 image without backing_file:

    $ qemu-img create -f qcow2 -o encryption,size=1G foo.qcow2
    Formatting 'foo.qcow2', fmt=qcow2 size=1073741824 encryption=on cluster_size=65536 lazy_refcounts=off 
    $ qemu-img info foo.qcow2
    Disk image 'foo.qcow2' is encrypted.
    password: 
    image: foo.qcow2
    file format: qcow2
    virtual size: 1.0G (1073741824 bytes)
    disk size: 136K
    encrypted: yes
    cluster_size: 65536
    $ qemu-system-x86_64 -nodefaults --enable-kvm -S -m 512 -vnc :0 -usb -monitor stdio -drive if=ide,file=foo.qcow2,id=foo
    QEMU 1.1.50 monitor - type 'help' for more information
    (qemu) info block
    foo: removable=0 io-status=ok file=foo.qcow2 ro=0 drv=qcow2 encrypted=1 bps=0 bps_rd=0 bps_wr=0 iops=0 iops_rd=0 iops_wr=0
    (qemu) c
    foo (foo.qcow2) is encrypted.
    Password: 

Now wrap an unencrypted one around it:

    $ qemu-img create -f qcow2 -o size=1G,backing_file=foo.qcow2 bar.qcow2
    Formatting 'bar.qcow2', fmt=qcow2 size=1073741824 backing_file='foo.qcow2' encryption=off cluster_size=65536 lazy_refcounts=off 
    $ qemu-img info bar.qcow2
    image: bar.qcow2
    file format: qcow2
    virtual size: 1.0G (1073741824 bytes)
    disk size: 196K
    cluster_size: 65536
    backing file: foo.qcow2
    $ qemu-system-x86_64 -nodefaults --enable-kvm -S -m 512 -vnc :0 -usb -monitor stdio -drive if=ide,file=bar.qcow2,id=foo
    QEMU 1.1.50 monitor - type 'help' for more information
    (qemu) c
    'foo' (foo.qcow2) is encrypted
    (qemu) 

Regression :)

>> I understand we require HMP code to go via QMP for everything, to keep
>> HMP honest.  This case shows a drawback: duplicated code, leading to
>> inconsistencies.
>
> Keeping DeviceEncrypted would solve this.

Another way is to replace valid-encryption-key by the predicate that's
actually wanted: key-required.

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

* Re: [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-10  7:56       ` Markus Armbruster
@ 2012-08-10 13:33         ` Luiz Capitulino
  2012-08-10 16:35           ` Markus Armbruster
  0 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-10 13:33 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

On Fri, 10 Aug 2012 09:56:11 +0200
Markus Armbruster <armbru@redhat.com> wrote:

> Revisited this one on review of v2, replying here for context.
> 
> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > On Thu, 02 Aug 2012 13:35:54 +0200
> > Markus Armbruster <armbru@redhat.com> wrote:
> >
> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> 
> >> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> >> > ---
> >> >  block.c          | 1 +
> >> >  qapi-schema.json | 7 +++++--
> >> >  2 files changed, 6 insertions(+), 2 deletions(-)
> >> >
> >> > diff --git a/block.c b/block.c
> >> > index b38940b..9c113b8 100644
> >> > --- a/block.c
> >> > +++ b/block.c
> >> > @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
> >> >              info->value->inserted->ro = bs->read_only;
> >> >              info->value->inserted->drv = g_strdup(bs->drv->format_name);
> >> >              info->value->inserted->encrypted = bs->encrypted;
> >> > +            info->value->inserted->valid_encryption_key = bs->valid_key;
> >> >              if (bs->backing_file[0]) {
> >> >                  info->value->inserted->has_backing_file = true;
> >> >                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
> >> > diff --git a/qapi-schema.json b/qapi-schema.json
> >> > index bc55ed2..1b2d7f5 100644
> >> > --- a/qapi-schema.json
> >> > +++ b/qapi-schema.json
> >> > @@ -400,6 +400,8 @@
> >> >  #
> >> >  # @encrypted: true if the backing device is encrypted
> >> >  #
> >> > +# @valid_encryption_key: true if a valid encryption key has been set
> >> > +#
> >> >  # @bps: total throughput limit in bytes per second is specified
> >> >  #
> >> >  # @bps_rd: read throughput limit in bytes per second is specified
> >> > @@ -419,8 +421,9 @@
> >> >  { 'type': 'BlockDeviceInfo',
> >> >    'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
> >> >              '*backing_file': 'str', 'encrypted': 'bool',
> >> > -            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
> >> > -            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
> >> > +            'valid_encryption_key': 'bool', 'bps': 'int',
> >> > +            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
> >> > +            'iops_rd': 'int', 'iops_wr': 'int'} }
> >> >  
> >> >  ##
> >> >  # @BlockDeviceIoStatus:
> >> 
> >> BlockDeviceInfo is API, isn't it?
> >
> > Yes.
> >
> >> Note that bs->valid_key currently implies bs->encrypted.  bs->valid_key
> >> && !bs->encrypted is impossible.  Should we make valid_encryption_key
> >> only available when encrypted?
> >
> > I don't think so. It's a bool, so it's ok for it to be false when
> > encrypted is false.
> 
> What bothers me is encrypted=false, valid_encryption_key=true.

Disappearing keys is worse, IMHO (assuming that that situation is impossible
in practice, of course).

> >> valid_encryption_key is a bit long for my taste.  Yours may be
> >> different.
> >
> > We should choose more descriptive and self-documenting names for the
> > protocol. Besides, I can't think of anything shorter that won't get
> > cryptic.
> >
> > Suggestions are always welcome though :)
> 
> valid_encryption_key sounds like the value is the valid key.

That's exactly what it is.

> got_crypt_key?  Also avoids "valid".  Good, because current encrypted
> formats don't actually validate the key; they happily accept any key.

That's a block layer bug, not QMP's.

QMP clients are going to be misguided by valid_encryption_key the same way
they are with the block_passwd command or how we suffer from it internally
when calling bdrv_set_key() (which also manifests itself in HMP).

Fixing the bug where it is will automatically fix all its instances.

> GIGO.  In theory, you can trash a disk that way.  In practice, we can
> hope the guest will refuse to touch the disk, because it can't recognize
> partition table / filesystems.

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

* Re: [Qemu-devel] [PATCH 12/34] hmp: hmp_cont(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-10  8:42       ` Markus Armbruster
@ 2012-08-10 14:22         ` Luiz Capitulino
  2012-08-10 16:37           ` Markus Armbruster
  0 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-10 14:22 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

On Fri, 10 Aug 2012 10:42:23 +0200
Markus Armbruster <armbru@redhat.com> wrote:

> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > On Thu, 02 Aug 2012 13:53:08 +0200
> > Markus Armbruster <armbru@redhat.com> wrote:
> >
> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> 
> >> > This commit changes hmp_cont() to loop through all block devices
> >> > and proactively set an encryption key for any encrypted device
> >> > without a valid one.
> >> >
> >> > This change is needed because QERR_DEVICE_ENCRYPTED is going to be
> >> > dropped by a future commit.
> >> >
> >> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> >> > ---
> >> >  hmp.c | 43 +++++++++++++++++++++++++------------------
> >> >  1 file changed, 25 insertions(+), 18 deletions(-)
> >> >
> >> > diff --git a/hmp.c b/hmp.c
> >> > index 6b72a64..1ebeb63 100644
> >> > --- a/hmp.c
> >> > +++ b/hmp.c
> >> > @@ -610,34 +610,41 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
> >> >  
> >> >  static void hmp_cont_cb(void *opaque, int err)
> >> >  {
> >> > -    Monitor *mon = opaque;
> >> > -
> >> >      if (!err) {
> >> > -        hmp_cont(mon, NULL);
> >> > +        qmp_cont(NULL);
> >> >      }
> >> >  }
> >> >  
> >> > -void hmp_cont(Monitor *mon, const QDict *qdict)
> >> > +static bool blockinfo_is_encrypted(const BlockInfo *bdev)
> >> >  {
> >> > -    Error *errp = NULL;
> >> > -
> >> > -    qmp_cont(&errp);
> >> > -    if (error_is_set(&errp)) {
> >> > -        if (error_is_type(errp, QERR_DEVICE_ENCRYPTED)) {
> >> > -            const char *device;
> >> > +    return (bdev->inserted && bdev->inserted->encrypted);
> >> > +}
> >> >  
> >> > -            /* The device is encrypted. Ask the user for the password
> >> > -               and retry */
> >> > +static bool blockinfo_key_is_set(const BlockInfo *bdev)
> >> > +{
> >> > +    return (bdev->inserted && bdev->inserted->valid_encryption_key);
> >> > +}
> >> >  
> >> > -            device = error_get_field(errp, "device");
> >> > -            assert(device != NULL);
> >> > +void hmp_cont(Monitor *mon, const QDict *qdict)
> >> > +{
> >> > +    BlockInfoList *bdev_list, *bdev;
> >> > +    Error *errp = NULL;
> >> >  
> >> > -            monitor_read_block_device_key(mon, device, hmp_cont_cb, mon);
> >> > -            error_free(errp);
> >> > -            return;
> >> > +    bdev_list = qmp_query_block(NULL);
> >> > +    for (bdev = bdev_list; bdev; bdev = bdev->next) {
> >> > +        if (blockinfo_is_encrypted(bdev->value) &&
> >> > +            !blockinfo_key_is_set(bdev->value)) {
> >> > +                monitor_read_block_device_key(mon, bdev->value->device,
> >> > +                                              hmp_cont_cb, NULL);
> >> > +                goto out;
> >> >          }
> >> > -        hmp_handle_error(mon, &errp);
> >> >      }
> >> > +
> >> > +    qmp_cont(&errp);
> >> > +    hmp_handle_error(mon, &errp);
> >> > +
> >> > +out:
> >> > +    qapi_free_BlockInfoList(bdev_list);
> >> >  }
> >> >  
> >> >  void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
> >> 
> >> Quote my previous analysis:
> >> 
> >> Diff makes this change look worse than it is.  Odd: M-x ediff gets it
> >> right.  Anyway, here's how I think it works:
> >> 
> >> Unchanged qmp_cont(): search the bdrv_states for the first encrypted one
> >> without a key.  If found, set err argument to QERR_DEVICE_ENCRYPTED.
> >> Other errors unrelated to encrypted devices are also possible.
> >> 
> >> hmp_cont() before: try qmp_cont().  If we get QERR_DEVICE_ENCRYPTED,
> >> extract the device from the error object, and prompt for its key, with a
> >> callback that retries hmp_cont() if the key was provided.
> >> 
> >> After: search the bdrv_states for an encrypted one without a key.  If
> >> there is none, qmp_cont(), no special error handling.  If there is one,
> >> prompt for its key, with a callback that runs qmp_cont() if the key was
> >> provided.
> >> 
> >> End quote.
> >> 
> >> Two observations:
> >> 
> >> 1. I don't understand how this works for multiple encrypted BDSs without
> >> keys.  If there are any, hmp_cont() starts reading the first one's key,
> >> then returns.  But the callback doesn't start reading the next one's
> >> key.  Please explain.
> >
> > The callback calls qmp_cont(), which will fail. Then the user will enter
> > cont again, and the loop on BlockInfos will run again and the user will
> > be asked for the password of the next image.
> >
> > IOW, each time cont is issued by the user it will ask for the password
> > of a different device.
> >
> > That's the current behavior, and I believe it was also the behavior before
> > I converted cont to the qapi.
> 
> Ugh.  Clunky even for QEMU standards.
> 
> cont gives no indication that the run state change didn't happen.

Agreed. We should have freedom to change cont's semantics on HMP if we
need/want to in order to fix this.

But that's out of the scope of this series, of course.

> 
> >> 2. qmp_cont() uses bdrv_key_required() to test whether a BDS lacks a
> >> key.  Your new hmp_cont() uses blockinfo_is_encrypted() &&
> >> !blockinfo_key_is_set().  Not obvious that the two are equivalent.
> >> 
> >> I'm afraid they are not.  bdrv_key_required() checks the backing image
> >> first:
> >> 
> >>     int bdrv_key_required(BlockDriverState *bs)
> >>     {
> >>         BlockDriverState *backing_hd = bs->backing_hd;
> >> 
> >>         if (backing_hd && backing_hd->encrypted && !backing_hd->valid_key)
> >>             return 1;
> >>         return (bs->encrypted && !bs->valid_key);
> >>     }
> >> 
> >> Your code doesn't:
> >> 
> >>     static bool blockinfo_is_encrypted(const BlockInfo *bdev)
> >>     {
> >>         return (bdev->inserted && bdev->inserted->encrypted);
> >>     }
> >> 
> >>     static bool blockinfo_key_is_set(const BlockInfo *bdev)
> >>     {
> >>         return (bdev->inserted && bdev->inserted->valid_encryption_key);
> >>     }
> >> 
> >>     BlockInfoList *qmp_query_block(Error **errp)
> >>     {
> >>         BlockInfoList *head = NULL, *cur_item = NULL;
> >>         BlockDriverState *bs;
> >> 
> >>         QTAILQ_FOREACH(bs, &bdrv_states, list) {
> >>             BlockInfoList *info = g_malloc0(sizeof(*info));
> >> [...]
> >>             if (bs->drv) {
> >>                 info->value->has_inserted = true;
> >>                 info->value->inserted = g_malloc0(sizeof(*info->value->inserted));
> >> [...]
> >>                 info->value->inserted->encrypted = bs->encrypted;
> >>                 info->value->inserted->valid_encryption_key = bs->valid_key;
> >> [...]
> >> 
> >> Are you sure this is correct?
> >
> > Is it actually possible for backing_hd to be false and valid_key to be true?
> 
> Yes.  Let's create an encrypted QCOW2 image without backing_file:
> 
>     $ qemu-img create -f qcow2 -o encryption,size=1G foo.qcow2
>     Formatting 'foo.qcow2', fmt=qcow2 size=1073741824 encryption=on cluster_size=65536 lazy_refcounts=off 
>     $ qemu-img info foo.qcow2
>     Disk image 'foo.qcow2' is encrypted.
>     password: 
>     image: foo.qcow2
>     file format: qcow2
>     virtual size: 1.0G (1073741824 bytes)
>     disk size: 136K
>     encrypted: yes
>     cluster_size: 65536
>     $ qemu-system-x86_64 -nodefaults --enable-kvm -S -m 512 -vnc :0 -usb -monitor stdio -drive if=ide,file=foo.qcow2,id=foo
>     QEMU 1.1.50 monitor - type 'help' for more information
>     (qemu) info block
>     foo: removable=0 io-status=ok file=foo.qcow2 ro=0 drv=qcow2 encrypted=1 bps=0 bps_rd=0 bps_wr=0 iops=0 iops_rd=0 iops_wr=0
>     (qemu) c
>     foo (foo.qcow2) is encrypted.
>     Password: 
> 
> Now wrap an unencrypted one around it:
> 
>     $ qemu-img create -f qcow2 -o size=1G,backing_file=foo.qcow2 bar.qcow2
>     Formatting 'bar.qcow2', fmt=qcow2 size=1073741824 backing_file='foo.qcow2' encryption=off cluster_size=65536 lazy_refcounts=off 
>     $ qemu-img info bar.qcow2
>     image: bar.qcow2
>     file format: qcow2
>     virtual size: 1.0G (1073741824 bytes)
>     disk size: 196K
>     cluster_size: 65536
>     backing file: foo.qcow2
>     $ qemu-system-x86_64 -nodefaults --enable-kvm -S -m 512 -vnc :0 -usb -monitor stdio -drive if=ide,file=bar.qcow2,id=foo
>     QEMU 1.1.50 monitor - type 'help' for more information
>     (qemu) c
>     'foo' (foo.qcow2) is encrypted
>     (qemu) 
> 
> Regression :)

Hmm, right. I think this can also be reproduced by passing -snapshot
when using an encrypted image.

> >> I understand we require HMP code to go via QMP for everything, to keep
> >> HMP honest.  This case shows a drawback: duplicated code, leading to
> >> inconsistencies.
> >
> > Keeping DeviceEncrypted would solve this.
> 
> Another way is to replace valid-encryption-key by the predicate that's
> actually wanted: key-required.

Looks good, this would fix the bug above too, right?

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

* Re: [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-10 13:33         ` Luiz Capitulino
@ 2012-08-10 16:35           ` Markus Armbruster
  2012-08-10 17:00             ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Markus Armbruster @ 2012-08-10 16:35 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> On Fri, 10 Aug 2012 09:56:11 +0200
> Markus Armbruster <armbru@redhat.com> wrote:
>
>> Revisited this one on review of v2, replying here for context.
>> 
>> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> 
>> > On Thu, 02 Aug 2012 13:35:54 +0200
>> > Markus Armbruster <armbru@redhat.com> wrote:
>> >
>> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> >> 
>> >> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
>> >> > ---
>> >> >  block.c          | 1 +
>> >> >  qapi-schema.json | 7 +++++--
>> >> >  2 files changed, 6 insertions(+), 2 deletions(-)
>> >> >
>> >> > diff --git a/block.c b/block.c
>> >> > index b38940b..9c113b8 100644
>> >> > --- a/block.c
>> >> > +++ b/block.c
>> >> > @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
>> >> >              info->value->inserted->ro = bs->read_only;
>> >> >              info->value->inserted->drv = g_strdup(bs->drv->format_name);
>> >> >              info->value->inserted->encrypted = bs->encrypted;
>> >> > +            info->value->inserted->valid_encryption_key = bs->valid_key;
>> >> >              if (bs->backing_file[0]) {
>> >> >                  info->value->inserted->has_backing_file = true;
>> >> >                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
>> >> > diff --git a/qapi-schema.json b/qapi-schema.json
>> >> > index bc55ed2..1b2d7f5 100644
>> >> > --- a/qapi-schema.json
>> >> > +++ b/qapi-schema.json
>> >> > @@ -400,6 +400,8 @@
>> >> >  #
>> >> >  # @encrypted: true if the backing device is encrypted
>> >> >  #
>> >> > +# @valid_encryption_key: true if a valid encryption key has been set
>> >> > +#
>> >> >  # @bps: total throughput limit in bytes per second is specified
>> >> >  #
>> >> >  # @bps_rd: read throughput limit in bytes per second is specified
>> >> > @@ -419,8 +421,9 @@
>> >> >  { 'type': 'BlockDeviceInfo',
>> >> >    'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
>> >> >              '*backing_file': 'str', 'encrypted': 'bool',
>> >> > -            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
>> >> > -            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
>> >> > +            'valid_encryption_key': 'bool', 'bps': 'int',
>> >> > +            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
>> >> > +            'iops_rd': 'int', 'iops_wr': 'int'} }
>> >> >  
>> >> >  ##
>> >> >  # @BlockDeviceIoStatus:
>> >> 
>> >> BlockDeviceInfo is API, isn't it?
>> >
>> > Yes.
>> >
>> >> Note that bs->valid_key currently implies bs->encrypted.  bs->valid_key
>> >> && !bs->encrypted is impossible.  Should we make valid_encryption_key
>> >> only available when encrypted?
>> >
>> > I don't think so. It's a bool, so it's ok for it to be false when
>> > encrypted is false.
>> 
>> What bothers me is encrypted=false, valid_encryption_key=true.
>
> Disappearing keys is worse, IMHO (assuming that that situation is impossible
> in practice, of course).

It's fundamentally three states: unencrypted, encrypted-no-key,
encrypted-got-key.  I'm fine with mapping these onto two bools, it's how
the block layer does it.  You may want to consider a single enumeration
instead.

>> >> valid_encryption_key is a bit long for my taste.  Yours may be
>> >> different.
>> >
>> > We should choose more descriptive and self-documenting names for the
>> > protocol. Besides, I can't think of anything shorter that won't get
>> > cryptic.
>> >
>> > Suggestions are always welcome though :)
>> 
>> valid_encryption_key sounds like the value is the valid key.
>
> That's exactly what it is.

Err, isn't the value bool?  The key value is a string...

>> got_crypt_key?  Also avoids "valid".  Good, because current encrypted
>> formats don't actually validate the key; they happily accept any key.
>
> That's a block layer bug, not QMP's.
>
> QMP clients are going to be misguided by valid_encryption_key the same way
> they are with the block_passwd command or how we suffer from it internally
> when calling bdrv_set_key() (which also manifests itself in HMP).
>
> Fixing the bug where it is will automatically fix all its instances.

It's not fixable for existing image formats, and thus existing images.

You could even call it a feature that makes it (marginally) harder to
brute-force keys (I don't buy that argument myself).

>> GIGO.  In theory, you can trash a disk that way.  In practice, we can
>> hope the guest will refuse to touch the disk, because it can't recognize
>> partition table / filesystems.

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

* Re: [Qemu-devel] [PATCH 12/34] hmp: hmp_cont(): don't rely on QERR_DEVICE_ENCRYPTED
  2012-08-10 14:22         ` Luiz Capitulino
@ 2012-08-10 16:37           ` Markus Armbruster
  0 siblings, 0 replies; 85+ messages in thread
From: Markus Armbruster @ 2012-08-10 16:37 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> On Fri, 10 Aug 2012 10:42:23 +0200
> Markus Armbruster <armbru@redhat.com> wrote:
>
>> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> 
>> > On Thu, 02 Aug 2012 13:53:08 +0200
>> > Markus Armbruster <armbru@redhat.com> wrote:
>> >
>> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> >> 
>> >> > This commit changes hmp_cont() to loop through all block devices
>> >> > and proactively set an encryption key for any encrypted device
>> >> > without a valid one.
>> >> >
>> >> > This change is needed because QERR_DEVICE_ENCRYPTED is going to be
>> >> > dropped by a future commit.
>> >> >
>> >> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
>> >> > ---
>> >> >  hmp.c | 43 +++++++++++++++++++++++++------------------
>> >> >  1 file changed, 25 insertions(+), 18 deletions(-)
>> >> >
>> >> > diff --git a/hmp.c b/hmp.c
>> >> > index 6b72a64..1ebeb63 100644
>> >> > --- a/hmp.c
>> >> > +++ b/hmp.c
>> >> > @@ -610,34 +610,41 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
>> >> >  
>> >> >  static void hmp_cont_cb(void *opaque, int err)
>> >> >  {
>> >> > -    Monitor *mon = opaque;
>> >> > -
>> >> >      if (!err) {
>> >> > -        hmp_cont(mon, NULL);
>> >> > +        qmp_cont(NULL);
>> >> >      }
>> >> >  }
>> >> >  
>> >> > -void hmp_cont(Monitor *mon, const QDict *qdict)
>> >> > +static bool blockinfo_is_encrypted(const BlockInfo *bdev)
>> >> >  {
>> >> > -    Error *errp = NULL;
>> >> > -
>> >> > -    qmp_cont(&errp);
>> >> > -    if (error_is_set(&errp)) {
>> >> > -        if (error_is_type(errp, QERR_DEVICE_ENCRYPTED)) {
>> >> > -            const char *device;
>> >> > +    return (bdev->inserted && bdev->inserted->encrypted);
>> >> > +}
>> >> >  
>> >> > -            /* The device is encrypted. Ask the user for the password
>> >> > -               and retry */
>> >> > +static bool blockinfo_key_is_set(const BlockInfo *bdev)
>> >> > +{
>> >> > +    return (bdev->inserted && bdev->inserted->valid_encryption_key);
>> >> > +}
>> >> >  
>> >> > -            device = error_get_field(errp, "device");
>> >> > -            assert(device != NULL);
>> >> > +void hmp_cont(Monitor *mon, const QDict *qdict)
>> >> > +{
>> >> > +    BlockInfoList *bdev_list, *bdev;
>> >> > +    Error *errp = NULL;
>> >> >  
>> >> > -            monitor_read_block_device_key(mon, device, hmp_cont_cb, mon);
>> >> > -            error_free(errp);
>> >> > -            return;
>> >> > +    bdev_list = qmp_query_block(NULL);
>> >> > +    for (bdev = bdev_list; bdev; bdev = bdev->next) {
>> >> > +        if (blockinfo_is_encrypted(bdev->value) &&
>> >> > +            !blockinfo_key_is_set(bdev->value)) {
>> >> > +                monitor_read_block_device_key(mon, bdev->value->device,
>> >> > +                                              hmp_cont_cb, NULL);
>> >> > +                goto out;
>> >> >          }
>> >> > -        hmp_handle_error(mon, &errp);
>> >> >      }
>> >> > +
>> >> > +    qmp_cont(&errp);
>> >> > +    hmp_handle_error(mon, &errp);
>> >> > +
>> >> > +out:
>> >> > +    qapi_free_BlockInfoList(bdev_list);
>> >> >  }
>> >> >  
>> >> >  void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
>> >> 
>> >> Quote my previous analysis:
>> >> 
>> >> Diff makes this change look worse than it is.  Odd: M-x ediff gets it
>> >> right.  Anyway, here's how I think it works:
>> >> 
>> >> Unchanged qmp_cont(): search the bdrv_states for the first encrypted one
>> >> without a key.  If found, set err argument to QERR_DEVICE_ENCRYPTED.
>> >> Other errors unrelated to encrypted devices are also possible.
>> >> 
>> >> hmp_cont() before: try qmp_cont().  If we get QERR_DEVICE_ENCRYPTED,
>> >> extract the device from the error object, and prompt for its key, with a
>> >> callback that retries hmp_cont() if the key was provided.
>> >> 
>> >> After: search the bdrv_states for an encrypted one without a key.  If
>> >> there is none, qmp_cont(), no special error handling.  If there is one,
>> >> prompt for its key, with a callback that runs qmp_cont() if the key was
>> >> provided.
>> >> 
>> >> End quote.
>> >> 
>> >> Two observations:
>> >> 
>> >> 1. I don't understand how this works for multiple encrypted BDSs without
>> >> keys.  If there are any, hmp_cont() starts reading the first one's key,
>> >> then returns.  But the callback doesn't start reading the next one's
>> >> key.  Please explain.
>> >
>> > The callback calls qmp_cont(), which will fail. Then the user will enter
>> > cont again, and the loop on BlockInfos will run again and the user will
>> > be asked for the password of the next image.
>> >
>> > IOW, each time cont is issued by the user it will ask for the password
>> > of a different device.
>> >
>> > That's the current behavior, and I believe it was also the behavior before
>> > I converted cont to the qapi.
>> 
>> Ugh.  Clunky even for QEMU standards.
>> 
>> cont gives no indication that the run state change didn't happen.
>
> Agreed. We should have freedom to change cont's semantics on HMP if we
> need/want to in order to fix this.
>
> But that's out of the scope of this series, of course.

Yup.

>> >> 2. qmp_cont() uses bdrv_key_required() to test whether a BDS lacks a
>> >> key.  Your new hmp_cont() uses blockinfo_is_encrypted() &&
>> >> !blockinfo_key_is_set().  Not obvious that the two are equivalent.
>> >> 
>> >> I'm afraid they are not.  bdrv_key_required() checks the backing image
>> >> first:
>> >> 
>> >>     int bdrv_key_required(BlockDriverState *bs)
>> >>     {
>> >>         BlockDriverState *backing_hd = bs->backing_hd;
>> >> 
>> >>         if (backing_hd && backing_hd->encrypted && !backing_hd->valid_key)
>> >>             return 1;
>> >>         return (bs->encrypted && !bs->valid_key);
>> >>     }
>> >> 
>> >> Your code doesn't:
>> >> 
>> >>     static bool blockinfo_is_encrypted(const BlockInfo *bdev)
>> >>     {
>> >>         return (bdev->inserted && bdev->inserted->encrypted);
>> >>     }
>> >> 
>> >>     static bool blockinfo_key_is_set(const BlockInfo *bdev)
>> >>     {
>> >>         return (bdev->inserted && bdev->inserted->valid_encryption_key);
>> >>     }
>> >> 
>> >>     BlockInfoList *qmp_query_block(Error **errp)
>> >>     {
>> >>         BlockInfoList *head = NULL, *cur_item = NULL;
>> >>         BlockDriverState *bs;
>> >> 
>> >>         QTAILQ_FOREACH(bs, &bdrv_states, list) {
>> >>             BlockInfoList *info = g_malloc0(sizeof(*info));
>> >> [...]
>> >>             if (bs->drv) {
>> >>                 info->value->has_inserted = true;
>> >>                 info->value->inserted = g_malloc0(sizeof(*info->value->inserted));
>> >> [...]
>> >>                 info->value->inserted->encrypted = bs->encrypted;
>> >>                 info->value->inserted->valid_encryption_key = bs->valid_key;
>> >> [...]
>> >> 
>> >> Are you sure this is correct?
>> >
>> > Is it actually possible for backing_hd to be false and valid_key to be true?
>> 
>> Yes.  Let's create an encrypted QCOW2 image without backing_file:
>> 
>>     $ qemu-img create -f qcow2 -o encryption,size=1G foo.qcow2
>>     Formatting 'foo.qcow2', fmt=qcow2 size=1073741824 encryption=on
>> cluster_size=65536 lazy_refcounts=off
>>     $ qemu-img info foo.qcow2
>>     Disk image 'foo.qcow2' is encrypted.
>>     password: 
>>     image: foo.qcow2
>>     file format: qcow2
>>     virtual size: 1.0G (1073741824 bytes)
>>     disk size: 136K
>>     encrypted: yes
>>     cluster_size: 65536
>>     $ qemu-system-x86_64 -nodefaults --enable-kvm -S -m 512 -vnc :0
>> -usb -monitor stdio -drive if=ide,file=foo.qcow2,id=foo
>>     QEMU 1.1.50 monitor - type 'help' for more information
>>     (qemu) info block
>>     foo: removable=0 io-status=ok file=foo.qcow2 ro=0 drv=qcow2
>> encrypted=1 bps=0 bps_rd=0 bps_wr=0 iops=0 iops_rd=0 iops_wr=0
>>     (qemu) c
>>     foo (foo.qcow2) is encrypted.
>>     Password: 
>> 
>> Now wrap an unencrypted one around it:
>> 
>>     $ qemu-img create -f qcow2 -o size=1G,backing_file=foo.qcow2 bar.qcow2
>>     Formatting 'bar.qcow2', fmt=qcow2 size=1073741824
>> backing_file='foo.qcow2' encryption=off cluster_size=65536
>> lazy_refcounts=off
>>     $ qemu-img info bar.qcow2
>>     image: bar.qcow2
>>     file format: qcow2
>>     virtual size: 1.0G (1073741824 bytes)
>>     disk size: 196K
>>     cluster_size: 65536
>>     backing file: foo.qcow2
>>     $ qemu-system-x86_64 -nodefaults --enable-kvm -S -m 512 -vnc :0
>> -usb -monitor stdio -drive if=ide,file=bar.qcow2,id=foo
>>     QEMU 1.1.50 monitor - type 'help' for more information
>>     (qemu) c
>>     'foo' (foo.qcow2) is encrypted
>>     (qemu) 
>> 
>> Regression :)
>
> Hmm, right. I think this can also be reproduced by passing -snapshot
> when using an encrypted image.
>
>> >> I understand we require HMP code to go via QMP for everything, to keep
>> >> HMP honest.  This case shows a drawback: duplicated code, leading to
>> >> inconsistencies.
>> >
>> > Keeping DeviceEncrypted would solve this.
>> 
>> Another way is to replace valid-encryption-key by the predicate that's
>> actually wanted: key-required.
>
> Looks good, this would fix the bug above too, right?

The one I marked "Regression :)"?  Yes, I think it would fix that one.

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

* Re: [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-10 16:35           ` Markus Armbruster
@ 2012-08-10 17:00             ` Luiz Capitulino
  2012-08-10 17:17               ` Markus Armbruster
  0 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-10 17:00 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

On Fri, 10 Aug 2012 18:35:26 +0200
Markus Armbruster <armbru@redhat.com> wrote:

> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > On Fri, 10 Aug 2012 09:56:11 +0200
> > Markus Armbruster <armbru@redhat.com> wrote:
> >
> >> Revisited this one on review of v2, replying here for context.
> >> 
> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> 
> >> > On Thu, 02 Aug 2012 13:35:54 +0200
> >> > Markus Armbruster <armbru@redhat.com> wrote:
> >> >
> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> >> 
> >> >> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> >> >> > ---
> >> >> >  block.c          | 1 +
> >> >> >  qapi-schema.json | 7 +++++--
> >> >> >  2 files changed, 6 insertions(+), 2 deletions(-)
> >> >> >
> >> >> > diff --git a/block.c b/block.c
> >> >> > index b38940b..9c113b8 100644
> >> >> > --- a/block.c
> >> >> > +++ b/block.c
> >> >> > @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
> >> >> >              info->value->inserted->ro = bs->read_only;
> >> >> >              info->value->inserted->drv = g_strdup(bs->drv->format_name);
> >> >> >              info->value->inserted->encrypted = bs->encrypted;
> >> >> > +            info->value->inserted->valid_encryption_key = bs->valid_key;
> >> >> >              if (bs->backing_file[0]) {
> >> >> >                  info->value->inserted->has_backing_file = true;
> >> >> >                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
> >> >> > diff --git a/qapi-schema.json b/qapi-schema.json
> >> >> > index bc55ed2..1b2d7f5 100644
> >> >> > --- a/qapi-schema.json
> >> >> > +++ b/qapi-schema.json
> >> >> > @@ -400,6 +400,8 @@
> >> >> >  #
> >> >> >  # @encrypted: true if the backing device is encrypted
> >> >> >  #
> >> >> > +# @valid_encryption_key: true if a valid encryption key has been set
> >> >> > +#
> >> >> >  # @bps: total throughput limit in bytes per second is specified
> >> >> >  #
> >> >> >  # @bps_rd: read throughput limit in bytes per second is specified
> >> >> > @@ -419,8 +421,9 @@
> >> >> >  { 'type': 'BlockDeviceInfo',
> >> >> >    'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
> >> >> >              '*backing_file': 'str', 'encrypted': 'bool',
> >> >> > -            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
> >> >> > -            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
> >> >> > +            'valid_encryption_key': 'bool', 'bps': 'int',
> >> >> > +            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
> >> >> > +            'iops_rd': 'int', 'iops_wr': 'int'} }
> >> >> >  
> >> >> >  ##
> >> >> >  # @BlockDeviceIoStatus:
> >> >> 
> >> >> BlockDeviceInfo is API, isn't it?
> >> >
> >> > Yes.
> >> >
> >> >> Note that bs->valid_key currently implies bs->encrypted.  bs->valid_key
> >> >> && !bs->encrypted is impossible.  Should we make valid_encryption_key
> >> >> only available when encrypted?
> >> >
> >> > I don't think so. It's a bool, so it's ok for it to be false when
> >> > encrypted is false.
> >> 
> >> What bothers me is encrypted=false, valid_encryption_key=true.
> >
> > Disappearing keys is worse, IMHO (assuming that that situation is impossible
> > in practice, of course).
> 
> It's fundamentally three states: unencrypted, encrypted-no-key,
> encrypted-got-key.  I'm fine with mapping these onto two bools, it's how
> the block layer does it.  You may want to consider a single enumeration
> instead.

That's arguable. But I like the bools slightly better because they allow
clients to do a true/false check vs. having to check against an enum value.

Again, that's arguable.

> >> >> valid_encryption_key is a bit long for my taste.  Yours may be
> >> >> different.
> >> >
> >> > We should choose more descriptive and self-documenting names for the
> >> > protocol. Besides, I can't think of anything shorter that won't get
> >> > cryptic.
> >> >
> >> > Suggestions are always welcome though :)
> >> 
> >> valid_encryption_key sounds like the value is the valid key.
> >
> > That's exactly what it is.
> 
> Err, isn't the value bool?  The key value is a string...

Ah, sorry, I read "sounds like true means the key is valid even for an
invalid key". I've renamed it to encryption_key_missing, should be better
(although I could also do encryption_key_is_missing).

> >> got_crypt_key?  Also avoids "valid".  Good, because current encrypted
> >> formats don't actually validate the key; they happily accept any key.
> >
> > That's a block layer bug, not QMP's.
> >
> > QMP clients are going to be misguided by valid_encryption_key the same way
> > they are with the block_passwd command or how we suffer from it internally
> > when calling bdrv_set_key() (which also manifests itself in HMP).
> >
> > Fixing the bug where it is will automatically fix all its instances.
> 
> It's not fixable for existing image formats, and thus existing images.

Why not? I'd expect that changing AES_set_decrypt_key() to fail for an
invalid key wouldn't affect images, am I wrong?

> You could even call it a feature that makes it (marginally) harder to
> brute-force keys (I don't buy that argument myself).

I don't, either.

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

* Re: [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-10 17:00             ` Luiz Capitulino
@ 2012-08-10 17:17               ` Markus Armbruster
  2012-08-10 17:50                 ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Markus Armbruster @ 2012-08-10 17:17 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> On Fri, 10 Aug 2012 18:35:26 +0200
> Markus Armbruster <armbru@redhat.com> wrote:
>
>> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> 
>> > On Fri, 10 Aug 2012 09:56:11 +0200
>> > Markus Armbruster <armbru@redhat.com> wrote:
>> >
>> >> Revisited this one on review of v2, replying here for context.
>> >> 
>> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> >> 
>> >> > On Thu, 02 Aug 2012 13:35:54 +0200
>> >> > Markus Armbruster <armbru@redhat.com> wrote:
>> >> >
>> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> >> >> 
>> >> >> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
>> >> >> > ---
>> >> >> >  block.c          | 1 +
>> >> >> >  qapi-schema.json | 7 +++++--
>> >> >> >  2 files changed, 6 insertions(+), 2 deletions(-)
>> >> >> >
>> >> >> > diff --git a/block.c b/block.c
>> >> >> > index b38940b..9c113b8 100644
>> >> >> > --- a/block.c
>> >> >> > +++ b/block.c
>> >> >> > @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
>> >> >> >              info->value->inserted->ro = bs->read_only;
>> >> >> >              info->value->inserted->drv = g_strdup(bs->drv->format_name);
>> >> >> >              info->value->inserted->encrypted = bs->encrypted;
>> >> >> > +            info->value->inserted->valid_encryption_key = bs->valid_key;
>> >> >> >              if (bs->backing_file[0]) {
>> >> >> >                  info->value->inserted->has_backing_file = true;
>> >> >> >                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
>> >> >> > diff --git a/qapi-schema.json b/qapi-schema.json
>> >> >> > index bc55ed2..1b2d7f5 100644
>> >> >> > --- a/qapi-schema.json
>> >> >> > +++ b/qapi-schema.json
>> >> >> > @@ -400,6 +400,8 @@
>> >> >> >  #
>> >> >> >  # @encrypted: true if the backing device is encrypted
>> >> >> >  #
>> >> >> > +# @valid_encryption_key: true if a valid encryption key has been set
>> >> >> > +#
>> >> >> >  # @bps: total throughput limit in bytes per second is specified
>> >> >> >  #
>> >> >> >  # @bps_rd: read throughput limit in bytes per second is specified
>> >> >> > @@ -419,8 +421,9 @@
>> >> >> >  { 'type': 'BlockDeviceInfo',
>> >> >> >    'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
>> >> >> >              '*backing_file': 'str', 'encrypted': 'bool',
>> >> >> > -            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
>> >> >> > -            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
>> >> >> > +            'valid_encryption_key': 'bool', 'bps': 'int',
>> >> >> > +            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
>> >> >> > +            'iops_rd': 'int', 'iops_wr': 'int'} }
>> >> >> >  
>> >> >> >  ##
>> >> >> >  # @BlockDeviceIoStatus:
>> >> >> 
>> >> >> BlockDeviceInfo is API, isn't it?
>> >> >
>> >> > Yes.
>> >> >
>> >> >> Note that bs->valid_key currently implies bs->encrypted.  bs->valid_key
>> >> >> && !bs->encrypted is impossible.  Should we make valid_encryption_key
>> >> >> only available when encrypted?
>> >> >
>> >> > I don't think so. It's a bool, so it's ok for it to be false when
>> >> > encrypted is false.
>> >> 
>> >> What bothers me is encrypted=false, valid_encryption_key=true.
>> >
>> > Disappearing keys is worse, IMHO (assuming that that situation is impossible
>> > in practice, of course).
>> 
>> It's fundamentally three states: unencrypted, encrypted-no-key,
>> encrypted-got-key.  I'm fine with mapping these onto two bools, it's how
>> the block layer does it.  You may want to consider a single enumeration
>> instead.
>
> That's arguable. But I like the bools slightly better because they allow
> clients to do a true/false check vs. having to check against an enum value.
>
> Again, that's arguable.
>
>> >> >> valid_encryption_key is a bit long for my taste.  Yours may be
>> >> >> different.
>> >> >
>> >> > We should choose more descriptive and self-documenting names for the
>> >> > protocol. Besides, I can't think of anything shorter that won't get
>> >> > cryptic.
>> >> >
>> >> > Suggestions are always welcome though :)
>> >> 
>> >> valid_encryption_key sounds like the value is the valid key.
>> >
>> > That's exactly what it is.
>> 
>> Err, isn't the value bool?  The key value is a string...
>
> Ah, sorry, I read "sounds like true means the key is valid even for an
> invalid key". I've renamed it to encryption_key_missing, should be better
> (although I could also do encryption_key_is_missing).
>
>> >> got_crypt_key?  Also avoids "valid".  Good, because current encrypted
>> >> formats don't actually validate the key; they happily accept any key.
>> >
>> > That's a block layer bug, not QMP's.
>> >
>> > QMP clients are going to be misguided by valid_encryption_key the same way
>> > they are with the block_passwd command or how we suffer from it internally
>> > when calling bdrv_set_key() (which also manifests itself in HMP).
>> >
>> > Fixing the bug where it is will automatically fix all its instances.
>> 
>> It's not fixable for existing image formats, and thus existing images.
>
> Why not? I'd expect that changing AES_set_decrypt_key() to fail for an
> invalid key wouldn't affect images, am I wrong?

AES_set_decrypt_key() and AES_set_encrypt_key() accept any key with 128,
192 or 256 bits.  Decrypting with an incorrect key simply produces
garbage.  That's what ciphers do.

>> You could even call it a feature that makes it (marginally) harder to
>> brute-force keys (I don't buy that argument myself).
>
> I don't, either.

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

* Re: [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-10 17:17               ` Markus Armbruster
@ 2012-08-10 17:50                 ` Luiz Capitulino
  2012-08-11  7:45                   ` Markus Armbruster
  0 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-10 17:50 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

On Fri, 10 Aug 2012 19:17:22 +0200
Markus Armbruster <armbru@redhat.com> wrote:

> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > On Fri, 10 Aug 2012 18:35:26 +0200
> > Markus Armbruster <armbru@redhat.com> wrote:
> >
> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> 
> >> > On Fri, 10 Aug 2012 09:56:11 +0200
> >> > Markus Armbruster <armbru@redhat.com> wrote:
> >> >
> >> >> Revisited this one on review of v2, replying here for context.
> >> >> 
> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> >> 
> >> >> > On Thu, 02 Aug 2012 13:35:54 +0200
> >> >> > Markus Armbruster <armbru@redhat.com> wrote:
> >> >> >
> >> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> >> >> 
> >> >> >> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> >> >> >> > ---
> >> >> >> >  block.c          | 1 +
> >> >> >> >  qapi-schema.json | 7 +++++--
> >> >> >> >  2 files changed, 6 insertions(+), 2 deletions(-)
> >> >> >> >
> >> >> >> > diff --git a/block.c b/block.c
> >> >> >> > index b38940b..9c113b8 100644
> >> >> >> > --- a/block.c
> >> >> >> > +++ b/block.c
> >> >> >> > @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
> >> >> >> >              info->value->inserted->ro = bs->read_only;
> >> >> >> >              info->value->inserted->drv = g_strdup(bs->drv->format_name);
> >> >> >> >              info->value->inserted->encrypted = bs->encrypted;
> >> >> >> > +            info->value->inserted->valid_encryption_key = bs->valid_key;
> >> >> >> >              if (bs->backing_file[0]) {
> >> >> >> >                  info->value->inserted->has_backing_file = true;
> >> >> >> >                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
> >> >> >> > diff --git a/qapi-schema.json b/qapi-schema.json
> >> >> >> > index bc55ed2..1b2d7f5 100644
> >> >> >> > --- a/qapi-schema.json
> >> >> >> > +++ b/qapi-schema.json
> >> >> >> > @@ -400,6 +400,8 @@
> >> >> >> >  #
> >> >> >> >  # @encrypted: true if the backing device is encrypted
> >> >> >> >  #
> >> >> >> > +# @valid_encryption_key: true if a valid encryption key has been set
> >> >> >> > +#
> >> >> >> >  # @bps: total throughput limit in bytes per second is specified
> >> >> >> >  #
> >> >> >> >  # @bps_rd: read throughput limit in bytes per second is specified
> >> >> >> > @@ -419,8 +421,9 @@
> >> >> >> >  { 'type': 'BlockDeviceInfo',
> >> >> >> >    'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
> >> >> >> >              '*backing_file': 'str', 'encrypted': 'bool',
> >> >> >> > -            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
> >> >> >> > -            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
> >> >> >> > +            'valid_encryption_key': 'bool', 'bps': 'int',
> >> >> >> > +            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
> >> >> >> > +            'iops_rd': 'int', 'iops_wr': 'int'} }
> >> >> >> >  
> >> >> >> >  ##
> >> >> >> >  # @BlockDeviceIoStatus:
> >> >> >> 
> >> >> >> BlockDeviceInfo is API, isn't it?
> >> >> >
> >> >> > Yes.
> >> >> >
> >> >> >> Note that bs->valid_key currently implies bs->encrypted.  bs->valid_key
> >> >> >> && !bs->encrypted is impossible.  Should we make valid_encryption_key
> >> >> >> only available when encrypted?
> >> >> >
> >> >> > I don't think so. It's a bool, so it's ok for it to be false when
> >> >> > encrypted is false.
> >> >> 
> >> >> What bothers me is encrypted=false, valid_encryption_key=true.
> >> >
> >> > Disappearing keys is worse, IMHO (assuming that that situation is impossible
> >> > in practice, of course).
> >> 
> >> It's fundamentally three states: unencrypted, encrypted-no-key,
> >> encrypted-got-key.  I'm fine with mapping these onto two bools, it's how
> >> the block layer does it.  You may want to consider a single enumeration
> >> instead.
> >
> > That's arguable. But I like the bools slightly better because they allow
> > clients to do a true/false check vs. having to check against an enum value.
> >
> > Again, that's arguable.
> >
> >> >> >> valid_encryption_key is a bit long for my taste.  Yours may be
> >> >> >> different.
> >> >> >
> >> >> > We should choose more descriptive and self-documenting names for the
> >> >> > protocol. Besides, I can't think of anything shorter that won't get
> >> >> > cryptic.
> >> >> >
> >> >> > Suggestions are always welcome though :)
> >> >> 
> >> >> valid_encryption_key sounds like the value is the valid key.
> >> >
> >> > That's exactly what it is.
> >> 
> >> Err, isn't the value bool?  The key value is a string...
> >
> > Ah, sorry, I read "sounds like true means the key is valid even for an
> > invalid key". I've renamed it to encryption_key_missing, should be better
> > (although I could also do encryption_key_is_missing).
> >
> >> >> got_crypt_key?  Also avoids "valid".  Good, because current encrypted
> >> >> formats don't actually validate the key; they happily accept any key.
> >> >
> >> > That's a block layer bug, not QMP's.
> >> >
> >> > QMP clients are going to be misguided by valid_encryption_key the same way
> >> > they are with the block_passwd command or how we suffer from it internally
> >> > when calling bdrv_set_key() (which also manifests itself in HMP).
> >> >
> >> > Fixing the bug where it is will automatically fix all its instances.
> >> 
> >> It's not fixable for existing image formats, and thus existing images.
> >
> > Why not? I'd expect that changing AES_set_decrypt_key() to fail for an
> > invalid key wouldn't affect images, am I wrong?
> 
> AES_set_decrypt_key() and AES_set_encrypt_key() accept any key with 128,
> 192 or 256 bits.  Decrypting with an incorrect key simply produces
> garbage.  That's what ciphers do.

(That's not my area of expertise, so hope I won't embarass myself)

But how is ssh or any other software using encryption capable of telling
you that you entered a wrong password? Do they check against known data?

Even if that's the case, any possible fix should be done in the block layer.

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

* Re: [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-10 17:50                 ` Luiz Capitulino
@ 2012-08-11  7:45                   ` Markus Armbruster
  2012-08-13 13:35                     ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Markus Armbruster @ 2012-08-11  7:45 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> On Fri, 10 Aug 2012 19:17:22 +0200
> Markus Armbruster <armbru@redhat.com> wrote:
>
>> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> 
>> > On Fri, 10 Aug 2012 18:35:26 +0200
>> > Markus Armbruster <armbru@redhat.com> wrote:
>> >
>> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> >> 
>> >> > On Fri, 10 Aug 2012 09:56:11 +0200
>> >> > Markus Armbruster <armbru@redhat.com> wrote:
>> >> >
>> >> >> Revisited this one on review of v2, replying here for context.
>> >> >> 
>> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> >> >> 
>> >> >> > On Thu, 02 Aug 2012 13:35:54 +0200
>> >> >> > Markus Armbruster <armbru@redhat.com> wrote:
>> >> >> >
>> >> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> >> >> >> 
>> >> >> >> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
>> >> >> >> > ---
>> >> >> >> >  block.c          | 1 +
>> >> >> >> >  qapi-schema.json | 7 +++++--
>> >> >> >> >  2 files changed, 6 insertions(+), 2 deletions(-)
>> >> >> >> >
>> >> >> >> > diff --git a/block.c b/block.c
>> >> >> >> > index b38940b..9c113b8 100644
>> >> >> >> > --- a/block.c
>> >> >> >> > +++ b/block.c
>> >> >> >> > @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
>> >> >> >> >              info->value->inserted->ro = bs->read_only;
>> >> >> >> >              info->value->inserted->drv = g_strdup(bs->drv->format_name);
>> >> >> >> >              info->value->inserted->encrypted = bs->encrypted;
>> >> >> >> > +            info->value->inserted->valid_encryption_key = bs->valid_key;
>> >> >> >> >              if (bs->backing_file[0]) {
>> >> >> >> >                  info->value->inserted->has_backing_file = true;
>> >> >> >> >                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
>> >> >> >> > diff --git a/qapi-schema.json b/qapi-schema.json
>> >> >> >> > index bc55ed2..1b2d7f5 100644
>> >> >> >> > --- a/qapi-schema.json
>> >> >> >> > +++ b/qapi-schema.json
>> >> >> >> > @@ -400,6 +400,8 @@
>> >> >> >> >  #
>> >> >> >> >  # @encrypted: true if the backing device is encrypted
>> >> >> >> >  #
>> >> >> >> > +# @valid_encryption_key: true if a valid encryption key has been set
>> >> >> >> > +#
>> >> >> >> >  # @bps: total throughput limit in bytes per second is specified
>> >> >> >> >  #
>> >> >> >> >  # @bps_rd: read throughput limit in bytes per second is specified
>> >> >> >> > @@ -419,8 +421,9 @@
>> >> >> >> >  { 'type': 'BlockDeviceInfo',
>> >> >> >> >    'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
>> >> >> >> >              '*backing_file': 'str', 'encrypted': 'bool',
>> >> >> >> > -            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
>> >> >> >> > -            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
>> >> >> >> > +            'valid_encryption_key': 'bool', 'bps': 'int',
>> >> >> >> > +            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
>> >> >> >> > +            'iops_rd': 'int', 'iops_wr': 'int'} }
>> >> >> >> >  
>> >> >> >> >  ##
>> >> >> >> >  # @BlockDeviceIoStatus:
>> >> >> >> 
>> >> >> >> BlockDeviceInfo is API, isn't it?
>> >> >> >
>> >> >> > Yes.
>> >> >> >
>> >> >> >> Note that bs->valid_key currently implies bs->encrypted.
>> >> >> >> bs->valid_key
>> >> >> >> && !bs->encrypted is impossible.  Should we make valid_encryption_key
>> >> >> >> only available when encrypted?
>> >> >> >
>> >> >> > I don't think so. It's a bool, so it's ok for it to be false when
>> >> >> > encrypted is false.
>> >> >> 
>> >> >> What bothers me is encrypted=false, valid_encryption_key=true.
>> >> >
>> >> > Disappearing keys is worse, IMHO (assuming that that situation
>> >> > is impossible
>> >> > in practice, of course).
>> >> 
>> >> It's fundamentally three states: unencrypted, encrypted-no-key,
>> >> encrypted-got-key.  I'm fine with mapping these onto two bools, it's how
>> >> the block layer does it.  You may want to consider a single enumeration
>> >> instead.
>> >
>> > That's arguable. But I like the bools slightly better because they allow
>> > clients to do a true/false check vs. having to check against an enum value.
>> >
>> > Again, that's arguable.
>> >
>> >> >> >> valid_encryption_key is a bit long for my taste.  Yours may be
>> >> >> >> different.
>> >> >> >
>> >> >> > We should choose more descriptive and self-documenting names for the
>> >> >> > protocol. Besides, I can't think of anything shorter that won't get
>> >> >> > cryptic.
>> >> >> >
>> >> >> > Suggestions are always welcome though :)
>> >> >> 
>> >> >> valid_encryption_key sounds like the value is the valid key.
>> >> >
>> >> > That's exactly what it is.
>> >> 
>> >> Err, isn't the value bool?  The key value is a string...
>> >
>> > Ah, sorry, I read "sounds like true means the key is valid even for an
>> > invalid key". I've renamed it to encryption_key_missing, should be better
>> > (although I could also do encryption_key_is_missing).
>> >
>> >> >> got_crypt_key?  Also avoids "valid".  Good, because current encrypted
>> >> >> formats don't actually validate the key; they happily accept any key.
>> >> >
>> >> > That's a block layer bug, not QMP's.
>> >> >
>> >> > QMP clients are going to be misguided by valid_encryption_key
>> >> > the same way
>> >> > they are with the block_passwd command or how we suffer from it
>> >> > internally
>> >> > when calling bdrv_set_key() (which also manifests itself in HMP).
>> >> >
>> >> > Fixing the bug where it is will automatically fix all its instances.
>> >> 
>> >> It's not fixable for existing image formats, and thus existing images.
>> >
>> > Why not? I'd expect that changing AES_set_decrypt_key() to fail for an
>> > invalid key wouldn't affect images, am I wrong?
>> 
>> AES_set_decrypt_key() and AES_set_encrypt_key() accept any key with 128,
>> 192 or 256 bits.  Decrypting with an incorrect key simply produces
>> garbage.  That's what ciphers do.
>
> (That's not my area of expertise, so hope I won't embarass myself)
>
> But how is ssh or any other software using encryption capable of telling
> you that you entered a wrong password? Do they check against known data?

SSH password authentication boils down to the remote's password
authentication, with the communication channel secured against
eavesdroppers.

More relevant: if you secure your private SSH key with a passphrase,
it's stored encrypted.  I don't know how exactly SSH determines that a
passphrase is correct.  A plausible guess is it encrypts (key,h(key)).
Decrypt, split into key and checksum, compare h(key) to checksum.

> Even if that's the case, any possible fix should be done in the block layer.

It's not fixable there.  Which makes it a feature.

Best we could do is extend QCOW2 so that invalid keys can be rejected.
Will work only with new QCOW2 driver and new images.

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

* Re: [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-11  7:45                   ` Markus Armbruster
@ 2012-08-13 13:35                     ` Luiz Capitulino
  2012-08-13 13:50                       ` Markus Armbruster
  0 siblings, 1 reply; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-13 13:35 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

On Sat, 11 Aug 2012 09:45:14 +0200
Markus Armbruster <armbru@redhat.com> wrote:

> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > On Fri, 10 Aug 2012 19:17:22 +0200
> > Markus Armbruster <armbru@redhat.com> wrote:
> >
> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> 
> >> > On Fri, 10 Aug 2012 18:35:26 +0200
> >> > Markus Armbruster <armbru@redhat.com> wrote:
> >> >
> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> >> 
> >> >> > On Fri, 10 Aug 2012 09:56:11 +0200
> >> >> > Markus Armbruster <armbru@redhat.com> wrote:
> >> >> >
> >> >> >> Revisited this one on review of v2, replying here for context.
> >> >> >> 
> >> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> >> >> 
> >> >> >> > On Thu, 02 Aug 2012 13:35:54 +0200
> >> >> >> > Markus Armbruster <armbru@redhat.com> wrote:
> >> >> >> >
> >> >> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> >> >> >> 
> >> >> >> >> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> >> >> >> >> > ---
> >> >> >> >> >  block.c          | 1 +
> >> >> >> >> >  qapi-schema.json | 7 +++++--
> >> >> >> >> >  2 files changed, 6 insertions(+), 2 deletions(-)
> >> >> >> >> >
> >> >> >> >> > diff --git a/block.c b/block.c
> >> >> >> >> > index b38940b..9c113b8 100644
> >> >> >> >> > --- a/block.c
> >> >> >> >> > +++ b/block.c
> >> >> >> >> > @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
> >> >> >> >> >              info->value->inserted->ro = bs->read_only;
> >> >> >> >> >              info->value->inserted->drv = g_strdup(bs->drv->format_name);
> >> >> >> >> >              info->value->inserted->encrypted = bs->encrypted;
> >> >> >> >> > +            info->value->inserted->valid_encryption_key = bs->valid_key;
> >> >> >> >> >              if (bs->backing_file[0]) {
> >> >> >> >> >                  info->value->inserted->has_backing_file = true;
> >> >> >> >> >                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
> >> >> >> >> > diff --git a/qapi-schema.json b/qapi-schema.json
> >> >> >> >> > index bc55ed2..1b2d7f5 100644
> >> >> >> >> > --- a/qapi-schema.json
> >> >> >> >> > +++ b/qapi-schema.json
> >> >> >> >> > @@ -400,6 +400,8 @@
> >> >> >> >> >  #
> >> >> >> >> >  # @encrypted: true if the backing device is encrypted
> >> >> >> >> >  #
> >> >> >> >> > +# @valid_encryption_key: true if a valid encryption key has been set
> >> >> >> >> > +#
> >> >> >> >> >  # @bps: total throughput limit in bytes per second is specified
> >> >> >> >> >  #
> >> >> >> >> >  # @bps_rd: read throughput limit in bytes per second is specified
> >> >> >> >> > @@ -419,8 +421,9 @@
> >> >> >> >> >  { 'type': 'BlockDeviceInfo',
> >> >> >> >> >    'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
> >> >> >> >> >              '*backing_file': 'str', 'encrypted': 'bool',
> >> >> >> >> > -            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
> >> >> >> >> > -            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
> >> >> >> >> > +            'valid_encryption_key': 'bool', 'bps': 'int',
> >> >> >> >> > +            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
> >> >> >> >> > +            'iops_rd': 'int', 'iops_wr': 'int'} }
> >> >> >> >> >  
> >> >> >> >> >  ##
> >> >> >> >> >  # @BlockDeviceIoStatus:
> >> >> >> >> 
> >> >> >> >> BlockDeviceInfo is API, isn't it?
> >> >> >> >
> >> >> >> > Yes.
> >> >> >> >
> >> >> >> >> Note that bs->valid_key currently implies bs->encrypted.
> >> >> >> >> bs->valid_key
> >> >> >> >> && !bs->encrypted is impossible.  Should we make valid_encryption_key
> >> >> >> >> only available when encrypted?
> >> >> >> >
> >> >> >> > I don't think so. It's a bool, so it's ok for it to be false when
> >> >> >> > encrypted is false.
> >> >> >> 
> >> >> >> What bothers me is encrypted=false, valid_encryption_key=true.
> >> >> >
> >> >> > Disappearing keys is worse, IMHO (assuming that that situation
> >> >> > is impossible
> >> >> > in practice, of course).
> >> >> 
> >> >> It's fundamentally three states: unencrypted, encrypted-no-key,
> >> >> encrypted-got-key.  I'm fine with mapping these onto two bools, it's how
> >> >> the block layer does it.  You may want to consider a single enumeration
> >> >> instead.
> >> >
> >> > That's arguable. But I like the bools slightly better because they allow
> >> > clients to do a true/false check vs. having to check against an enum value.
> >> >
> >> > Again, that's arguable.
> >> >
> >> >> >> >> valid_encryption_key is a bit long for my taste.  Yours may be
> >> >> >> >> different.
> >> >> >> >
> >> >> >> > We should choose more descriptive and self-documenting names for the
> >> >> >> > protocol. Besides, I can't think of anything shorter that won't get
> >> >> >> > cryptic.
> >> >> >> >
> >> >> >> > Suggestions are always welcome though :)
> >> >> >> 
> >> >> >> valid_encryption_key sounds like the value is the valid key.
> >> >> >
> >> >> > That's exactly what it is.
> >> >> 
> >> >> Err, isn't the value bool?  The key value is a string...
> >> >
> >> > Ah, sorry, I read "sounds like true means the key is valid even for an
> >> > invalid key". I've renamed it to encryption_key_missing, should be better
> >> > (although I could also do encryption_key_is_missing).
> >> >
> >> >> >> got_crypt_key?  Also avoids "valid".  Good, because current encrypted
> >> >> >> formats don't actually validate the key; they happily accept any key.
> >> >> >
> >> >> > That's a block layer bug, not QMP's.
> >> >> >
> >> >> > QMP clients are going to be misguided by valid_encryption_key
> >> >> > the same way
> >> >> > they are with the block_passwd command or how we suffer from it
> >> >> > internally
> >> >> > when calling bdrv_set_key() (which also manifests itself in HMP).
> >> >> >
> >> >> > Fixing the bug where it is will automatically fix all its instances.
> >> >> 
> >> >> It's not fixable for existing image formats, and thus existing images.
> >> >
> >> > Why not? I'd expect that changing AES_set_decrypt_key() to fail for an
> >> > invalid key wouldn't affect images, am I wrong?
> >> 
> >> AES_set_decrypt_key() and AES_set_encrypt_key() accept any key with 128,
> >> 192 or 256 bits.  Decrypting with an incorrect key simply produces
> >> garbage.  That's what ciphers do.
> >
> > (That's not my area of expertise, so hope I won't embarass myself)
> >
> > But how is ssh or any other software using encryption capable of telling
> > you that you entered a wrong password? Do they check against known data?
> 
> SSH password authentication boils down to the remote's password
> authentication, with the communication channel secured against
> eavesdroppers.
> 
> More relevant: if you secure your private SSH key with a passphrase,
> it's stored encrypted.  I don't know how exactly SSH determines that a
> passphrase is correct.  A plausible guess is it encrypts (key,h(key)).
> Decrypt, split into key and checksum, compare h(key) to checksum.
> 
> > Even if that's the case, any possible fix should be done in the block layer.
> 
> It's not fixable there.  Which makes it a feature.
> 
> Best we could do is extend QCOW2 so that invalid keys can be rejected.
> Will work only with new QCOW2 driver and new images.

It's fixable in the block layer then :)

It can be acceptable to have workarounds in QMP if a severe issue is found
with current images, but this bug exists for ages and nobody has complained
so far. So, I'd go for the Right fix.

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

* Re: [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-13 13:35                     ` Luiz Capitulino
@ 2012-08-13 13:50                       ` Markus Armbruster
  2012-08-13 14:02                         ` Luiz Capitulino
  0 siblings, 1 reply; 85+ messages in thread
From: Markus Armbruster @ 2012-08-13 13:50 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

Luiz Capitulino <lcapitulino@redhat.com> writes:

> On Sat, 11 Aug 2012 09:45:14 +0200
> Markus Armbruster <armbru@redhat.com> wrote:
>
>> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> 
>> > On Fri, 10 Aug 2012 19:17:22 +0200
>> > Markus Armbruster <armbru@redhat.com> wrote:
>> >
>> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> >> 
>> >> > On Fri, 10 Aug 2012 18:35:26 +0200
>> >> > Markus Armbruster <armbru@redhat.com> wrote:
>> >> >
>> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> >> >> 
>> >> >> > On Fri, 10 Aug 2012 09:56:11 +0200
>> >> >> > Markus Armbruster <armbru@redhat.com> wrote:
>> >> >> >
>> >> >> >> Revisited this one on review of v2, replying here for context.
>> >> >> >> 
>> >> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> >> >> >> 
>> >> >> >> > On Thu, 02 Aug 2012 13:35:54 +0200
>> >> >> >> > Markus Armbruster <armbru@redhat.com> wrote:
>> >> >> >> >
>> >> >> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
>> >> >> >> >> 
>> >> >> >> >> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
>> >> >> >> >> > ---
>> >> >> >> >> >  block.c          | 1 +
>> >> >> >> >> >  qapi-schema.json | 7 +++++--
>> >> >> >> >> >  2 files changed, 6 insertions(+), 2 deletions(-)
>> >> >> >> >> >
>> >> >> >> >> > diff --git a/block.c b/block.c
>> >> >> >> >> > index b38940b..9c113b8 100644
>> >> >> >> >> > --- a/block.c
>> >> >> >> >> > +++ b/block.c
>> >> >> >> >> > @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
>> >> >> >> >> >              info->value->inserted->ro = bs->read_only;
>> >> >> >> >> >              info->value->inserted->drv = g_strdup(bs->drv->format_name);
>> >> >> >> >> >              info->value->inserted->encrypted = bs->encrypted;
>> >> >> >> >> > +            info->value->inserted->valid_encryption_key = bs->valid_key;
>> >> >> >> >> >              if (bs->backing_file[0]) {
>> >> >> >> >> >                  info->value->inserted->has_backing_file = true;
>> >> >> >> >> >                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
>> >> >> >> >> > diff --git a/qapi-schema.json b/qapi-schema.json
>> >> >> >> >> > index bc55ed2..1b2d7f5 100644
>> >> >> >> >> > --- a/qapi-schema.json
>> >> >> >> >> > +++ b/qapi-schema.json
>> >> >> >> >> > @@ -400,6 +400,8 @@
>> >> >> >> >> >  #
>> >> >> >> >> >  # @encrypted: true if the backing device is encrypted
>> >> >> >> >> >  #
>> >> >> >> >> > +# @valid_encryption_key: true if a valid encryption key has been set
>> >> >> >> >> > +#
>> >> >> >> >> >  # @bps: total throughput limit in bytes per second is specified
>> >> >> >> >> >  #
>> >> >> >> >> >  # @bps_rd: read throughput limit in bytes per second is specified
>> >> >> >> >> > @@ -419,8 +421,9 @@
>> >> >> >> >> >  { 'type': 'BlockDeviceInfo',
>> >> >> >> >> >    'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
>> >> >> >> >> >              '*backing_file': 'str', 'encrypted': 'bool',
>> >> >> >> >> > -            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
>> >> >> >> >> > -            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
>> >> >> >> >> > +            'valid_encryption_key': 'bool', 'bps': 'int',
>> >> >> >> >> > +            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
>> >> >> >> >> > +            'iops_rd': 'int', 'iops_wr': 'int'} }
>> >> >> >> >> >  
>> >> >> >> >> >  ##
>> >> >> >> >> >  # @BlockDeviceIoStatus:
>> >> >> >> >> 
>> >> >> >> >> BlockDeviceInfo is API, isn't it?
>> >> >> >> >
>> >> >> >> > Yes.
>> >> >> >> >
>> >> >> >> >> Note that bs->valid_key currently implies bs->encrypted.
>> >> >> >> >> bs->valid_key
>> >> >> >> >> && !bs->encrypted is impossible.  Should we make
>> >> >> >> >> valid_encryption_key
>> >> >> >> >> only available when encrypted?
>> >> >> >> >
>> >> >> >> > I don't think so. It's a bool, so it's ok for it to be false when
>> >> >> >> > encrypted is false.
>> >> >> >> 
>> >> >> >> What bothers me is encrypted=false, valid_encryption_key=true.
>> >> >> >
>> >> >> > Disappearing keys is worse, IMHO (assuming that that situation
>> >> >> > is impossible
>> >> >> > in practice, of course).
>> >> >> 
>> >> >> It's fundamentally three states: unencrypted, encrypted-no-key,
>> >> >> encrypted-got-key.  I'm fine with mapping these onto two bools, it's how
>> >> >> the block layer does it.  You may want to consider a single enumeration
>> >> >> instead.
>> >> >
>> >> > That's arguable. But I like the bools slightly better because they allow
>> >> > clients to do a true/false check vs. having to check against an
>> >> > enum value.
>> >> >
>> >> > Again, that's arguable.
>> >> >
>> >> >> >> >> valid_encryption_key is a bit long for my taste.  Yours may be
>> >> >> >> >> different.
>> >> >> >> >
>> >> >> >> > We should choose more descriptive and self-documenting
>> >> >> >> > names for the
>> >> >> >> > protocol. Besides, I can't think of anything shorter that won't get
>> >> >> >> > cryptic.
>> >> >> >> >
>> >> >> >> > Suggestions are always welcome though :)
>> >> >> >> 
>> >> >> >> valid_encryption_key sounds like the value is the valid key.
>> >> >> >
>> >> >> > That's exactly what it is.
>> >> >> 
>> >> >> Err, isn't the value bool?  The key value is a string...
>> >> >
>> >> > Ah, sorry, I read "sounds like true means the key is valid even for an
>> >> > invalid key". I've renamed it to encryption_key_missing, should be better
>> >> > (although I could also do encryption_key_is_missing).
>> >> >
>> >> >> >> got_crypt_key?  Also avoids "valid".  Good, because current encrypted
>> >> >> >> formats don't actually validate the key; they happily accept any key.
>> >> >> >
>> >> >> > That's a block layer bug, not QMP's.
>> >> >> >
>> >> >> > QMP clients are going to be misguided by valid_encryption_key
>> >> >> > the same way
>> >> >> > they are with the block_passwd command or how we suffer from it
>> >> >> > internally
>> >> >> > when calling bdrv_set_key() (which also manifests itself in HMP).
>> >> >> >
>> >> >> > Fixing the bug where it is will automatically fix all its instances.
>> >> >> 
>> >> >> It's not fixable for existing image formats, and thus existing images.
>> >> >
>> >> > Why not? I'd expect that changing AES_set_decrypt_key() to fail for an
>> >> > invalid key wouldn't affect images, am I wrong?
>> >> 
>> >> AES_set_decrypt_key() and AES_set_encrypt_key() accept any key with 128,
>> >> 192 or 256 bits.  Decrypting with an incorrect key simply produces
>> >> garbage.  That's what ciphers do.
>> >
>> > (That's not my area of expertise, so hope I won't embarass myself)
>> >
>> > But how is ssh or any other software using encryption capable of telling
>> > you that you entered a wrong password? Do they check against known data?
>> 
>> SSH password authentication boils down to the remote's password
>> authentication, with the communication channel secured against
>> eavesdroppers.
>> 
>> More relevant: if you secure your private SSH key with a passphrase,
>> it's stored encrypted.  I don't know how exactly SSH determines that a
>> passphrase is correct.  A plausible guess is it encrypts (key,h(key)).
>> Decrypt, split into key and checksum, compare h(key) to checksum.
>> 
>> > Even if that's the case, any possible fix should be done in the block layer.
>> 
>> It's not fixable there.  Which makes it a feature.
>> 
>> Best we could do is extend QCOW2 so that invalid keys can be rejected.
>> Will work only with new QCOW2 driver and new images.
>
> It's fixable in the block layer then :)

I'd rather not debate the meaning of "fixable".  All I'm saying is that
the case "we got a key, and it may or may not be the right one" won't go
away, and thus calling the thing valid_encryption_key will remain
misleading.

> It can be acceptable to have workarounds in QMP if a severe issue is found
> with current images, but this bug exists for ages and nobody has complained
> so far. So, I'd go for the Right fix.

We can't fix it for old images, only for new ones.

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

* Re: [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field
  2012-08-13 13:50                       ` Markus Armbruster
@ 2012-08-13 14:02                         ` Luiz Capitulino
  0 siblings, 0 replies; 85+ messages in thread
From: Luiz Capitulino @ 2012-08-13 14:02 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: kwolf, aliguori, qemu-devel, mdroth, pbonzini, eblake

On Mon, 13 Aug 2012 15:50:13 +0200
Markus Armbruster <armbru@redhat.com> wrote:

> Luiz Capitulino <lcapitulino@redhat.com> writes:
> 
> > On Sat, 11 Aug 2012 09:45:14 +0200
> > Markus Armbruster <armbru@redhat.com> wrote:
> >
> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> 
> >> > On Fri, 10 Aug 2012 19:17:22 +0200
> >> > Markus Armbruster <armbru@redhat.com> wrote:
> >> >
> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> >> 
> >> >> > On Fri, 10 Aug 2012 18:35:26 +0200
> >> >> > Markus Armbruster <armbru@redhat.com> wrote:
> >> >> >
> >> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> >> >> 
> >> >> >> > On Fri, 10 Aug 2012 09:56:11 +0200
> >> >> >> > Markus Armbruster <armbru@redhat.com> wrote:
> >> >> >> >
> >> >> >> >> Revisited this one on review of v2, replying here for context.
> >> >> >> >> 
> >> >> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> >> >> >> 
> >> >> >> >> > On Thu, 02 Aug 2012 13:35:54 +0200
> >> >> >> >> > Markus Armbruster <armbru@redhat.com> wrote:
> >> >> >> >> >
> >> >> >> >> >> Luiz Capitulino <lcapitulino@redhat.com> writes:
> >> >> >> >> >> 
> >> >> >> >> >> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> >> >> >> >> >> > ---
> >> >> >> >> >> >  block.c          | 1 +
> >> >> >> >> >> >  qapi-schema.json | 7 +++++--
> >> >> >> >> >> >  2 files changed, 6 insertions(+), 2 deletions(-)
> >> >> >> >> >> >
> >> >> >> >> >> > diff --git a/block.c b/block.c
> >> >> >> >> >> > index b38940b..9c113b8 100644
> >> >> >> >> >> > --- a/block.c
> >> >> >> >> >> > +++ b/block.c
> >> >> >> >> >> > @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
> >> >> >> >> >> >              info->value->inserted->ro = bs->read_only;
> >> >> >> >> >> >              info->value->inserted->drv = g_strdup(bs->drv->format_name);
> >> >> >> >> >> >              info->value->inserted->encrypted = bs->encrypted;
> >> >> >> >> >> > +            info->value->inserted->valid_encryption_key = bs->valid_key;
> >> >> >> >> >> >              if (bs->backing_file[0]) {
> >> >> >> >> >> >                  info->value->inserted->has_backing_file = true;
> >> >> >> >> >> >                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
> >> >> >> >> >> > diff --git a/qapi-schema.json b/qapi-schema.json
> >> >> >> >> >> > index bc55ed2..1b2d7f5 100644
> >> >> >> >> >> > --- a/qapi-schema.json
> >> >> >> >> >> > +++ b/qapi-schema.json
> >> >> >> >> >> > @@ -400,6 +400,8 @@
> >> >> >> >> >> >  #
> >> >> >> >> >> >  # @encrypted: true if the backing device is encrypted
> >> >> >> >> >> >  #
> >> >> >> >> >> > +# @valid_encryption_key: true if a valid encryption key has been set
> >> >> >> >> >> > +#
> >> >> >> >> >> >  # @bps: total throughput limit in bytes per second is specified
> >> >> >> >> >> >  #
> >> >> >> >> >> >  # @bps_rd: read throughput limit in bytes per second is specified
> >> >> >> >> >> > @@ -419,8 +421,9 @@
> >> >> >> >> >> >  { 'type': 'BlockDeviceInfo',
> >> >> >> >> >> >    'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
> >> >> >> >> >> >              '*backing_file': 'str', 'encrypted': 'bool',
> >> >> >> >> >> > -            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
> >> >> >> >> >> > -            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
> >> >> >> >> >> > +            'valid_encryption_key': 'bool', 'bps': 'int',
> >> >> >> >> >> > +            'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int',
> >> >> >> >> >> > +            'iops_rd': 'int', 'iops_wr': 'int'} }
> >> >> >> >> >> >  
> >> >> >> >> >> >  ##
> >> >> >> >> >> >  # @BlockDeviceIoStatus:
> >> >> >> >> >> 
> >> >> >> >> >> BlockDeviceInfo is API, isn't it?
> >> >> >> >> >
> >> >> >> >> > Yes.
> >> >> >> >> >
> >> >> >> >> >> Note that bs->valid_key currently implies bs->encrypted.
> >> >> >> >> >> bs->valid_key
> >> >> >> >> >> && !bs->encrypted is impossible.  Should we make
> >> >> >> >> >> valid_encryption_key
> >> >> >> >> >> only available when encrypted?
> >> >> >> >> >
> >> >> >> >> > I don't think so. It's a bool, so it's ok for it to be false when
> >> >> >> >> > encrypted is false.
> >> >> >> >> 
> >> >> >> >> What bothers me is encrypted=false, valid_encryption_key=true.
> >> >> >> >
> >> >> >> > Disappearing keys is worse, IMHO (assuming that that situation
> >> >> >> > is impossible
> >> >> >> > in practice, of course).
> >> >> >> 
> >> >> >> It's fundamentally three states: unencrypted, encrypted-no-key,
> >> >> >> encrypted-got-key.  I'm fine with mapping these onto two bools, it's how
> >> >> >> the block layer does it.  You may want to consider a single enumeration
> >> >> >> instead.
> >> >> >
> >> >> > That's arguable. But I like the bools slightly better because they allow
> >> >> > clients to do a true/false check vs. having to check against an
> >> >> > enum value.
> >> >> >
> >> >> > Again, that's arguable.
> >> >> >
> >> >> >> >> >> valid_encryption_key is a bit long for my taste.  Yours may be
> >> >> >> >> >> different.
> >> >> >> >> >
> >> >> >> >> > We should choose more descriptive and self-documenting
> >> >> >> >> > names for the
> >> >> >> >> > protocol. Besides, I can't think of anything shorter that won't get
> >> >> >> >> > cryptic.
> >> >> >> >> >
> >> >> >> >> > Suggestions are always welcome though :)
> >> >> >> >> 
> >> >> >> >> valid_encryption_key sounds like the value is the valid key.
> >> >> >> >
> >> >> >> > That's exactly what it is.
> >> >> >> 
> >> >> >> Err, isn't the value bool?  The key value is a string...
> >> >> >
> >> >> > Ah, sorry, I read "sounds like true means the key is valid even for an
> >> >> > invalid key". I've renamed it to encryption_key_missing, should be better
> >> >> > (although I could also do encryption_key_is_missing).
> >> >> >
> >> >> >> >> got_crypt_key?  Also avoids "valid".  Good, because current encrypted
> >> >> >> >> formats don't actually validate the key; they happily accept any key.
> >> >> >> >
> >> >> >> > That's a block layer bug, not QMP's.
> >> >> >> >
> >> >> >> > QMP clients are going to be misguided by valid_encryption_key
> >> >> >> > the same way
> >> >> >> > they are with the block_passwd command or how we suffer from it
> >> >> >> > internally
> >> >> >> > when calling bdrv_set_key() (which also manifests itself in HMP).
> >> >> >> >
> >> >> >> > Fixing the bug where it is will automatically fix all its instances.
> >> >> >> 
> >> >> >> It's not fixable for existing image formats, and thus existing images.
> >> >> >
> >> >> > Why not? I'd expect that changing AES_set_decrypt_key() to fail for an
> >> >> > invalid key wouldn't affect images, am I wrong?
> >> >> 
> >> >> AES_set_decrypt_key() and AES_set_encrypt_key() accept any key with 128,
> >> >> 192 or 256 bits.  Decrypting with an incorrect key simply produces
> >> >> garbage.  That's what ciphers do.
> >> >
> >> > (That's not my area of expertise, so hope I won't embarass myself)
> >> >
> >> > But how is ssh or any other software using encryption capable of telling
> >> > you that you entered a wrong password? Do they check against known data?
> >> 
> >> SSH password authentication boils down to the remote's password
> >> authentication, with the communication channel secured against
> >> eavesdroppers.
> >> 
> >> More relevant: if you secure your private SSH key with a passphrase,
> >> it's stored encrypted.  I don't know how exactly SSH determines that a
> >> passphrase is correct.  A plausible guess is it encrypts (key,h(key)).
> >> Decrypt, split into key and checksum, compare h(key) to checksum.
> >> 
> >> > Even if that's the case, any possible fix should be done in the block layer.
> >> 
> >> It's not fixable there.  Which makes it a feature.
> >> 
> >> Best we could do is extend QCOW2 so that invalid keys can be rejected.
> >> Will work only with new QCOW2 driver and new images.
> >
> > It's fixable in the block layer then :)
> 
> I'd rather not debate the meaning of "fixable".  All I'm saying is that
> the case "we got a key, and it may or may not be the right one" won't go
> away, and thus calling the thing valid_encryption_key will remain
> misleading.

It's not called valid_encryption_key anymore, so there's no point discussing
this anymore (unless I'm missing something and there are other points to
be discussed).

> > It can be acceptable to have workarounds in QMP if a severe issue is found
> > with current images, but this bug exists for ages and nobody has complained
> > so far. So, I'd go for the Right fix.
> 
> We can't fix it for old images, only for new ones.

Yes, what I'm saying is: let's go for the right fix (for new images) and only
add workarounds (for existing images) if really required.

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

end of thread, other threads:[~2012-08-13 14:02 UTC | newest]

Thread overview: 85+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-02  1:02 [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 01/34] monitor: drop unused monitor debug code Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 02/34] qerror: QERR_AMBIGUOUS_PATH: drop %(object) from human msg Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 03/34] qerror: QERR_DEVICE_ENCRYPTED: add filename info to " Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 04/34] qerror: reduce public exposure Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 05/34] qerror: drop qerror_abort() Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 06/34] qerror: avoid passing qerr pointer Luiz Capitulino
2012-08-02 11:23   ` Markus Armbruster
2012-08-02 13:44     ` Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 07/34] qerror: QError: drop file, linenr, func Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 08/34] qerror: qerror_format(): return an allocated string Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 09/34] qerror: don't delay error message construction Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 10/34] error: " Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 11/34] qmp: query-block: add 'valid_encryption_key' field Luiz Capitulino
2012-08-02 11:35   ` Markus Armbruster
2012-08-02 13:54     ` Luiz Capitulino
2012-08-10  7:56       ` Markus Armbruster
2012-08-10 13:33         ` Luiz Capitulino
2012-08-10 16:35           ` Markus Armbruster
2012-08-10 17:00             ` Luiz Capitulino
2012-08-10 17:17               ` Markus Armbruster
2012-08-10 17:50                 ` Luiz Capitulino
2012-08-11  7:45                   ` Markus Armbruster
2012-08-13 13:35                     ` Luiz Capitulino
2012-08-13 13:50                       ` Markus Armbruster
2012-08-13 14:02                         ` Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 12/34] hmp: hmp_cont(): don't rely on QERR_DEVICE_ENCRYPTED Luiz Capitulino
2012-08-02 11:53   ` Markus Armbruster
2012-08-02 14:22     ` Luiz Capitulino
2012-08-10  8:42       ` Markus Armbruster
2012-08-10 14:22         ` Luiz Capitulino
2012-08-10 16:37           ` Markus Armbruster
2012-08-02  1:02 ` [Qemu-devel] [PATCH 13/34] hmp: hmp_change(): " Luiz Capitulino
2012-08-02 13:27   ` Markus Armbruster
2012-08-02 13:46     ` Paolo Bonzini
2012-08-02 13:53       ` Markus Armbruster
2012-08-02 13:57         ` Paolo Bonzini
2012-08-02 14:53           ` Luiz Capitulino
2012-08-02 14:51       ` Luiz Capitulino
2012-08-02 14:42     ` Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 14/34] net: inet_connect(), inet_connect_opts(): add in_progress argument Luiz Capitulino
2012-08-02 15:12   ` Markus Armbruster
2012-08-02  1:02 ` [Qemu-devel] [PATCH 15/34] net: inet_connect(), inet_connect_opts(): return -errno Luiz Capitulino
2012-08-02 13:41   ` Luiz Capitulino
2012-08-02 15:50     ` Markus Armbruster
2012-08-02 16:49       ` Luiz Capitulino
2012-08-06  6:52       ` Amos Kong
2012-08-06 19:59         ` Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 16/34] migration: don't rely on QERR_SOCKET_* Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 17/34] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS Luiz Capitulino
2012-08-02 15:58   ` Markus Armbruster
2012-08-06  7:04     ` Amos Kong
2012-08-02 16:54   ` Michael Roth
2012-08-02 17:08     ` Luiz Capitulino
2012-08-03 18:26       ` Michael Roth
2012-08-03 20:31         ` Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 18/34] error: drop unused functions Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 19/34] block: block_int: include qerror.h Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 20/34] hmp: hmp.h: include qdict.h Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 21/34] qapi: qapi-types.h: don't include qapi/qapi-types-core.h Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 22/34] qapi: generate correct enum names for camel case enums Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 23/34] qapi: don't convert enum strings to lowercase Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 24/34] qapi-schema: add ErrorClass enum Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 25/34] qerror: qerror_table: don't use C99 struct initializers Luiz Capitulino
2012-08-02 16:48   ` Markus Armbruster
2012-08-02  1:02 ` [Qemu-devel] [PATCH 26/34] error, qerror: add ErrorClass argument to error functions Luiz Capitulino
2012-08-02 16:57   ` Markus Armbruster
2012-08-02  1:02 ` [Qemu-devel] [PATCH 27/34] qerror: add proper ErrorClass value for QERR_ macros Luiz Capitulino
2012-08-02 17:01   ` Markus Armbruster
2012-08-02  1:02 ` [Qemu-devel] [PATCH 28/34] error: add error_get_class() Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 29/34] qmp: switch to the new error format on the wire Luiz Capitulino
2012-08-02 17:12   ` Markus Armbruster
2012-08-02 17:19     ` Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 30/34] qemu-ga: " Luiz Capitulino
2012-08-03 17:44   ` Michael Roth
2012-08-03 17:56     ` Eric Blake
2012-08-03 18:02       ` Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 31/34] error, qerror: pass desc string to error calls Luiz Capitulino
2012-08-02 17:19   ` Markus Armbruster
2012-08-02  1:02 ` [Qemu-devel] [PATCH 32/34] qerror: drop qerror_table and qerror_format() Luiz Capitulino
2012-08-02  1:02 ` [Qemu-devel] [PATCH 33/34] error: drop error_get_qobject()/error_set_qobject() Luiz Capitulino
2012-08-02 17:20   ` Markus Armbruster
2012-08-02  1:02 ` [Qemu-devel] [PATCH 34/34] error, qerror: drop QDict member Luiz Capitulino
2012-08-02 13:41 ` [Qemu-devel] [PATCH v1 00/34]: add new error format Luiz Capitulino
2012-08-02 17:22 ` Markus Armbruster

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).