[Qemu-devel] [PATCH] json-parser: don't replicate tokens at each level of recursion

2012-08-10 Thread Michael Roth
Currently, when parsing a stream of tokens we make a copy of the token
list at the beginning of each level of recursion so that we do not
modify the original list in cases where we need to fall back to an
earlier state.

In the worst case, we will only read 1 or 2 tokens off the list before
recursing again, which means an upper bound of roughly N^2 token allocations.

For a "reasonably" sized QMP request (in this a QMP representation of
cirrus_vga's device state, generated via QIDL, being passed in via
qom-set), this caused my 16GB's of memory to be exhausted before any
noticeable progress was made by the parser. The command is here for
reference, and can be issued against upstream QMP to reproduce (failure
occurs before any qmp command routing/execution):

http://pastebin.com/mJrZ3Ctg

This patch works around the issue by using single copy of the token list
in the form of an indexable array so that we can save/restore state by
manipulating indices. With this patch applied the above QMP/JSON request
can be parsed in under a second.

Tested with valgrind, make check, and QMP.

Signed-off-by: Michael Roth 
---
 json-parser.c |  234 +++--
 1 file changed, 146 insertions(+), 88 deletions(-)

diff --git a/json-parser.c b/json-parser.c
index 849e215..b4e6a60 100644
--- a/json-parser.c
+++ b/json-parser.c
@@ -27,6 +27,11 @@
 typedef struct JSONParserContext
 {
 Error *err;
+struct {
+QObject **buf;
+size_t pos;
+size_t count;
+} tokens;
 } JSONParserContext;
 
 #define BUG_ON(cond) assert(!(cond))
@@ -40,7 +45,7 @@ typedef struct JSONParserContext
  * 4) deal with premature EOI
  */
 
-static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list 
*ap);
+static QObject *parse_value(JSONParserContext *ctxt, va_list *ap);
 
 /**
  * Token manipulators
@@ -270,27 +275,115 @@ out:
 return NULL;
 }
 
+static QObject *parser_context_pop_token(JSONParserContext *ctxt)
+{
+QObject *token;
+g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+token = ctxt->tokens.buf[ctxt->tokens.pos];
+ctxt->tokens.pos++;
+return token;
+}
+
+/* Note: parser_context_{peek|pop}_token do not increment the
+ * token object's refcount. In both cases the references will continue
+ * to be * tracked and cleanup in parser_context_free()
+ */
+static QObject *parser_context_peek_token(JSONParserContext *ctxt)
+{
+QObject *token;
+g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+token = ctxt->tokens.buf[ctxt->tokens.pos];
+return token;
+}
+
+static JSONParserContext parser_context_save(JSONParserContext *ctxt)
+{
+JSONParserContext saved_ctxt;
+saved_ctxt.tokens.pos = ctxt->tokens.pos;
+saved_ctxt.tokens.count = ctxt->tokens.count;
+saved_ctxt.tokens.buf = ctxt->tokens.buf;
+return saved_ctxt;
+}
+
+static void parser_context_restore(JSONParserContext *ctxt,
+   JSONParserContext saved_ctxt)
+{
+ctxt->tokens.pos = saved_ctxt.tokens.pos;
+ctxt->tokens.count = saved_ctxt.tokens.count;
+ctxt->tokens.buf = saved_ctxt.tokens.buf;
+}
+
+static void tokens_count_from_iter(QObject *obj, void *opaque)
+{
+size_t *count = opaque;
+(*count)++;
+}
+
+static void tokens_append_from_iter(QObject *obj, void *opaque)
+{
+JSONParserContext *ctxt = opaque;
+g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+ctxt->tokens.buf[ctxt->tokens.pos++] = obj;
+qobject_incref(obj);
+}
+
+static JSONParserContext *parser_context_new(QList *tokens)
+{
+JSONParserContext *ctxt;
+size_t count = 0;
+
+if (!tokens) {
+return NULL;
+}
+
+qlist_iter(tokens, tokens_count_from_iter, &count);
+if (count == 0) {
+return NULL;
+}
+
+ctxt = g_malloc0(sizeof(JSONParserContext));
+ctxt->tokens.pos = 0;
+ctxt->tokens.count = count;
+ctxt->tokens.buf = g_malloc(count * sizeof(QObject *));
+qlist_iter(tokens, tokens_append_from_iter, ctxt);
+ctxt->tokens.pos = 0;
+
+return ctxt;
+}
+
+static void parser_context_free(JSONParserContext *ctxt)
+{
+int i;
+if (ctxt) {
+for (i = 0; i < ctxt->tokens.count; i++) {
+qobject_decref(ctxt->tokens.buf[i]);
+}
+g_free(ctxt->tokens.buf);
+g_free(ctxt);
+}
+}
+
 /**
  * Parsing rules
  */
-static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, 
va_list *ap)
+static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
 {
 QObject *key = NULL, *token = NULL, *value, *peek;
-QList *working = qlist_copy(*tokens);
+JSONParserContext saved_ctxt = parser_context_save(ctxt);
 
-peek = qlist_peek(working);
+peek = parser_context_peek_token(ctxt);
 if (peek == NULL) {
 parse_error(ctxt, NULL, "premature EOI");
 g

Re: [Qemu-devel] [PATCH] json-parser: don't replicate tokens at each level of recursion

2012-08-13 Thread Michael Roth
On Mon, Aug 13, 2012 at 03:01:56PM -0300, Luiz Capitulino wrote:
> On Fri, 10 Aug 2012 18:24:10 -0500
> Michael Roth  wrote:
> 
> > Currently, when parsing a stream of tokens we make a copy of the token
> > list at the beginning of each level of recursion so that we do not
> > modify the original list in cases where we need to fall back to an
> > earlier state.
> > 
> > In the worst case, we will only read 1 or 2 tokens off the list before
> > recursing again, which means an upper bound of roughly N^2 token 
> > allocations.
> > 
> > For a "reasonably" sized QMP request (in this a QMP representation of
> > cirrus_vga's device state, generated via QIDL, being passed in via
> > qom-set), this caused my 16GB's of memory to be exhausted before any
> > noticeable progress was made by the parser. The command is here for
> > reference, and can be issued against upstream QMP to reproduce (failure
> > occurs before any qmp command routing/execution):
> > 
> > http://pastebin.com/mJrZ3Ctg
> > 
> > This patch works around the issue by using single copy of the token list
> > in the form of an indexable array so that we can save/restore state by
> > manipulating indices. With this patch applied the above QMP/JSON request
> > can be parsed in under a second.
> 
> Approach looks sane to me, a few review comments below.
> 
> Anthony, could you provide your reviewed-by please?
> 
> > 
> > Tested with valgrind, make check, and QMP.
> > 
> > Signed-off-by: Michael Roth 
> > ---
> >  json-parser.c |  234 
> > +++--
> >  1 file changed, 146 insertions(+), 88 deletions(-)
> > 
> > diff --git a/json-parser.c b/json-parser.c
> > index 849e215..b4e6a60 100644
> > --- a/json-parser.c
> > +++ b/json-parser.c
> > @@ -27,6 +27,11 @@
> >  typedef struct JSONParserContext
> >  {
> >  Error *err;
> > +struct {
> > +QObject **buf;
> > +size_t pos;
> > +size_t count;
> > +} tokens;
> >  } JSONParserContext;
> >  
> >  #define BUG_ON(cond) assert(!(cond))
> > @@ -40,7 +45,7 @@ typedef struct JSONParserContext
> >   * 4) deal with premature EOI
> >   */
> >  
> > -static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, 
> > va_list *ap);
> > +static QObject *parse_value(JSONParserContext *ctxt, va_list *ap);
> >  
> >  /**
> >   * Token manipulators
> > @@ -270,27 +275,115 @@ out:
> >  return NULL;
> >  }
> >  
> > +static QObject *parser_context_pop_token(JSONParserContext *ctxt)
> > +{
> > +QObject *token;
> > +g_assert(ctxt->tokens.pos < ctxt->tokens.count);
> > +token = ctxt->tokens.buf[ctxt->tokens.pos];
> > +ctxt->tokens.pos++;
> > +return token;
> > +}
> > +
> > +/* Note: parser_context_{peek|pop}_token do not increment the
> > + * token object's refcount. In both cases the references will continue
> > + * to be * tracked and cleanup in parser_context_free()
> > + */
> > +static QObject *parser_context_peek_token(JSONParserContext *ctxt)
> > +{
> > +QObject *token;
> > +g_assert(ctxt->tokens.pos < ctxt->tokens.count);
> > +token = ctxt->tokens.buf[ctxt->tokens.pos];
> > +return token;
> > +}
> > +
> > +static JSONParserContext parser_context_save(JSONParserContext *ctxt)
> > +{
> > +JSONParserContext saved_ctxt;
> > +saved_ctxt.tokens.pos = ctxt->tokens.pos;
> > +saved_ctxt.tokens.count = ctxt->tokens.count;
> > +saved_ctxt.tokens.buf = ctxt->tokens.buf;
> 
> Shouldn't saved_ctxt.err be initialized to NULL?
> 

Yes.

> > +return saved_ctxt;
> 
> I was going to say that saved_ctxt had to be static, but then I realized
> this will end up copying the struct to the caller.
> 

Yah, every caller needs to manage it's own context, so I went with
passing by copy since allocating/deallocating these "half-contexts" (we
only care about token state with these) seems unecessary.
seemed

> > +}
> > +
> > +static void parser_context_restore(JSONParserContext *ctxt,
> > +   JSONParserContext saved_ctxt)
> > +{
> > +ctxt->tokens.pos = saved_ctxt.tokens.pos;
> > +ctxt->tokens.count = saved_ctxt.tokens.count;
> > +ctxt->tokens.buf = saved_ctxt.tokens.buf;
> > +}
> > +
> > +static void tokens_count_from_iter(QObject *obj, 

Re: [Qemu-devel] [PATCH] json-parser: don't replicate tokens at each level of recursion

2012-08-13 Thread Michael Roth
On Mon, Aug 13, 2012 at 08:49:26PM +0200, Markus Armbruster wrote:
> Michael Roth  writes:
> 
> > Currently, when parsing a stream of tokens we make a copy of the token
> > list at the beginning of each level of recursion so that we do not
> > modify the original list in cases where we need to fall back to an
> > earlier state.
> >
> > In the worst case, we will only read 1 or 2 tokens off the list before
> > recursing again, which means an upper bound of roughly N^2 token 
> > allocations.
> >
> > For a "reasonably" sized QMP request (in this a QMP representation of
> > cirrus_vga's device state, generated via QIDL, being passed in via
> > qom-set), this caused my 16GB's of memory to be exhausted before any
> > noticeable progress was made by the parser. The command is here for
> > reference, and can be issued against upstream QMP to reproduce (failure
> > occurs before any qmp command routing/execution):
> >
> > http://pastebin.com/mJrZ3Ctg
> 
> Commit messages are forever, pastebins aren't.
> 
> What about preserving your test case for eternity under tests/?

We might be able to generate some json objects that cause the behavior and add
them to check-qjson.

> 
> [...]
> 



[Qemu-devel] Add infrastructure for supporting QIDL annotations

2012-08-14 Thread Michael Roth
These patches are based are origin/master, and can also be obtained from:

git://github.com/mdroth/qemu.git qidl-base

This is a cleanup of the infrastructure bits from
"[RFC v2] Use QEMU IDL for device serialization/introspection".

I know this is pretty late into the release cycle, but the patches in
this series have gotten decent review, and I have a seperate branch (qidl-conv1
in my github repo) that uses these bits to serialize i440fx, piix3/piix ide,
usb, cirrus_vga, and a few others via QIDL. So there shouldn't be too much
churn going forward.

Changes since rfc v2:

 - Parser/Codegen fix-ups for cases encountered converting piix ide and usb.
 - Fixed license headers.
 - Stricter arg-checking for QIDL macros when passing to codegen.
 - Added asserts to detect mis-use of QIDL property/visitor interfaces.
 - Renamed QAPI visit_*_array interfaces to visit_*_carray to clarify that
   these are serialization routines for single-dimension C arrays.




[Qemu-devel] [PATCH 11/20] qapi: qapi.py, make json parser more robust

2012-08-14 Thread Michael Roth
Currently the QAPI JSON parser expects a very particular style of code
indentation, the major one being that terminating curly/square brackets are
not on placed on a seperate line. This is incompatible with most
pretty-print formats, so make it a little more robust by supporting
these cases.

Signed-off-by: Michael Roth 
---
 scripts/qapi.py |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index a347203..47cd672 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -81,7 +81,7 @@ def parse_schema(fp):
 if line.startswith('#') or line == '\n':
 continue
 
-if line.startswith(' '):
+if line[0] in ['}', ']', ' ', '\t']:
 expr += line
 elif expr:
 expr_eval = evaluate(expr)
-- 
1.7.9.5




[Qemu-devel] [PATCH 13/20] qom-fuse: workaround for truncated properties > 4096

2012-08-14 Thread Michael Roth
We currently hard-code property size at 4096 for the purposes of
getattr()/stat()/etc. For 'state' properties we can exceed this easily,
leading to truncated responses.

Instead, for a particular property, make it
max(4096, most_recent_property_size * 2). This allows some
head-room for properties that change size periodically (numbers,
strings, state properties containing arrays, etc)

Also, implement a simple property cache to avoid spinning on qom-get
if an application reads beyond the actual size. This also allows us
to use a snapshot of a single qom-get that persists across read()'s.
Old Cache entries are evicted as soon as we attempt to read() from
offset 0 again.

Reviewed-by: Anthony Liguori 
Signed-off-by: Michael Roth 
---
 QMP/qom-fuse |   24 +---
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/QMP/qom-fuse b/QMP/qom-fuse
index 5c6754a..bd43f29 100755
--- a/QMP/qom-fuse
+++ b/QMP/qom-fuse
@@ -26,6 +26,7 @@ class QOMFS(Fuse):
 self.qmp.connect()
 self.ino_map = {}
 self.ino_count = 1
+self.prop_cache = {}
 
 def get_ino(self, path):
 if self.ino_map.has_key(path):
@@ -67,12 +68,16 @@ class QOMFS(Fuse):
 if not self.is_property(path):
 return -ENOENT
 
-path, prop = path.rsplit('/', 1)
-try:
-data = str(self.qmp.command('qom-get', path=path, property=prop))
-data += '\n' # make values shell friendly
-except:
-return -EPERM
+# avoid extra calls to qom-get by using cached value when offset > 0
+if offset == 0 or not self.prop_cache.has_key(path):
+directory, prop = path.rsplit('/', 1)
+try:
+resp = str(self.qmp.command('qom-get', path=directory, 
property=prop))
+self.prop_cache[path] = resp + '\n' # make values shell 
friendly
+except:
+return -EPERM
+
+data = self.prop_cache[path]
 
 if offset > len(data):
 return ''
@@ -111,13 +116,18 @@ class QOMFS(Fuse):
0,
0))
 elif self.is_property(path):
+directory, prop = path.rsplit('/', 1)
+try:
+resp = str(self.qmp.command('qom-get', path=directory, 
property=prop))
+except:
+return -ENOENT
 value = posix.stat_result((0644 | stat.S_IFREG,
self.get_ino(path),
0,
1,
1000,
1000,
-   4096,
+   max(len(resp) * 2, 4096),
0,
0,
0))
-- 
1.7.9.5




[Qemu-devel] [PATCH 05/20] qapi: qapi_visit.py, support arrays and complex qapi definitions

2012-08-14 Thread Michael Roth
Add support for arrays in the code generators.

Complex field descriptions can now be used to provide additional
information to the visitor generators, such as the max size of an array,
or the field within a struct to use to determine how many elements are
present in the array to avoid serializing uninitialized elements.

Add handling for these in the code generators as well.

Reviewed-by: Anthony Liguori 
Signed-off-by: Michael Roth 
---
 scripts/qapi.py  |8 --
 scripts/qapi_commands.py |8 +++---
 scripts/qapi_types.py|2 +-
 scripts/qapi_visit.py|   64 +-
 4 files changed, 68 insertions(+), 14 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 122b4cb..a347203 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -110,12 +110,16 @@ def parse_args(typeinfo):
 argentry = typeinfo[member]
 optional = False
 structured = False
+annotated = False
 if member.startswith('*'):
 argname = member[1:]
 optional = True
 if isinstance(argentry, OrderedDict):
-structured = True
-yield (argname, argentry, optional, structured)
+if argentry.has_key(''):
+annotated = True
+else:
+structured = True
+yield (argname, argentry, optional, structured, annotated)
 
 def de_camel_case(name):
 new_name = ''
diff --git a/scripts/qapi_commands.py b/scripts/qapi_commands.py
index 3c4678d..a2e0c23 100644
--- a/scripts/qapi_commands.py
+++ b/scripts/qapi_commands.py
@@ -32,7 +32,7 @@ void %(visitor)s(Visitor *m, %(name)s * obj, const char 
*name, Error **errp);
 
 def generate_command_decl(name, args, ret_type):
 arglist=""
-for argname, argtype, optional, structured in parse_args(args):
+for argname, argtype, optional, structured, annotated in parse_args(args):
 argtype = c_type(argtype)
 if argtype == "char *":
 argtype = "const char *"
@@ -50,7 +50,7 @@ def gen_sync_call(name, args, ret_type, indent=0):
 retval=""
 if ret_type:
 retval = "retval = "
-for argname, argtype, optional, structured in parse_args(args):
+for argname, argtype, optional, structured, annotated in parse_args(args):
 if optional:
 arglist += "has_%s, " % c_var(argname)
 arglist += "%s, " % (c_var(argname))
@@ -106,7 +106,7 @@ Visitor *v;
 def gen_visitor_input_vars_decl(args):
 ret = ""
 push_indent()
-for argname, argtype, optional, structured in parse_args(args):
+for argname, argtype, optional, structured, annotated in parse_args(args):
 if optional:
 ret += mcgen('''
 bool has_%(argname)s = false;
@@ -145,7 +145,7 @@ v = qmp_input_get_visitor(mi);
 ''',
  obj=obj)
 
-for argname, argtype, optional, structured in parse_args(args):
+for argname, argtype, optional, structured, annotated in parse_args(args):
 if optional:
 ret += mcgen('''
 visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
diff --git a/scripts/qapi_types.py b/scripts/qapi_types.py
index cf601ae..8babfe1 100644
--- a/scripts/qapi_types.py
+++ b/scripts/qapi_types.py
@@ -35,7 +35,7 @@ struct %(name)s
 ''',
   name=structname)
 
-for argname, argentry, optional, structured in parse_args(members):
+for argname, argentry, optional, structured, annotated in 
parse_args(members):
 if optional:
 ret += mcgen('''
 bool has_%(c_name)s;
diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
index 25707f5..aac2172 100644
--- a/scripts/qapi_visit.py
+++ b/scripts/qapi_visit.py
@@ -16,6 +16,52 @@ import sys
 import os
 import getopt
 import errno
+import types
+
+def generate_visit_carray_body(name, info):
+if info['array_size'][0].isdigit():
+array_size = info['array_size']
+elif info['array_size'][0] == '(' and info['array_size'][-1] == ')':
+array_size = info['array_size']
+else:
+array_size = "(*obj)->%s" % info['array_size']
+
+if info.has_key('array_capacity'):
+array_capacity = info['array_capacity']
+else:
+array_capacity = array_size
+
+if camel_case(de_camel_case(info['type'][0])) == info['type'][0]:
+ret = mcgen('''
+visit_start_carray(m, (void **)obj, "%(name)s", %(array_capacity)s, 
sizeof(%(type)s), errp);
+int %(name)s_i;
+for (%(name)s_i = 0; %(name)s_i < %(array_size)s; %(name)s_i++) {
+%(type)s %(name)s_ptr = &(*obj)->%(name)s[%(name)s_i];
+visit_type_%(type_short)s(m, &%(na

[Qemu-devel] [PATCH 04/20] qapi: qapi_visit.py, make code useable as module

2012-08-14 Thread Michael Roth
Reviewed-by: Anthony Liguori 
Signed-off-by: Michael Roth 
---
 scripts/qapi_visit.py |  143 +
 1 file changed, 74 insertions(+), 69 deletions(-)

diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
index 04ef7c4..25707f5 100644
--- a/scripts/qapi_visit.py
+++ b/scripts/qapi_visit.py
@@ -224,55 +224,57 @@ void visit_type_%(name)s(Visitor *m, %(name)s * obj, 
const char *name, Error **e
 ''',
 name=name)
 
-try:
-opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
-   ["source", "header", "prefix=", 
"output-dir="])
-except getopt.GetoptError, err:
-print str(err)
-sys.exit(1)
-
-output_dir = ""
-prefix = ""
-c_file = 'qapi-visit.c'
-h_file = 'qapi-visit.h'
-
-do_c = False
-do_h = False
-
-for o, a in opts:
-if o in ("-p", "--prefix"):
-prefix = a
-elif o in ("-o", "--output-dir"):
-output_dir = a + "/"
-elif o in ("-c", "--source"):
+def main(argv=[]):
+try:
+opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
+   ["source", "header", "prefix=",
+"output-dir="])
+except getopt.GetoptError, err:
+print str(err)
+sys.exit(1)
+
+output_dir = ""
+prefix = ""
+c_file = 'qapi-visit.c'
+h_file = 'qapi-visit.h'
+
+do_c = False
+do_h = False
+
+for o, a in opts:
+if o in ("-p", "--prefix"):
+prefix = a
+elif o in ("-o", "--output-dir"):
+output_dir = a + "/"
+elif o in ("-c", "--source"):
+do_c = True
+elif o in ("-h", "--header"):
+do_h = True
+
+if not do_c and not do_h:
 do_c = True
-elif o in ("-h", "--header"):
 do_h = True
 
-if not do_c and not do_h:
-do_c = True
-do_h = True
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
 
-c_file = output_dir + prefix + c_file
-h_file = output_dir + prefix + h_file
+try:
+os.makedirs(output_dir)
+except os.error, e:
+if e.errno != errno.EEXIST:
+raise
 
-try:
-os.makedirs(output_dir)
-except os.error, e:
-if e.errno != errno.EEXIST:
-raise
-
-def maybe_open(really, name, opt):
-if really:
-return open(name, opt)
-else:
-import StringIO
-return StringIO.StringIO()
+def maybe_open(really, name, opt):
+if really:
+return open(name, opt)
+else:
+import StringIO
+return StringIO.StringIO()
 
-fdef = maybe_open(do_c, c_file, 'w')
-fdecl = maybe_open(do_h, h_file, 'w')
+fdef = maybe_open(do_c, c_file, 'w')
+fdecl = maybe_open(do_h, h_file, 'w')
 
-fdef.write(mcgen('''
+fdef.write(mcgen('''
 /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
 
 /*
@@ -292,7 +294,7 @@ fdef.write(mcgen('''
 ''',
  header=basename(h_file)))
 
-fdecl.write(mcgen('''
+fdecl.write(mcgen('''
 /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
 
 /*
@@ -316,37 +318,40 @@ fdecl.write(mcgen('''
 ''',
   prefix=prefix, guard=guardname(h_file)))
 
-exprs = parse_schema(sys.stdin)
+exprs = parse_schema(sys.stdin)
 
-for expr in exprs:
-if expr.has_key('type'):
-ret = generate_visit_struct(expr['type'], expr['data'])
-ret += generate_visit_list(expr['type'], expr['data'])
-fdef.write(ret)
+for expr in exprs:
+if expr.has_key('type'):
+ret = generate_visit_struct(expr['type'], expr['data'])
+ret += generate_visit_list(expr['type'], expr['data'])
+fdef.write(ret)
 
-ret = generate_declaration(expr['type'], expr['data'])
-fdecl.write(ret)
-elif expr.has_key('union'):
-ret = generate_visit_union(expr['union'], expr['data'])
-ret += generate_visit_list(expr['union'], expr['data'])
-fdef.write(ret)
+ret = generate_declaration(expr['type'], expr['data'])
+fdecl.write(ret)
+elif expr.has_key('union'):
+ret = generate_visit_union(expr['union'], expr['data'])
+ret

[Qemu-devel] [PATCH 17/20] qidl: parser, initial import from qc.git

2012-08-14 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 scripts/qidl_parser.py |  512 
 1 file changed, 512 insertions(+)
 create mode 100644 scripts/qidl_parser.py

diff --git a/scripts/qidl_parser.py b/scripts/qidl_parser.py
new file mode 100644
index 000..831b3f5
--- /dev/null
+++ b/scripts/qidl_parser.py
@@ -0,0 +1,512 @@
+#
+# QEMU IDL Parser
+#
+# Copyright IBM, Corp. 2012
+#
+# Authors:
+#  Anthony Liguori 
+#  Michael Roth
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING file in the top-level directory.
+#
+# The lexer code is based off of:
+#   http://www.lysator.liu.se/c/ANSI-C-grammar-l.html
+
+import sys, json
+
+class Input(object):
+def __init__(self, text):
+self.fp = text
+self.buf = text
+self.eof = False
+
+def pop(self):
+if len(self.buf) == 0:
+self.eof = True
+return ''
+ch = self.buf[0]
+self.buf = self.buf[1:]
+return ch
+
+def in_range(ch, start, end):
+if ch >= start and ch <= end:
+return True
+return False
+
+# D[0-9]
+# L[a-zA-Z_]
+# H[a-fA-F0-9]
+# E[Ee][+-]?{D}+
+# FS   (f|F|l|L)
+# IS   (u|U|l|L)*
+
+def is_D(ch):
+return in_range(ch, '0', '9')
+
+def is_L(ch):
+return in_range(ch, 'a', 'z') or in_range(ch, 'A', 'Z') or ch == '_'
+
+def is_H(ch):
+return in_range(ch, 'a', 'f') or in_range(ch, 'A', 'F') or is_D(ch)
+
+def is_FS(ch):
+return ch in 'fFlL'
+
+def is_IS(ch):
+return ch in 'uUlL'
+
+def lexer(fp):
+ch = fp.pop()
+
+while not fp.eof:
+token = ''
+
+if is_L(ch):
+token += ch
+
+ch = fp.pop()
+while is_L(ch) or is_D(ch):
+token += ch
+ch = fp.pop()
+if token in [ 'auto', 'break', 'case', 'const', 'continue',
+   'default', 'do', 'else', 'enum', 'extern',
+   'for', 'goto', 'if', 'register', 'return', 'signed',
+   'sizeof',
+   'static', 'struct', 'typedef', 'union', 'unsigned',
+   'volatile', 'while' ]:
+yield (token, token)
+else:
+yield ('symbol', token)
+elif ch == "'":
+token += ch
+
+ch = fp.pop()
+if ch == '\\':
+token += ch
+token += fp.pop()
+else:
+token += ch
+token += fp.pop()
+ch = fp.pop()
+yield ('literal', token)
+elif ch == '"':
+token += ch
+
+ch = fp.pop()
+while ch not in ['', '"']:
+token += ch
+if ch == '\\':
+token += fp.pop()
+ch = fp.pop()
+token += ch
+yield ('literal', token)
+ch = fp.pop()
+elif ch in '.><+-*/%&^|!;{},:=()[]~?':
+token += ch
+ch = fp.pop()
+tmp_token = token + ch
+if tmp_token in ['<:']:
+yield ('operator', '[')
+ch = fp.pop()
+elif tmp_token in [':>']:
+yield ('operator', ']')
+ch = fp.pop()
+elif tmp_token in ['<%']:
+yield ('operator', '{')
+ch = fp.pop()
+elif tmp_token in ['%>']:
+yield ('operator', '}')
+ch = fp.pop()
+elif tmp_token == '//':
+token = tmp_token
+ch = fp.pop()
+while ch != '\n' and ch != '':
+token += ch
+ch = fp.pop()
+yield ('comment', token)
+elif tmp_token == '/*':
+token = tmp_token
+
+ch = fp.pop()
+while True:
+while ch != '*':
+token += ch
+ch = fp.pop()
+token += ch
+ch = fp.pop()
+if ch == '/':
+to

[Qemu-devel] [PATCH 19/20] qidl: qidl.h, definitions for qidl annotations

2012-08-14 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 qidl.h |   63 +++
 1 file changed, 63 insertions(+)
 create mode 100644 qidl.h

diff --git a/qidl.h b/qidl.h
new file mode 100644
index 000..210f4c6
--- /dev/null
+++ b/qidl.h
@@ -0,0 +1,63 @@
+/*
+ * QEMU IDL Macros/stubs
+ *
+ * See docs/qidl.txt for usage information.
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Michael Roth
+ *
+ * This work is licensed under the terms of the GNU GPLv2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QIDL_H
+#define QIDL_H
+
+#include 
+#include "qapi/qapi-visit-core.h"
+#include "qemu/object.h"
+#include "hw/qdev-properties.h"
+
+#ifdef QIDL_GEN
+
+/* we pass the code through the preprocessor with QIDL_GEN defined to parse
+ * structures as they'd appear after preprocessing, and use the following
+ * definitions mostly to re-insert the initial macros/annotations so they
+ * stick around for the parser to process
+ */
+#define QIDL(...) QIDL(__VA_ARGS__)
+#define QIDL_START(name, ...) QIDL_START(name, ##__VA_ARGS__)
+#define QIDL_END(name) QIDL_END(name)
+
+#define QIDL_VISIT_TYPE(name, v, s, f, e)
+#define QIDL_SCHEMA_ADD_LINK(name, obj, path, errp)
+#define QIDL_PROPERTIES(name)
+
+#else /* !QIDL_GEN */
+
+#define QIDL(...)
+#define QIDL_START(name, ...)
+#define QIDL_END(name) \
+static struct { \
+void (*visitor)(Visitor *, struct name **, const char *, Error **); \
+const char *schema_json_text; \
+Object *schema_obj; \
+Property *properties; \
+} qidl_data_##name;
+
+#define QIDL_VISIT_TYPE(name, v, s, f, e) \
+g_assert(qidl_data_##name.visitor); \
+qidl_data_##name.visitor(v, s, f, e)
+#define QIDL_SCHEMA_ADD_LINK(name, obj, path, errp) \
+g_assert(qidl_data_##name.schema_obj); \
+object_property_add_link(obj, path, "container", \
+ &qidl_data_##name.schema_obj, errp)
+#define QIDL_PROPERTIES(name) \
+qidl_data_##name.properties
+
+#endif /* QIDL_GEN */
+
+#endif
-- 
1.7.9.5




[Qemu-devel] [PATCH 12/20] qapi: add open-coded visitor for struct tm types

2012-08-14 Thread Michael Roth
Reviewed-by: Anthony Liguori 
Signed-off-by: Michael Roth 
---
 qapi/Makefile.objs |1 +
 qapi/misc-qapi-visit.c |   14 ++
 qapi/qapi-visit-core.h |3 +++
 3 files changed, 18 insertions(+)
 create mode 100644 qapi/misc-qapi-visit.c

diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs
index 5f5846e..7604b52 100644
--- a/qapi/Makefile.objs
+++ b/qapi/Makefile.objs
@@ -1,3 +1,4 @@
 qapi-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o
 qapi-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o
 qapi-obj-y += string-input-visitor.o string-output-visitor.o opts-visitor.o
+qapi-obj-y += misc-qapi-visit.o
diff --git a/qapi/misc-qapi-visit.c b/qapi/misc-qapi-visit.c
new file mode 100644
index 000..a44773d
--- /dev/null
+++ b/qapi/misc-qapi-visit.c
@@ -0,0 +1,14 @@
+#include 
+#include "qidl.h"
+
+void visit_type_tm(Visitor *v, struct tm *obj, const char *name, Error **errp)
+{
+visit_start_struct(v, NULL, "struct tm", name, 0, errp);
+visit_type_int32(v, &obj->tm_year, "tm_year", errp);
+visit_type_int32(v, &obj->tm_mon, "tm_mon", errp);
+visit_type_int32(v, &obj->tm_mday, "tm_mday", errp);
+visit_type_int32(v, &obj->tm_hour, "tm_hour", errp);
+visit_type_int32(v, &obj->tm_min, "tm_min", errp);
+visit_type_int32(v, &obj->tm_sec, "tm_sec", errp);
+visit_end_struct(v, errp);
+}
diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
index 5eb1616..10ec044 100644
--- a/qapi/qapi-visit-core.h
+++ b/qapi/qapi-visit-core.h
@@ -100,4 +100,7 @@ void visit_start_carray(Visitor *v, void **obj, const char 
*name,
 void visit_next_carray(Visitor *v, Error **errp);
 void visit_end_carray(Visitor *v, Error **errp);
 
+/* misc. visitors */
+void visit_type_tm(Visitor *m, struct tm *obj, const char *name, Error **errp);
+
 #endif
-- 
1.7.9.5




[Qemu-devel] [PATCH 18/20] qidl: codegen, initial commit

2012-08-14 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 scripts/qidl.py |  282 +++
 1 file changed, 282 insertions(+)
 create mode 100644 scripts/qidl.py

diff --git a/scripts/qidl.py b/scripts/qidl.py
new file mode 100644
index 000..71c89bc
--- /dev/null
+++ b/scripts/qidl.py
@@ -0,0 +1,282 @@
+#
+# QIDL Code Generator
+#
+# Copyright IBM, Corp. 2012
+#
+# Authors:
+#  Anthony Liguori 
+#  Michael Roth
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qidl_parser import parse_file
+from qapi import parse_schema, mcgen, camel_case, de_camel_case
+from qapi_visit import generate_visit_struct, push_indent, pop_indent
+import sys
+import json
+import getopt
+import os
+import errno
+
+def qapi_schema(node):
+schema = OrderedDict()
+data = OrderedDict()
+fields = None
+if node.has_key('typedef'):
+schema['type'] = node['typedef']
+fields = node['type']['fields']
+elif node.has_key('struct'):
+schema['type'] = node['struct']
+fields = node['fields']
+else:
+raise Exception("top-level neither typedef nor struct")
+
+for field in fields:
+if filter(lambda x: field.has_key(x), \
+['is_derived', 'is_immutable', 'is_broken', 'is_function', \
+ 'is_nested_decl', 'is_elsewhere']):
+continue
+
+description = {}
+
+if field['type'].endswith('_t'):
+typename = field['type'][:-2]
+elif field['type'].startswith('struct '):
+typename = field['type'].split(" ")[1]
+elif field['type'].startswith('enum '):
+typename = 'int'
+elif field['type'] == "_Bool":
+typename = 'bool'
+elif field['type'].endswith("char") and field.has_key('is_pointer'):
+typename = 'str';
+elif field['type'] == 'int':
+typename = 'int32'
+elif field['type'] == 'unsigned int':
+typename = 'uint32'
+elif field['type'] == 'char':
+typename = 'uint8'
+else:
+typename = field['type']
+
+if field.has_key('is_array') and field['is_array']:
+description['type'] = [typename]
+description[''] = 'true'
+if field.has_key('array_size'):
+description['array_size'] = field['array_size']
+if field.has_key('array_capacity'):
+description['array_capacity'] = field['array_capacity']
+elif camel_case(de_camel_case(typename)) == typename and \
+(not field.has_key('is_pointer') or not field['is_pointer']):
+description[''] = 'true'
+description[''] = 'true'
+description['type'] = typename
+else:
+description = typename
+
+if field.has_key('is_optional') and field['is_optional']:
+data["*" + field['variable']] = description
+else:
+data[field['variable']] = description
+
+schema['data'] = data
+return schema
+
+
+def parse_schema_file(filename):
+return parse_schema(open(filename, 'r'))
+
+def write_file(output, filename):
+if filename:
+output_file = open(filename, 'w')
+else:
+output_file = sys.stdout
+output_file.write(output)
+if filename:
+output_file.close()
+
+def property_list(node):
+prop_list = []
+fields = None
+if node.has_key('typedef'):
+state = node['typedef']
+fields = node['type']['fields']
+elif node.has_key('struct'):
+state = node['struct']
+fields = node['fields']
+else:
+raise Exception("top-level neither typedef nor struct")
+
+for field in fields:
+if not field.has_key('is_property'):
+continue
+
+for arglist in field['property_fields']:
+if field['variable'] == 'devfn':
+typename = 'pci_devfn'
+elif field['type'].endswith('_t'):
+typename = field['type'][:-2]
+   

[Qemu-devel] [PATCH 07/20] qapi: qapi_visit.py, support generating static functions

2012-08-14 Thread Michael Roth
qidl embeds visitor code into object files rather than linking against
seperate files, so allow for static declarations when we're using
qapi_visit.py as a library as we do with qidl.py

Reviewed-by: Anthony Liguori 
Signed-off-by: Michael Roth 
---
 scripts/qapi_visit.py |   51 -
 1 file changed, 33 insertions(+), 18 deletions(-)

diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
index aac2172..d146013 100644
--- a/scripts/qapi_visit.py
+++ b/scripts/qapi_visit.py
@@ -141,13 +141,16 @@ visit_end_optional(m, &err);
 ''')
 return ret
 
-def generate_visit_struct(name, members):
+def generate_visit_struct(name, members, static=False):
+ret_type = "void"
+if static:
+ret_type = "static " + ret_type
 ret = mcgen('''
 
-void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error 
**errp)
+%(ret_type)s visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char 
*name, Error **errp)
 {
 ''',
-name=name)
+name=name, ret_type=ret_type)
 
 push_indent()
 ret += generate_visit_struct_body("", name, members)
@@ -158,10 +161,13 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, 
const char *name, Error **
 ''')
 return ret
 
-def generate_visit_list(name, members):
+def generate_visit_list(name, members, static=False):
+ret_type = "void"
+if static:
+ret_type = "static " + ret_type
 return mcgen('''
 
-void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char 
*name, Error **errp)
+%(ret_type)s visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const 
char *name, Error **errp)
 {
 GenericList *i, **prev = (GenericList **)obj;
 Error *err = NULL;
@@ -183,19 +189,22 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList ** 
obj, const char *name,
 }
 }
 ''',
-name=name)
+name=name, ret_type=ret_type)
 
-def generate_visit_enum(name, members):
+def generate_visit_enum(name, members, static=False):
+ret_type = "void"
+if static:
+ret_type = "static " + ret_type
 return mcgen('''
 
-void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error 
**errp)
+%(ret_type)s visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, 
Error **errp)
 {
 visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
 }
 ''',
- name=name)
+ name=name, ret_type=ret_type)
 
-def generate_visit_union(name, members):
+def generate_visit_union(name, members, static=False):
 ret = generate_visit_enum('%sKind' % name, members.keys())
 
 ret += mcgen('''
@@ -252,27 +261,33 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, 
const char *name, Error **
 
 return ret
 
-def generate_declaration(name, members, genlist=True):
+def generate_declaration(name, members, genlist=True, static=False):
+ret_type = "void"
+if static:
+ret_type = "static " + ret_type
 ret = mcgen('''
 
-void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error 
**errp);
+%(ret_type)s visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char 
*name, Error **errp);
 ''',
-name=name)
+name=name, ret_type=ret_type)
 
 if genlist:
 ret += mcgen('''
-void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char 
*name, Error **errp);
+%(ret_type)s visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const 
char *name, Error **errp);
 ''',
- name=name)
+ name=name, ret_type=ret_type)
 
 return ret
 
-def generate_decl_enum(name, members, genlist=True):
+def generate_decl_enum(name, members, genlist=True, static=False):
+ret_type = "void"
+if static:
+ret_type = "static " + ret_type
 return mcgen('''
 
-void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error 
**errp);
+%(ret_type)s visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, 
Error **errp);
 ''',
-name=name)
+name=name, ret_type=ret_type)
 
 def main(argv=[]):
 try:
-- 
1.7.9.5




[Qemu-devel] [PATCH 20/20] qidl: unit tests

2012-08-14 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 Makefile   |2 +
 rules.mak  |   15 +++-
 tests/Makefile |8 +-
 tests/test-qidl-included.h |   31 
 tests/test-qidl-linked.c   |   91 +++
 tests/test-qidl-linked.h   |   18 +
 tests/test-qidl.c  |  177 
 7 files changed, 339 insertions(+), 3 deletions(-)
 create mode 100644 tests/test-qidl-included.h
 create mode 100644 tests/test-qidl-linked.c
 create mode 100644 tests/test-qidl-linked.h
 create mode 100644 tests/test-qidl.c

diff --git a/Makefile b/Makefile
index 7733e4c..f02251f 100644
--- a/Makefile
+++ b/Makefile
@@ -233,6 +233,7 @@ clean:
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
rm -f $$d/qemu-options.def; \
 done
+   find -depth -name qidl-generated -type d -exec rm -rf {} \;
 
 VERSION ?= $(shell cat VERSION)
 
@@ -403,6 +404,7 @@ qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
 # rebuilt before other object files
 Makefile: $(GENERATED_HEADERS)
 
+
 # Include automatically generated dependency files
 # Dependencies in Makefile.objs files come from our recursive subdir rules
 -include $(wildcard *.d tests/*.d)
diff --git a/rules.mak b/rules.mak
index a284946..48e7a95 100644
--- a/rules.mak
+++ b/rules.mak
@@ -15,7 +15,20 @@ MAKEFLAGS += -rR
 QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(*D)/$(*F).d
 
 %.o: %.c
-   $(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) 
$(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  CC$(TARGET_DIR)$@")
+
+%.qidl.c: %.c $(SRC_PATH)/qidl.h $(addprefix $(SRC_PATH)/scripts/,qidl.py 
qidl_parser.py qapi.py qapi_visit.py)
+   $(call rm -f $(*D)/qidl-generated/$(*F).qidl.c)
+   $(call quiet-command, $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(CFLAGS) 
-E -c -DQIDL_GEN $< | \
+ $(PYTHON) $(SRC_PATH)/scripts/qidl.py 
--output-filepath=$(*D)/qidl-generated/$(*F).qidl.c || [ "$$?" -eq 2 ])
+
+%.o: %.c %.qidl.c
+   $(if $(strip $(shell test -f $(*D)/qidl-generated/$(*F).qidl.c && echo 
"true")), \
+ $(call quiet-command, \
+   $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c \
+ -include $< -o $@ $(*D)/qidl-generated/$(*F).qidl.c,"qidl CC 
$@"), \
+ $(call quiet-command, \
+   $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c \
+ -o $@ $<,"  CC$@"))
 
 ifeq ($(LIBTOOL),)
 %.lo: %.c
diff --git a/tests/Makefile b/tests/Makefile
index ec6a050..a387643 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -15,6 +15,7 @@ check-unit-y += tests/test-string-output-visitor$(EXESUF)
 check-unit-y += tests/test-coroutine$(EXESUF)
 check-unit-y += tests/test-visitor-serialization$(EXESUF)
 check-unit-y += tests/test-iov$(EXESUF)
+check-unit-y += tests/test-qidl$(EXESUF)
 
 check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
 
@@ -34,11 +35,12 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o 
tests/check-qdict.o \
tests/test-coroutine.o tests/test-string-output-visitor.o \
tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \
tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
-   tests/test-qmp-commands.o tests/test-visitor-serialization.o
+   tests/test-qmp-commands.o tests/test-visitor-serialization.o \
+   tests/test-qidl.o
 
 test-qapi-obj-y =  $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y)
 test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o
-test-qapi-obj-y += module.o
+test-qapi-obj-y += module.o $(qom-obj-y)
 
 $(test-obj-y): QEMU_INCLUDES += -Itests
 
@@ -84,6 +86,8 @@ check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), 
$(check-qtest-$(TARGET)
 qtest-obj-y = tests/libqtest.o $(oslib-obj-y)
 $(check-qtest-y): $(qtest-obj-y)
 
+tests/test-qidl$(EXESUF): tests/test-qidl.o tests/test-qidl-linked.o 
$(test-qapi-obj-y) qapi/misc-qapi-visit.o
+
 .PHONY: check-help
 check-help:
@echo "Regression testing targets:"
diff --git a/tests/test-qidl-included.h b/tests/test-qidl-included.h
new file mode 100644
index 000..2aae51e
--- /dev/null
+++ b/tests/test-qidl-included.h
@@ -0,0 +1,31 @@
+/*
+ * Unit-tests for QIDL-generated visitors/code
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Michael Roth 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TEST_QIDL_INCLUDED_H
+#define TEST_QIDL_INCLUDED_H
+
+#include "qidl.h"
+
+QIDL_START(TestStructIncluded, state, properties)
+typedef struct TestStructIncluded {
+int32_t a QIDL(immutable);
+int32_t b;
+uint32_t c QIDL(immutable);
+uint32_t d;
+uint64_t e QIDL(immutable);
+uint64_t f QIDL(property, "f", 42);
+char *g QIDL(property, "g");
+char *h QIDL(immutable) QIDL(proper

[Qemu-devel] [PATCH 10/20] qapi: QmpInputVisitor, implement array handling

2012-08-14 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 qapi/qmp-input-visitor.c |   32 +++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index 107d8d3..c4388f3 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -132,7 +132,7 @@ static void qmp_input_start_struct(Visitor *v, void **obj, 
const char *kind,
 return;
 }
 
-if (obj) {
+if (obj && *obj == NULL) {
 *obj = g_malloc0(size);
 }
 }
@@ -274,6 +274,33 @@ static void qmp_input_start_optional(Visitor *v, bool 
*present,
 *present = true;
 }
 
+static void qmp_input_start_carray(Visitor *v, void **obj, const char *name,
+   size_t elem_count, size_t elem_size,
+   Error **errp)
+{
+if (obj && *obj == NULL) {
+*obj = g_malloc0(elem_count * elem_size);
+}
+qmp_input_start_list(v, name, errp);
+}
+
+static void qmp_input_next_carray(Visitor *v, Error **errp)
+{
+QmpInputVisitor *qiv = to_qiv(v);
+StackObject *so = &qiv->stack[qiv->nb_stack - 1];
+
+if (so->entry == NULL) {
+so->entry = qlist_first(qobject_to_qlist(so->obj));
+} else {
+so->entry = qlist_next(so->entry);
+}
+}
+
+static void qmp_input_end_carray(Visitor *v, Error **errp)
+{
+qmp_input_end_list(v, errp);
+}
+
 Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
 {
 return &v->visitor;
@@ -302,6 +329,9 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
 v->visitor.type_str = qmp_input_type_str;
 v->visitor.type_number = qmp_input_type_number;
 v->visitor.start_optional = qmp_input_start_optional;
+v->visitor.start_carray = qmp_input_start_carray;
+v->visitor.next_carray = qmp_input_next_carray;
+v->visitor.end_carray = qmp_input_end_carray;
 
 qmp_input_push(v, obj, NULL);
 qobject_incref(obj);
-- 
1.7.9.5




[Qemu-devel] [PATCH 16/20] qidl: Add documentation

2012-08-14 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 docs/qidl.txt |  343 +
 1 file changed, 343 insertions(+)
 create mode 100644 docs/qidl.txt

diff --git a/docs/qidl.txt b/docs/qidl.txt
new file mode 100644
index 000..19976d9
--- /dev/null
+++ b/docs/qidl.txt
@@ -0,0 +1,343 @@
+How to Serialize Device State with QIDL
+==
+
+This document describes how to implement save/restore of a device in QEMU using
+the QIDL compiler.  The QIDL compiler makes it easier to support live
+migration in devices by converging the serialization description with the
+device type declaration.  It has the following features:
+
+ 1. Single description of device state and how to serialize
+
+ 2. Fully inclusive serialization description--fields that aren't serialized
+are explicitly marked as such including the reason why.
+
+ 3. Optimized for the common case.  Even without any special annotations,
+many devices will Just Work out of the box.
+
+ 4. Build time schema definition.  Since QIDL runs at build time, we have full
+access to the schema during the build which means we can fail the build if
+the schema breaks.
+
+For the rest, of the document, the following simple device will be used as an
+example.
+
+typedef struct SerialDevice {
+SysBusDevice parent;
+
+uint8_t thr;// transmit holding register
+uint8_t lsr;// line status register
+uint8_t ier;// interrupt enable register
+
+int int_pending;// whether we have a pending queued interrupt
+CharDriverState *chr;   // backend
+} SerialDevice;
+
+Getting Started
+---
+
+The first step is to move your device struct definition to a header file.  This
+header file should only contain the struct definition and any preprocessor
+declarations you need to define the structure.  This header file will act as
+the source for the QIDL compiler.
+
+Do not include any function declarations in this header file as QIDL does not
+understand function declarations.
+
+Determining What State Gets Saved
+-
+
+By default, QIDL saves every field in a structure it sees.  This provides 
maximum
+correctness by default.  However, device structures generally contain state
+that reflects state that is in someway duplicated or not guest visible.  This
+more often that not reflects design implementation details.
+
+Since design implementation details change over time, saving this state makes
+compatibility hard to maintain since it would effectively lock down a device's
+implementation.
+
+QIDL allows a device author to suppress certain fields from being saved 
although
+there are very strict rules about when this is allowed and what needs to be 
done
+to ensure that this does not impact correctness.
+
+There are three cases where state can be suppressed: when it is **immutable**,
+**derived**, or **broken**.  In addition, QIDL can decide at run time whether 
to
+suppress a field by assigning it a **default** value.
+
+## Immutable Fields
+
+If a field is only set during device construction, based on parameters passed 
to
+the device's constructor, then there is no need to send save and restore this
+value.  We call these fields immutable and we tell QIDL about this fact by 
using
+a **immutable** marker.
+
+In our *SerialDevice* example, the *CharDriverState* pointer reflects the host
+backend that we use to send serial output to the user.  This is only assigned
+during device construction and never changes.  This means we can add an
+**immutable** marker to it:
+
+QIDL_START(SerialDevice, state)
+typedef struct SerialDevice {
+SysBusDevice parent;
+
+uint8_t thr;// transmit holding register
+uint8_t lsr;// line status register
+uint8_t ier;// interrupt enable register
+
+int int_pending;// whether we have a pending queued interrupt
+CharDriverState *chr QIDL(immutable);
+} SerialDevice;
+QIDL_END(SerialDevice)
+
+When reviewing patches that make use of the **immutable** marker, the following
+guidelines should be followed to determine if the marker is being used
+correctly.
+
+ 1. Check to see if the field is assigned anywhere other than the device
+initialization function.
+
+ 2. Check to see if any function is being called that modifies the state of the
+field outside of the initialization function.
+
+It can be subtle whether a field is truly immutable.  A good example is a
+*QEMUTimer*.  Timer's will usually have their timeout modified with a call to
+*qemu_mod_timer()* even though they are only assigned in the device
+initialization function.
+
+If the timer is always modified with a fixed value that is not dependent on
+guest state, then the timer is immutable since it's unaffected by the state of
+the gu

[Qemu-devel] [PATCH 01/20] qapi: qapi-visit.py -> qapi_visit.py so we can import

2012-08-14 Thread Michael Roth
Python doesn't allow "-" in module names, so we need to rename the file
so we can re-use bits of the codegen

Reviewed-by: Anthony Liguori 
Signed-off-by: Michael Roth 
---
 Makefile |8 
 scripts/{qapi-visit.py => qapi_visit.py} |0
 tests/Makefile   |4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)
 rename scripts/{qapi-visit.py => qapi_visit.py} (100%)

diff --git a/Makefile b/Makefile
index d736ea5..08c7d0e 100644
--- a/Makefile
+++ b/Makefile
@@ -187,8 +187,8 @@ qga/qapi-generated/qga-qapi-types.c 
qga/qapi-generated/qga-qapi-types.h :\
 $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py 
$(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
-   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py 
$(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi_visit.py $(qapi-py)
+   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py 
$(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
 $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py 
$(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py 
$(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
@@ -197,8 +197,8 @@ qapi-types.c qapi-types.h :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py 
$(gen-out-type) -o "." < $<, "  GEN   $@")
 qapi-visit.c qapi-visit.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
-   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py 
$(gen-out-type) -o "."  < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_visit.py $(qapi-py)
+   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py 
$(gen-out-type) -o "."  < $<, "  GEN   $@")
 qmp-commands.h qmp-marshal.c :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py 
$(gen-out-type) -m -o "." < $<, "  GEN   $@")
diff --git a/scripts/qapi-visit.py b/scripts/qapi_visit.py
similarity index 100%
rename from scripts/qapi-visit.py
rename to scripts/qapi_visit.py
diff --git a/tests/Makefile b/tests/Makefile
index f3f4159..3c05bdf 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -55,8 +55,8 @@ tests/test-qapi-types.c tests/test-qapi-types.h :\
 $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py 
$(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
 tests/test-qapi-visit.c tests/test-qapi-visit.h :\
-$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
-   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py 
$(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi_visit.py
+   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py 
$(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
 tests/test-qmp-commands.h tests/test-qmp-marshal.c :\
 $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py 
$(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
-- 
1.7.9.5




[Qemu-devel] [PATCH 08/20] qapi: qapi_visit.py, support for visiting non-pointer/embedded structs

2012-08-14 Thread Michael Roth
Reviewed-by: Anthony Liguori 
Signed-off-by: Michael Roth 
---
 scripts/qapi_visit.py |9 +
 1 file changed, 9 insertions(+)

diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
index d146013..ab44f11 100644
--- a/scripts/qapi_visit.py
+++ b/scripts/qapi_visit.py
@@ -107,6 +107,15 @@ if (obj && (*obj)->%(prefix)shas_%(c_name)s) {
 if annotated:
 if isinstance(argentry['type'], types.ListType):
 ret += generate_visit_carray_body(argname, argentry)
+elif argentry.has_key(''):
+tmp_ptr_name = "%s_%s_ptr" % 
(c_var(field_prefix).replace(".", ""), c_var(argname))
+ret += mcgen('''
+%(type)s *%(tmp_ptr)s = &(*obj)->%(c_prefix)s%(c_name)s;
+visit_type_%(type)s(m, (obj && *obj) ? &%(tmp_ptr)s : NULL, "%(name)s", errp);
+''',
+ c_prefix=c_var(field_prefix), 
prefix=field_prefix,
+ type=type_name(argentry['type']), 
c_name=c_var(argname),
+ name=argname, tmp_ptr=tmp_ptr_name)
 else:
 ret += mcgen('''
 visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, 
"%(name)s", errp);
-- 
1.7.9.5




[Qemu-devel] [PATCH 02/20] qapi: qapi-types.py -> qapi_types.py

2012-08-14 Thread Michael Roth
Python doesn't allow "-" in module names, so we need to rename the file
so we can re-use bits of the codegen

Signed-off-by: Michael Roth 
---
 Makefile |8 
 scripts/{qapi-types.py => qapi_types.py} |0
 tests/Makefile   |4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)
 rename scripts/{qapi-types.py => qapi_types.py} (100%)

diff --git a/Makefile b/Makefile
index 08c7d0e..e92ea6b 100644
--- a/Makefile
+++ b/Makefile
@@ -184,8 +184,8 @@ endif
 qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
 
 qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
-   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py 
$(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi_types.py $(qapi-py)
+   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_types.py 
$(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
 $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi_visit.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py 
$(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
@@ -194,8 +194,8 @@ $(SRC_PATH)/qapi-schema-guest.json 
$(SRC_PATH)/scripts/qapi-commands.py $(qapi-p
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py 
$(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 
 qapi-types.c qapi-types.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
-   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py 
$(gen-out-type) -o "." < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_types.py $(qapi-py)
+   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_types.py 
$(gen-out-type) -o "." < $<, "  GEN   $@")
 qapi-visit.c qapi-visit.h :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_visit.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py 
$(gen-out-type) -o "."  < $<, "  GEN   $@")
diff --git a/scripts/qapi-types.py b/scripts/qapi_types.py
similarity index 100%
rename from scripts/qapi-types.py
rename to scripts/qapi_types.py
diff --git a/tests/Makefile b/tests/Makefile
index 3c05bdf..156105c 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -52,8 +52,8 @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o 
$(coroutine-obj-y) $(tools
 tests/test-iov$(EXESUF): tests/test-iov.o iov.o
 
 tests/test-qapi-types.c tests/test-qapi-types.h :\
-$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
-   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py 
$(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi_types.py
+   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_types.py 
$(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
 tests/test-qapi-visit.c tests/test-qapi-visit.h :\
 $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi_visit.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py 
$(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
-- 
1.7.9.5




[Qemu-devel] [PATCH 03/20] qapi: qapi-commands.py -> qapi_commands.py

2012-08-14 Thread Michael Roth
Python doesn't allow "-" in module names, so we need to rename the file
so we can re-use bits of the codegen.

Signed-off-by: Michael Roth 
---
 Makefile   |8 
 scripts/{qapi-commands.py => qapi_commands.py} |0
 tests/Makefile |4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)
 rename scripts/{qapi-commands.py => qapi_commands.py} (100%)

diff --git a/Makefile b/Makefile
index e92ea6b..7733e4c 100644
--- a/Makefile
+++ b/Makefile
@@ -190,8 +190,8 @@ qga/qapi-generated/qga-qapi-visit.c 
qga/qapi-generated/qga-qapi-visit.h :\
 $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi_visit.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py 
$(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py 
$(qapi-py)
-   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py 
$(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi_commands.py 
$(qapi-py)
+   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_commands.py 
$(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 
 qapi-types.c qapi-types.h :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_types.py $(qapi-py)
@@ -200,8 +200,8 @@ qapi-visit.c qapi-visit.h :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_visit.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py 
$(gen-out-type) -o "."  < $<, "  GEN   $@")
 qmp-commands.h qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
-   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py 
$(gen-out-type) -m -o "." < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_commands.py $(qapi-py)
+   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_commands.py 
$(gen-out-type) -m -o "." < $<, "  GEN   $@")
 
 QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h 
qga-qmp-commands.h)
 $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
diff --git a/scripts/qapi-commands.py b/scripts/qapi_commands.py
similarity index 100%
rename from scripts/qapi-commands.py
rename to scripts/qapi_commands.py
diff --git a/tests/Makefile b/tests/Makefile
index 156105c..ec6a050 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -58,8 +58,8 @@ tests/test-qapi-visit.c tests/test-qapi-visit.h :\
 $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi_visit.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py 
$(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
 tests/test-qmp-commands.h tests/test-qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
-   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py 
$(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi_commands.py
+   $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_commands.py 
$(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
 
 
 tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o 
$(test-qapi-obj-y)
-- 
1.7.9.5




[Qemu-devel] [PATCH 14/20] module additions for schema registration

2012-08-14 Thread Michael Roth
Reviewed-by: Anthony Liguori 
Signed-off-by: Michael Roth 
---
 module.h |2 ++
 vl.c |1 +
 2 files changed, 3 insertions(+)

diff --git a/module.h b/module.h
index c4ccd57..cb81aa2 100644
--- a/module.h
+++ b/module.h
@@ -25,6 +25,7 @@ typedef enum {
 MODULE_INIT_MACHINE,
 MODULE_INIT_QAPI,
 MODULE_INIT_QOM,
+MODULE_INIT_QIDL,
 MODULE_INIT_MAX
 } module_init_type;
 
@@ -32,6 +33,7 @@ typedef enum {
 #define machine_init(function) module_init(function, MODULE_INIT_MACHINE)
 #define qapi_init(function) module_init(function, MODULE_INIT_QAPI)
 #define type_init(function) module_init(function, MODULE_INIT_QOM)
+#define qidl_init(function) module_init(function, MODULE_INIT_QIDL)
 
 void register_module_init(void (*fn)(void), module_init_type type);
 
diff --git a/vl.c b/vl.c
index d01256a..7895e9d 100644
--- a/vl.c
+++ b/vl.c
@@ -2358,6 +2358,7 @@ int main(int argc, char **argv, char **envp)
 }
 
 module_call_init(MODULE_INIT_QOM);
+module_call_init(MODULE_INIT_QIDL);
 
 runstate_init();
 
-- 
1.7.9.5




[Qemu-devel] [PATCH 15/20] qdev: move Property-related declarations to qdev-properties.h

2012-08-14 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 hw/qdev-properties.h |  151 ++
 hw/qdev.h|  126 +
 2 files changed, 152 insertions(+), 125 deletions(-)
 create mode 100644 hw/qdev-properties.h

diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h
new file mode 100644
index 000..ce79a79
--- /dev/null
+++ b/hw/qdev-properties.h
@@ -0,0 +1,151 @@
+/*
+ *  Property definitions for qdev
+ *
+ *  Copyright (c) 2009 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QDEV_PROPERTIES_H
+#define QDEV_PROPERTIES_H
+
+#include "qemu/object.h"
+#include "qemu-queue.h"
+
+typedef struct Property Property;
+
+typedef struct PropertyInfo PropertyInfo;
+
+typedef struct CompatProperty CompatProperty;
+
+struct Property {
+const char   *name;
+PropertyInfo *info;
+int  offset;
+uint8_t  bitnr;
+uint8_t  qtype;
+int64_t  defval;
+};
+
+struct PropertyInfo {
+const char *name;
+const char *legacy_name;
+const char **enum_table;
+int (*parse)(DeviceState *dev, Property *prop, const char *str);
+int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
+ObjectPropertyAccessor *get;
+ObjectPropertyAccessor *set;
+ObjectPropertyRelease *release;
+};
+
+typedef struct GlobalProperty {
+const char *driver;
+const char *property;
+const char *value;
+QTAILQ_ENTRY(GlobalProperty) next;
+} GlobalProperty;
+
+extern PropertyInfo qdev_prop_bit;
+extern PropertyInfo qdev_prop_uint8;
+extern PropertyInfo qdev_prop_uint16;
+extern PropertyInfo qdev_prop_uint32;
+extern PropertyInfo qdev_prop_int32;
+extern PropertyInfo qdev_prop_uint64;
+extern PropertyInfo qdev_prop_hex8;
+extern PropertyInfo qdev_prop_hex32;
+extern PropertyInfo qdev_prop_hex64;
+extern PropertyInfo qdev_prop_string;
+extern PropertyInfo qdev_prop_chr;
+extern PropertyInfo qdev_prop_ptr;
+extern PropertyInfo qdev_prop_macaddr;
+extern PropertyInfo qdev_prop_losttickpolicy;
+extern PropertyInfo qdev_prop_bios_chs_trans;
+extern PropertyInfo qdev_prop_drive;
+extern PropertyInfo qdev_prop_netdev;
+extern PropertyInfo qdev_prop_vlan;
+extern PropertyInfo qdev_prop_pci_devfn;
+extern PropertyInfo qdev_prop_blocksize;
+extern PropertyInfo qdev_prop_pci_host_devaddr;
+
+#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
+.name  = (_name),\
+.info  = &(_prop),   \
+.offset= offsetof(_state, _field)\
++ type_check(_type,typeof_field(_state, _field)),\
+}
+#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
+.name  = (_name),   \
+.info  = &(_prop),  \
+.offset= offsetof(_state, _field)   \
++ type_check(_type,typeof_field(_state, _field)),   \
+.qtype = QTYPE_QINT,\
+.defval= (_type)_defval,\
+}
+#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) {  \
+.name  = (_name),\
+.info  = &(qdev_prop_bit),   \
+.bitnr= (_bit),  \
+.offset= offsetof(_state, _field)\
++ type_check(uint32_t,typeof_field(_state, _field)), \
+.qtype = QTYPE_QBOOL,\
+.defval= (bool)_defval,  \
+}
+
+#define DEFINE_PROP_UINT8(_n, _s, _f, _d)   \
+DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
+#define DEFINE_PROP_UINT16(_n, _s, _f, _d)  \
+DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t)
+#define DEFINE_PROP_UINT32(_n, _s, _f, _d)  \
+DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t)
+#define DEFINE_PROP_INT32(_n, _s, _f, _d)  \
+DEFINE_PROP_DEFAULT(_n, _s, _f, 

[Qemu-devel] [PATCH 06/20] qapi: add visitor interfaces for C arrays

2012-08-14 Thread Michael Roth
Generally these will be serialized into lists, but the
representation can be of any form so long as it can
be deserialized into a single-dimension C array.

Signed-off-by: Michael Roth 
---
 qapi/qapi-visit-core.c |   25 +
 qapi/qapi-visit-core.h |8 
 2 files changed, 33 insertions(+)

diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 7a82b63..9a74ed0 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -311,3 +311,28 @@ void input_type_enum(Visitor *v, int *obj, const char 
*strings[],
 g_free(enum_str);
 *obj = value;
 }
+
+void visit_start_carray(Visitor *v, void **obj, const char *name,
+size_t elem_count, size_t elem_size, Error **errp)
+{
+g_assert(v->start_carray);
+if (!error_is_set(errp)) {
+v->start_carray(v, obj, name, elem_count, elem_size, errp);
+}
+}
+
+void visit_next_carray(Visitor *v, Error **errp)
+{
+g_assert(v->next_carray);
+if (!error_is_set(errp)) {
+v->next_carray(v, errp);
+}
+}
+
+void visit_end_carray(Visitor *v, Error **errp)
+{
+g_assert(v->end_carray);
+if (!error_is_set(errp)) {
+v->end_carray(v, errp);
+}
+}
diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
index 60aceda..5eb1616 100644
--- a/qapi/qapi-visit-core.h
+++ b/qapi/qapi-visit-core.h
@@ -43,6 +43,10 @@ struct Visitor
 void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
 void (*type_number)(Visitor *v, double *obj, const char *name,
 Error **errp);
+void (*start_carray)(Visitor *v, void **obj, const char *name,
+size_t elem_count, size_t elem_size, Error **errp);
+void (*next_carray)(Visitor *v, Error **errp);
+void (*end_carray)(Visitor *v, Error **errp);
 
 /* May be NULL */
 void (*start_optional)(Visitor *v, bool *present, const char *name,
@@ -91,5 +95,9 @@ void visit_type_size(Visitor *v, uint64_t *obj, const char 
*name, Error **errp);
 void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
 void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
 void visit_type_number(Visitor *v, double *obj, const char *name, Error 
**errp);
+void visit_start_carray(Visitor *v, void **obj, const char *name,
+   size_t elem_count, size_t elem_size, Error **errp);
+void visit_next_carray(Visitor *v, Error **errp);
+void visit_end_carray(Visitor *v, Error **errp);
 
 #endif
-- 
1.7.9.5




[Qemu-devel] [PATCH 09/20] qapi: QmpOutputVisitor, implement array handling

2012-08-14 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 qapi/qmp-output-visitor.c |   20 
 1 file changed, 20 insertions(+)

diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
index 2bce9d5..ea08795 100644
--- a/qapi/qmp-output-visitor.c
+++ b/qapi/qmp-output-visitor.c
@@ -181,6 +181,23 @@ static void qmp_output_type_number(Visitor *v, double 
*obj, const char *name,
 qmp_output_add(qov, name, qfloat_from_double(*obj));
 }
 
+static void qmp_output_start_carray(Visitor *v, void **obj, const char *name,
+size_t elem_count, size_t elem_size,
+Error **errp)
+{
+qmp_output_start_list(v, name, errp);
+}
+
+static void qmp_output_next_carray(Visitor *v, Error **errp)
+{
+}
+
+static void qmp_output_end_carray(Visitor *v, Error **errp)
+{
+QmpOutputVisitor *qov = to_qov(v);
+qmp_output_pop(qov);
+}
+
 QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
 {
 QObject *obj = qmp_output_first(qov);
@@ -228,6 +245,9 @@ QmpOutputVisitor *qmp_output_visitor_new(void)
 v->visitor.type_bool = qmp_output_type_bool;
 v->visitor.type_str = qmp_output_type_str;
 v->visitor.type_number = qmp_output_type_number;
+v->visitor.start_carray = qmp_output_start_carray;
+v->visitor.next_carray = qmp_output_next_carray;
+v->visitor.end_carray = qmp_output_end_carray;
 
 QTAILQ_INIT(&v->stack);
 
-- 
1.7.9.5




Re: [Qemu-devel] [PATCH 16/20] qidl: Add documentation

2012-08-14 Thread Michael Roth
On Tue, Aug 14, 2012 at 08:41:56PM +0100, Peter Maydell wrote:
> On 14 August 2012 17:27, Michael Roth  wrote:
> >
> > Signed-off-by: Michael Roth 
> > ---
> >  docs/qidl.txt |  343 
> > +
> >  1 file changed, 343 insertions(+)
> >  create mode 100644 docs/qidl.txt
> >
> > diff --git a/docs/qidl.txt b/docs/qidl.txt
> > new file mode 100644
> > index 000..19976d9
> > --- /dev/null
> > +++ b/docs/qidl.txt
> > @@ -0,0 +1,343 @@
> > +How to Serialize Device State with QIDL
> > +==
> > +
> > +This document describes how to implement save/restore of a device in QEMU 
> > using
> > +the QIDL compiler.  The QIDL compiler makes it easier to support live
> > +migration in devices by converging the serialization description with the
> > +device type declaration.  It has the following features:
> > +
> > + 1. Single description of device state and how to serialize
> > +
> > + 2. Fully inclusive serialization description--fields that aren't 
> > serialized
> > +are explicitly marked as such including the reason why.
> > +
> > + 3. Optimized for the common case.  Even without any special annotations,
> > +many devices will Just Work out of the box.
> > +
> > + 4. Build time schema definition.  Since QIDL runs at build time, we have 
> > full
> > +access to the schema during the build which means we can fail the 
> > build if
> > +the schema breaks.
> > +
> > +For the rest, of the document, the following simple device will be used as 
> > an
> > +example.
> > +
> > +typedef struct SerialDevice {
> > +SysBusDevice parent;
> > +
> > +uint8_t thr;// transmit holding register
> > +uint8_t lsr;// line status register
> > +uint8_t ier;// interrupt enable register
> > +
> > +int int_pending;// whether we have a pending queued 
> > interrupt
> > +CharDriverState *chr;   // backend
> > +} SerialDevice;
> 
> "//" style comments are a breach of the QEMU coding style so we shouldn't
> be using them in documentation examples...
> 
> > +
> > +In our *SerialDevice* example, the *CharDriverState* pointer reflects the 
> > host
> > +backend that we use to send serial output to the user.  This is only 
> > assigned
> > +during device construction and never changes.  This means we can add an
> > +**immutable** marker to it:
> > +
> > +QIDL_START(SerialDevice, state)
> > +typedef struct SerialDevice {
> > +SysBusDevice parent;
> > +
> > +uint8_t thr;// transmit holding register
> > +uint8_t lsr;// line status register
> > +uint8_t ier;// interrupt enable register
> > +
> > +int int_pending;// whether we have a pending queued 
> > interrupt
> > +CharDriverState *chr QIDL(immutable);
> > +} SerialDevice;
> > +QIDL_END(SerialDevice)
> 
> I think it would be nicer to have a QIDL input format from which the structure
> is generated as one of the outputs; that would avoid having to have some of
> this ugly QIDL() markup.

Some kind of inline/embedded input format, or external (like QAPI
schemas)?

In terms of the ugliness of things, Anthony suggested we re-introduce
the simpler form of the annotations by doing something like:

#define _immutable QIDL(immutable)

as syntactic sugar for the more commonly used annotations/macros. This
can all be done in qidl.h, transparently to the parser (thanks to the
fact that we pass the code through the preprocessor prior to parsing).
There's also a few things we can do to replace the QIDL_START/QIDL_END
pairs with a single indicator.

> 
> We could also use this to autogenerate a lot of the QOM required boilerplate,
> qdev Property arrays, etc etc.

QIDL handles properties, and could possibly be used to generate some QOM
boilerplate. We can get as creative as need be really, it's just that
properties/serialization were the primary/initial use-cases.

> 
> -- PMM
> 



Re: [Qemu-devel] [PATCH] json-parser: don't replicate tokens at each level of recursion

2012-08-15 Thread Michael Roth
On Mon, Aug 13, 2012 at 09:25:44PM -0500, Michael Roth wrote:
> On Mon, Aug 13, 2012 at 03:01:56PM -0300, Luiz Capitulino wrote:
> > On Fri, 10 Aug 2012 18:24:10 -0500
> > Michael Roth  wrote:
> > 
> > > +qlist_iter(tokens, tokens_count_from_iter, &count);
> > > +if (count == 0) {
> > > +return NULL;
> > > +}
> > 
> > Please, add qlist_size() instead.
> > 
> 
> Gladly :) I spent a good amount for a function that did this, not sure
> how I missed it.
> 

Heh, read that as "please, use qlist_size() instead". I've added it
after further searching for it :)

> > > +
> > > +ctxt = g_malloc0(sizeof(JSONParserContext));
> > > +ctxt->tokens.pos = 0;
> > > +ctxt->tokens.count = count;
> > > +ctxt->tokens.buf = g_malloc(count * sizeof(QObject *));
> > > +qlist_iter(tokens, tokens_append_from_iter, ctxt);
> > > +ctxt->tokens.pos = 0;
> > > +
> > > +return ctxt;
> > > +}
> > > +
> > > +static void parser_context_free(JSONParserContext *ctxt)
> > > +{
> > > +int i;
> > > +if (ctxt) {
> > > +for (i = 0; i < ctxt->tokens.count; i++) {
> > > +qobject_decref(ctxt->tokens.buf[i]);
> > > +}
> > > +g_free(ctxt->tokens.buf);
> > > +g_free(ctxt);
> > 
> > Isn't this leaking ctxt->err?
> > 
> 
> Indeed. Looks like we were leaking this previously as well. I'll get it
> in V2.
> 

Apparently not, actually. It looks like error_propagate() handles
whether to free the error or pass it up the stack, so we can't mess with
it in the free function. I've added a comment to note that ctxt->err
needs to be freed seperately.

V2 is incoming with comments addressed.



[Qemu-devel] [PATCH for-1.2 v2 1/3] qlist: add qlist_size()

2012-08-15 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 qlist.c |   13 +
 qlist.h |1 +
 2 files changed, 14 insertions(+)

diff --git a/qlist.c b/qlist.c
index 88498b1..b48ec5b 100644
--- a/qlist.c
+++ b/qlist.c
@@ -124,6 +124,19 @@ int qlist_empty(const QList *qlist)
 return QTAILQ_EMPTY(&qlist->head);
 }
 
+static void qlist_size_iter(QObject *obj, void *opaque)
+{
+size_t *count = opaque;
+(*count)++;
+}
+
+size_t qlist_size(const QList *qlist)
+{
+size_t count = 0;
+qlist_iter(qlist, qlist_size_iter, &count);
+return count;
+}
+
 /**
  * qobject_to_qlist(): Convert a QObject into a QList
  */
diff --git a/qlist.h b/qlist.h
index d426bd4..ae776f9 100644
--- a/qlist.h
+++ b/qlist.h
@@ -49,6 +49,7 @@ void qlist_iter(const QList *qlist,
 QObject *qlist_pop(QList *qlist);
 QObject *qlist_peek(QList *qlist);
 int qlist_empty(const QList *qlist);
+size_t qlist_size(const QList *qlist);
 QList *qobject_to_qlist(const QObject *obj);
 
 static inline const QListEntry *qlist_first(const QList *qlist)
-- 
1.7.9.5




[Qemu-devel] [PATCH for-1.2 v2 2/3] json-parser: don't replicate tokens at each level of recursion

2012-08-15 Thread Michael Roth
Currently, when parsing a stream of tokens we make a copy of the token
list at the beginning of each level of recursion so that we do not
modify the original list in cases where we need to fall back to an
earlier state.

In the worst case, we will only read 1 or 2 tokens off the list before
recursing again, which means an upper bound of roughly N^2 token allocations.

For a "reasonably" sized QMP request (in this a QMP representation of
cirrus_vga's device state, generated via QIDL, being passed in via
qom-set), this caused my 16GB's of memory to be exhausted before any
noticeable progress was made by the parser.

This patch works around the issue by using single copy of the token list
in the form of an indexable array so that we can save/restore state by
manipulating indices.

A subsequent commit adds a "large_dict" test case which exhibits the
same behavior as above. With this patch applied the test case successfully
completes in under a second.

Tested with valgrind, make check, and QMP.

Signed-off-by: Michael Roth 
---
 json-parser.c |  229 +++--
 1 file changed, 141 insertions(+), 88 deletions(-)

diff --git a/json-parser.c b/json-parser.c
index 849e215..65a87c7 100644
--- a/json-parser.c
+++ b/json-parser.c
@@ -27,6 +27,11 @@
 typedef struct JSONParserContext
 {
 Error *err;
+struct {
+QObject **buf;
+size_t pos;
+size_t count;
+} tokens;
 } JSONParserContext;
 
 #define BUG_ON(cond) assert(!(cond))
@@ -40,7 +45,7 @@ typedef struct JSONParserContext
  * 4) deal with premature EOI
  */
 
-static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list 
*ap);
+static QObject *parse_value(JSONParserContext *ctxt, va_list *ap);
 
 /**
  * Token manipulators
@@ -270,27 +275,110 @@ out:
 return NULL;
 }
 
+static QObject *parser_context_pop_token(JSONParserContext *ctxt)
+{
+QObject *token;
+g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+token = ctxt->tokens.buf[ctxt->tokens.pos];
+ctxt->tokens.pos++;
+return token;
+}
+
+/* Note: parser_context_{peek|pop}_token do not increment the
+ * token object's refcount. In both cases the references will continue
+ * to be * tracked and cleanup in parser_context_free()
+ */
+static QObject *parser_context_peek_token(JSONParserContext *ctxt)
+{
+QObject *token;
+g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+token = ctxt->tokens.buf[ctxt->tokens.pos];
+return token;
+}
+
+static JSONParserContext parser_context_save(JSONParserContext *ctxt)
+{
+JSONParserContext saved_ctxt = {0};
+saved_ctxt.tokens.pos = ctxt->tokens.pos;
+saved_ctxt.tokens.count = ctxt->tokens.count;
+saved_ctxt.tokens.buf = ctxt->tokens.buf;
+return saved_ctxt;
+}
+
+static void parser_context_restore(JSONParserContext *ctxt,
+   JSONParserContext saved_ctxt)
+{
+ctxt->tokens.pos = saved_ctxt.tokens.pos;
+ctxt->tokens.count = saved_ctxt.tokens.count;
+ctxt->tokens.buf = saved_ctxt.tokens.buf;
+}
+
+static void tokens_append_from_iter(QObject *obj, void *opaque)
+{
+JSONParserContext *ctxt = opaque;
+g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+ctxt->tokens.buf[ctxt->tokens.pos++] = obj;
+qobject_incref(obj);
+}
+
+static JSONParserContext *parser_context_new(QList *tokens)
+{
+JSONParserContext *ctxt;
+size_t count;
+
+if (!tokens) {
+return NULL;
+}
+
+count = qlist_size(tokens);
+if (count == 0) {
+return NULL;
+}
+
+ctxt = g_malloc0(sizeof(JSONParserContext));
+ctxt->tokens.pos = 0;
+ctxt->tokens.count = count;
+ctxt->tokens.buf = g_malloc(count * sizeof(QObject *));
+qlist_iter(tokens, tokens_append_from_iter, ctxt);
+ctxt->tokens.pos = 0;
+
+return ctxt;
+}
+
+/* to support error propagation, ctxt->err must be freed seperately */
+static void parser_context_free(JSONParserContext *ctxt)
+{
+int i;
+if (ctxt) {
+for (i = 0; i < ctxt->tokens.count; i++) {
+qobject_decref(ctxt->tokens.buf[i]);
+}
+g_free(ctxt->tokens.buf);
+g_free(ctxt);
+}
+}
+
 /**
  * Parsing rules
  */
-static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, 
va_list *ap)
+static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
 {
 QObject *key = NULL, *token = NULL, *value, *peek;
-QList *working = qlist_copy(*tokens);
+JSONParserContext saved_ctxt = parser_context_save(ctxt);
 
-peek = qlist_peek(working);
+peek = parser_context_peek_token(ctxt);
 if (peek == NULL) {
 parse_error(ctxt, NULL, "premature EOI");
 goto out;
 }
 
-key = parse_value(ctxt, &working, ap);
+key = parse_value(ctxt, ap);
 if (!key || qobject_type(key) != 

[Qemu-devel] [PATCH for-1.2 v2 3/3] check-qjson: add test for large JSON objects

2012-08-15 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 tests/check-qjson.c |   53 +++
 1 file changed, 53 insertions(+)

diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index 526e25e..ef9b529 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -690,6 +690,58 @@ static void unterminated_literal(void)
 g_assert(obj == NULL);
 }
 
+/*
+ * this generates json of the form:
+ * a(0,m) = [0, 1, ..., m-1]
+ * a(n,m) = {
+ *'key0': a(0,m),
+ *'key1': a(1,m),
+ *...
+ *'key(n-1)': a(n-1,m)
+ *  }
+ */
+static void gen_test_json(GString *gstr, int nest_level_max,
+  int elem_count)
+{
+int i;
+
+g_assert(gstr);
+if (nest_level_max == 0) {
+g_string_append(gstr, "[");
+for (i = 0; i < elem_count; i++) {
+g_string_append_printf(gstr, "%d", i);
+if (i < elem_count - 1) {
+g_string_append_printf(gstr, ", ");
+}
+}
+g_string_append(gstr, "]");
+return;
+}
+
+g_string_append(gstr, "{");
+for (i = 0; i < nest_level_max; i++) {
+g_string_append_printf(gstr, "'key%d': ", i);
+gen_test_json(gstr, i, elem_count);
+if (i < nest_level_max - 1) {
+g_string_append(gstr, ",");
+}
+}
+g_string_append(gstr, "}");
+}
+
+static void large_dict(void)
+{
+GString *gstr = g_string_new("");
+QObject *obj;
+
+gen_test_json(gstr, 10, 100);
+obj = qobject_from_json(gstr->str);
+g_assert(obj != NULL);
+
+qobject_decref(obj);
+g_string_free(gstr, true);
+}
+
 int main(int argc, char **argv)
 {
 g_test_init(&argc, &argv, NULL);
@@ -706,6 +758,7 @@ int main(int argc, char **argv)
 g_test_add_func("/literals/keyword", keyword_literal);
 
 g_test_add_func("/dicts/simple_dict", simple_dict);
+g_test_add_func("/dicts/large_dict", large_dict);
 g_test_add_func("/lists/simple_list", simple_list);
 
 g_test_add_func("/whitespace/simple_whitespace", simple_whitespace);
-- 
1.7.9.5




Re: [Qemu-devel] [PATCH for-1.2 v2 2/3] json-parser: don't replicate tokens at each level of recursion

2012-08-15 Thread Michael Roth
On Wed, Aug 15, 2012 at 12:09:09PM -0600, Eric Blake wrote:
> On 08/15/2012 11:56 AM, Michael Roth wrote:
> > Currently, when parsing a stream of tokens we make a copy of the token
> > list at the beginning of each level of recursion so that we do not
> > modify the original list in cases where we need to fall back to an
> > earlier state.
> > 
> > +
> > +/* Note: parser_context_{peek|pop}_token do not increment the
> > + * token object's refcount. In both cases the references will continue
> > + * to be * tracked and cleanup in parser_context_free()
> 
> Bad comment reflow? s/be * tracked/be tracked/
> 
> > +
> > +/* to support error propagation, ctxt->err must be freed seperately */
> 
> s/seperately/separately/
> 

Thanks, fixed in incoming v3

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





[Qemu-devel] [PATCH for-1.2 v3 1/3] qlist: add qlist_size()

2012-08-15 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 qlist.c |   13 +
 qlist.h |1 +
 2 files changed, 14 insertions(+)

diff --git a/qlist.c b/qlist.c
index 88498b1..b48ec5b 100644
--- a/qlist.c
+++ b/qlist.c
@@ -124,6 +124,19 @@ int qlist_empty(const QList *qlist)
 return QTAILQ_EMPTY(&qlist->head);
 }
 
+static void qlist_size_iter(QObject *obj, void *opaque)
+{
+size_t *count = opaque;
+(*count)++;
+}
+
+size_t qlist_size(const QList *qlist)
+{
+size_t count = 0;
+qlist_iter(qlist, qlist_size_iter, &count);
+return count;
+}
+
 /**
  * qobject_to_qlist(): Convert a QObject into a QList
  */
diff --git a/qlist.h b/qlist.h
index d426bd4..ae776f9 100644
--- a/qlist.h
+++ b/qlist.h
@@ -49,6 +49,7 @@ void qlist_iter(const QList *qlist,
 QObject *qlist_pop(QList *qlist);
 QObject *qlist_peek(QList *qlist);
 int qlist_empty(const QList *qlist);
+size_t qlist_size(const QList *qlist);
 QList *qobject_to_qlist(const QObject *obj);
 
 static inline const QListEntry *qlist_first(const QList *qlist)
-- 
1.7.9.5




[Qemu-devel] [PATCH for-1.2 v3 3/3] check-qjson: add test for large JSON objects

2012-08-15 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 tests/check-qjson.c |   53 +++
 1 file changed, 53 insertions(+)

diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index 526e25e..3b896f5 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -466,6 +466,58 @@ static void simple_dict(void)
 }
 }
 
+/*
+ * this generates json of the form:
+ * a(0,m) = [0, 1, ..., m-1]
+ * a(n,m) = {
+ *'key0': a(0,m),
+ *'key1': a(1,m),
+ *...
+ *'key(n-1)': a(n-1,m)
+ *  }
+ */
+static void gen_test_json(GString *gstr, int nest_level_max,
+  int elem_count)
+{
+int i;
+
+g_assert(gstr);
+if (nest_level_max == 0) {
+g_string_append(gstr, "[");
+for (i = 0; i < elem_count; i++) {
+g_string_append_printf(gstr, "%d", i);
+if (i < elem_count - 1) {
+g_string_append_printf(gstr, ", ");
+}
+}
+g_string_append(gstr, "]");
+return;
+}
+
+g_string_append(gstr, "{");
+for (i = 0; i < nest_level_max; i++) {
+g_string_append_printf(gstr, "'key%d': ", i);
+gen_test_json(gstr, i, elem_count);
+if (i < nest_level_max - 1) {
+g_string_append(gstr, ",");
+}
+}
+g_string_append(gstr, "}");
+}
+
+static void large_dict(void)
+{
+GString *gstr = g_string_new("");
+QObject *obj;
+
+gen_test_json(gstr, 10, 100);
+obj = qobject_from_json(gstr->str);
+g_assert(obj != NULL);
+
+qobject_decref(obj);
+g_string_free(gstr, true);
+}
+
 static void simple_list(void)
 {
 int i;
@@ -706,6 +758,7 @@ int main(int argc, char **argv)
 g_test_add_func("/literals/keyword", keyword_literal);
 
 g_test_add_func("/dicts/simple_dict", simple_dict);
+g_test_add_func("/dicts/large_dict", large_dict);
 g_test_add_func("/lists/simple_list", simple_list);
 
 g_test_add_func("/whitespace/simple_whitespace", simple_whitespace);
-- 
1.7.9.5




[Qemu-devel] [PATCH for-1.2 v3 2/3] json-parser: don't replicate tokens at each level of recursion

2012-08-15 Thread Michael Roth
Currently, when parsing a stream of tokens we make a copy of the token
list at the beginning of each level of recursion so that we do not
modify the original list in cases where we need to fall back to an
earlier state.

In the worst case, we will only read 1 or 2 tokens off the list before
recursing again, which means an upper bound of roughly N^2 token allocations.

For a "reasonably" sized QMP request (in this a QMP representation of
cirrus_vga's device state, generated via QIDL, being passed in via
qom-set), this caused my 16GB's of memory to be exhausted before any
noticeable progress was made by the parser.

This patch works around the issue by using single copy of the token list
in the form of an indexable array so that we can save/restore state by
manipulating indices.

A subsequent commit adds a "large_dict" test case which exhibits the
same behavior as above. With this patch applied the test case successfully
completes in under a second.

Tested with valgrind, make check, and QMP.

Signed-off-by: Michael Roth 
---
 json-parser.c |  230 +++--
 1 file changed, 142 insertions(+), 88 deletions(-)

diff --git a/json-parser.c b/json-parser.c
index 849e215..457291b 100644
--- a/json-parser.c
+++ b/json-parser.c
@@ -27,6 +27,11 @@
 typedef struct JSONParserContext
 {
 Error *err;
+struct {
+QObject **buf;
+size_t pos;
+size_t count;
+} tokens;
 } JSONParserContext;
 
 #define BUG_ON(cond) assert(!(cond))
@@ -40,7 +45,7 @@ typedef struct JSONParserContext
  * 4) deal with premature EOI
  */
 
-static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list 
*ap);
+static QObject *parse_value(JSONParserContext *ctxt, va_list *ap);
 
 /**
  * Token manipulators
@@ -270,27 +275,111 @@ out:
 return NULL;
 }
 
+static QObject *parser_context_pop_token(JSONParserContext *ctxt)
+{
+QObject *token;
+g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+token = ctxt->tokens.buf[ctxt->tokens.pos];
+ctxt->tokens.pos++;
+return token;
+}
+
+/* Note: parser_context_{peek|pop}_token do not increment the
+ * token object's refcount. In both cases the references will continue
+ * to be tracked and cleaned up in parser_context_free(), so do not
+ * attempt to free the token object.
+ */
+static QObject *parser_context_peek_token(JSONParserContext *ctxt)
+{
+QObject *token;
+g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+token = ctxt->tokens.buf[ctxt->tokens.pos];
+return token;
+}
+
+static JSONParserContext parser_context_save(JSONParserContext *ctxt)
+{
+JSONParserContext saved_ctxt = {0};
+saved_ctxt.tokens.pos = ctxt->tokens.pos;
+saved_ctxt.tokens.count = ctxt->tokens.count;
+saved_ctxt.tokens.buf = ctxt->tokens.buf;
+return saved_ctxt;
+}
+
+static void parser_context_restore(JSONParserContext *ctxt,
+   JSONParserContext saved_ctxt)
+{
+ctxt->tokens.pos = saved_ctxt.tokens.pos;
+ctxt->tokens.count = saved_ctxt.tokens.count;
+ctxt->tokens.buf = saved_ctxt.tokens.buf;
+}
+
+static void tokens_append_from_iter(QObject *obj, void *opaque)
+{
+JSONParserContext *ctxt = opaque;
+g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+ctxt->tokens.buf[ctxt->tokens.pos++] = obj;
+qobject_incref(obj);
+}
+
+static JSONParserContext *parser_context_new(QList *tokens)
+{
+JSONParserContext *ctxt;
+size_t count;
+
+if (!tokens) {
+return NULL;
+}
+
+count = qlist_size(tokens);
+if (count == 0) {
+return NULL;
+}
+
+ctxt = g_malloc0(sizeof(JSONParserContext));
+ctxt->tokens.pos = 0;
+ctxt->tokens.count = count;
+ctxt->tokens.buf = g_malloc(count * sizeof(QObject *));
+qlist_iter(tokens, tokens_append_from_iter, ctxt);
+ctxt->tokens.pos = 0;
+
+return ctxt;
+}
+
+/* to support error propagation, ctxt->err must be freed separately */
+static void parser_context_free(JSONParserContext *ctxt)
+{
+int i;
+if (ctxt) {
+for (i = 0; i < ctxt->tokens.count; i++) {
+qobject_decref(ctxt->tokens.buf[i]);
+}
+g_free(ctxt->tokens.buf);
+g_free(ctxt);
+}
+}
+
 /**
  * Parsing rules
  */
-static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, 
va_list *ap)
+static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
 {
 QObject *key = NULL, *token = NULL, *value, *peek;
-QList *working = qlist_copy(*tokens);
+JSONParserContext saved_ctxt = parser_context_save(ctxt);
 
-peek = qlist_peek(working);
+peek = parser_context_peek_token(ctxt);
 if (peek == NULL) {
 parse_error(ctxt, NULL, "premature EOI");
 goto out;
 }
 
-key = parse_value(ctxt, &working, ap);
+key = parse_value(ctxt, ap

Re: [Qemu-devel] [PATCH for-1.2 v3 1/3] qlist: add qlist_size()

2012-08-15 Thread Michael Roth
On Wed, Aug 15, 2012 at 01:52:33PM -0600, Eric Blake wrote:
> On 08/15/2012 12:45 PM, Michael Roth wrote:
> > Signed-off-by: Michael Roth 
> > ---
> >  qlist.c |   13 +
> >  qlist.h |1 +
> >  2 files changed, 14 insertions(+)
> 
> No cover-letter?

Started off as 1 patch with the explanation in the commit

> 
> Reviewed-by: Eric Blake 
> 
> -- 
> Eric Blake   ebl...@redhat.com+1-919-301-3266
> Libvirt virtualization library http://libvirt.org
> 





Re: [Qemu-devel] [PATCH for-1.2 v3 2/3] json-parser: don't replicate tokens at each level of recursion

2012-08-15 Thread Michael Roth
On Wed, Aug 15, 2012 at 02:04:52PM -0600, Eric Blake wrote:
> On 08/15/2012 12:45 PM, Michael Roth wrote:
> > Currently, when parsing a stream of tokens we make a copy of the token
> > list at the beginning of each level of recursion so that we do not
> > modify the original list in cases where we need to fall back to an
> > earlier state.
> > 
> > In the worst case, we will only read 1 or 2 tokens off the list before
> > recursing again, which means an upper bound of roughly N^2 token 
> > allocations.
> > 
> > For a "reasonably" sized QMP request (in this a QMP representation of
> > cirrus_vga's device state, generated via QIDL, being passed in via
> > qom-set), this caused my 16GB's of memory to be exhausted before any
> > noticeable progress was made by the parser.
> > 
> > This patch works around the issue by using single copy of the token list
> > in the form of an indexable array so that we can save/restore state by
> > manipulating indices.
> > 
> > A subsequent commit adds a "large_dict" test case which exhibits the
> > same behavior as above. With this patch applied the test case successfully
> > completes in under a second.
> > 
> > Tested with valgrind, make check, and QMP.
> > 
> > Signed-off-by: Michael Roth 
> > ---
> >  json-parser.c |  230 
> > +++--
> >  1 file changed, 142 insertions(+), 88 deletions(-)
> 
> I'm not the most familiar with this code, so take my review with a grain
> of salt, but I read through it and the transformation looks sane (and my
> non-code findings from v2 were fixed).
> 
> Reviewed-by: Eric Blake 
> 
> > +static JSONParserContext parser_context_save(JSONParserContext *ctxt)
> > +{
> > +JSONParserContext saved_ctxt = {0};
> > +saved_ctxt.tokens.pos = ctxt->tokens.pos;
> > +saved_ctxt.tokens.count = ctxt->tokens.count;
> > +saved_ctxt.tokens.buf = ctxt->tokens.buf;
> 
> Is it any simpler to condense 3 lines to 1:
> 
> saved_cts.tokens = ctxt->tokens;
> 
> > +return saved_ctxt;
> > +}
> > +
> > +static void parser_context_restore(JSONParserContext *ctxt,
> > +   JSONParserContext saved_ctxt)
> > +{
> > +ctxt->tokens.pos = saved_ctxt.tokens.pos;
> > +ctxt->tokens.count = saved_ctxt.tokens.count;
> > +ctxt->tokens.buf = saved_ctxt.tokens.buf;
> 
> and again, ctxt->tokens = saved_ctxt.tokens;

Poor function naming: save/restore apply to the token state, the other
fields in ctxt are unused, so I opted to set the fields explicitly.

Can probably make this read a little better by breaking token state off
into it's own struct, but I think we can clean that up later.

Thanks for the review!

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





Re: [Qemu-devel] [PATCH for-1.2 v3 2/3] json-parser: don't replicate tokens at each level of recursion

2012-08-16 Thread Michael Roth
On Thu, Aug 16, 2012 at 11:11:26AM -0300, Luiz Capitulino wrote:
> On Wed, 15 Aug 2012 13:45:43 -0500
> Michael Roth  wrote:
> 
> > Currently, when parsing a stream of tokens we make a copy of the token
> > list at the beginning of each level of recursion so that we do not
> > modify the original list in cases where we need to fall back to an
> > earlier state.
> > 
> > In the worst case, we will only read 1 or 2 tokens off the list before
> > recursing again, which means an upper bound of roughly N^2 token 
> > allocations.
> > 
> > For a "reasonably" sized QMP request (in this a QMP representation of
> > cirrus_vga's device state, generated via QIDL, being passed in via
> > qom-set), this caused my 16GB's of memory to be exhausted before any
> > noticeable progress was made by the parser.
> > 
> > This patch works around the issue by using single copy of the token list
> > in the form of an indexable array so that we can save/restore state by
> > manipulating indices.
> > 
> > A subsequent commit adds a "large_dict" test case which exhibits the
> > same behavior as above. With this patch applied the test case successfully
> > completes in under a second.
> > 
> > Tested with valgrind, make check, and QMP.
> > 
> > Signed-off-by: Michael Roth 
> > ---
> >  json-parser.c |  230 
> > +++--
> >  1 file changed, 142 insertions(+), 88 deletions(-)
> > 
> > diff --git a/json-parser.c b/json-parser.c
> > index 849e215..457291b 100644
> > --- a/json-parser.c
> > +++ b/json-parser.c
> > @@ -27,6 +27,11 @@
> >  typedef struct JSONParserContext
> >  {
> >  Error *err;
> > +struct {
> > +QObject **buf;
> > +size_t pos;
> > +size_t count;
> > +} tokens;
> >  } JSONParserContext;
> >  
> >  #define BUG_ON(cond) assert(!(cond))
> > @@ -40,7 +45,7 @@ typedef struct JSONParserContext
> >   * 4) deal with premature EOI
> >   */
> >  
> > -static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, 
> > va_list *ap);
> > +static QObject *parse_value(JSONParserContext *ctxt, va_list *ap);
> >  
> >  /**
> >   * Token manipulators
> > @@ -270,27 +275,111 @@ out:
> >  return NULL;
> >  }
> >  
> > +static QObject *parser_context_pop_token(JSONParserContext *ctxt)
> > +{
> > +QObject *token;
> > +g_assert(ctxt->tokens.pos < ctxt->tokens.count);
> > +token = ctxt->tokens.buf[ctxt->tokens.pos];
> > +ctxt->tokens.pos++;
> 
> Shouldn't pos be decremented instead? Haven't tried it yet to confirm, but
> if I'm right I can fix it myself (unless this requires fixes in other areas).
> 

No that's intentional, since qlist_pop() (which this replaces) actually "pops"
from the beginning of the list. So in this case we make the next element the
new "head" by simply incrementing the starting position (so it's easy to roll
back later).

> > +return token;
> > +}
> > +
> > +/* Note: parser_context_{peek|pop}_token do not increment the
> > + * token object's refcount. In both cases the references will continue
> > + * to be tracked and cleaned up in parser_context_free(), so do not
> > + * attempt to free the token object.
> > + */
> > +static QObject *parser_context_peek_token(JSONParserContext *ctxt)
> > +{
> > +QObject *token;
> > +g_assert(ctxt->tokens.pos < ctxt->tokens.count);
> > +token = ctxt->tokens.buf[ctxt->tokens.pos];
> > +return token;
> > +}
> > +
> > +static JSONParserContext parser_context_save(JSONParserContext *ctxt)
> > +{
> > +JSONParserContext saved_ctxt = {0};
> > +saved_ctxt.tokens.pos = ctxt->tokens.pos;
> > +saved_ctxt.tokens.count = ctxt->tokens.count;
> > +saved_ctxt.tokens.buf = ctxt->tokens.buf;
> > +return saved_ctxt;
> > +}
> > +
> > +static void parser_context_restore(JSONParserContext *ctxt,
> > +   JSONParserContext saved_ctxt)
> > +{
> > +ctxt->tokens.pos = saved_ctxt.tokens.pos;
> > +ctxt->tokens.count = saved_ctxt.tokens.count;
> > +ctxt->tokens.buf = saved_ctxt.tokens.buf;
> > +}
> > +
> > +static void tokens_append_from_iter(QObject *obj, void *opaque)
> > +{
> > +JSONParserContext *ctxt = opaque;
> > +g_assert(ctxt->tokens.pos < ctxt-

Re: [Qemu-devel] [PATCH for-1.2 v3 1/3] qlist: add qlist_size()

2012-08-16 Thread Michael Roth
On Thu, Aug 16, 2012 at 10:40:05AM -0300, Luiz Capitulino wrote:
> On Wed, 15 Aug 2012 13:45:42 -0500
> Michael Roth  wrote:
> 
> > 
> > Signed-off-by: Michael Roth 
> 
> I've applied this series to the qmp branch for 1.2. I'll run some tests and if
> all goes alright will send a pull request shortly.
> 

I just noticed via our fancy #qemu github bot that Anthony
applied these already, but I asked about and if you want to
test/submit through your queue it should all work out. So either
way.

Thanks!

> > ---
> >  qlist.c |   13 +
> >  qlist.h |1 +
> >  2 files changed, 14 insertions(+)
> > 
> > diff --git a/qlist.c b/qlist.c
> > index 88498b1..b48ec5b 100644
> > --- a/qlist.c
> > +++ b/qlist.c
> > @@ -124,6 +124,19 @@ int qlist_empty(const QList *qlist)
> >  return QTAILQ_EMPTY(&qlist->head);
> >  }
> >  
> > +static void qlist_size_iter(QObject *obj, void *opaque)
> > +{
> > +size_t *count = opaque;
> > +(*count)++;
> > +}
> > +
> > +size_t qlist_size(const QList *qlist)
> > +{
> > +size_t count = 0;
> > +qlist_iter(qlist, qlist_size_iter, &count);
> > +return count;
> > +}
> > +
> >  /**
> >   * qobject_to_qlist(): Convert a QObject into a QList
> >   */
> > diff --git a/qlist.h b/qlist.h
> > index d426bd4..ae776f9 100644
> > --- a/qlist.h
> > +++ b/qlist.h
> > @@ -49,6 +49,7 @@ void qlist_iter(const QList *qlist,
> >  QObject *qlist_pop(QList *qlist);
> >  QObject *qlist_peek(QList *qlist);
> >  int qlist_empty(const QList *qlist);
> > +size_t qlist_size(const QList *qlist);
> >  QList *qobject_to_qlist(const QObject *obj);
> >  
> >  static inline const QListEntry *qlist_first(const QList *qlist)
> 



Re: [Qemu-devel] qemu-ga : Guest Agent : Windows 2008 : Unknown command guest-fsfreeze-freeze

2012-08-20 Thread Michael Roth
On Mon, Aug 20, 2012 at 10:54:29AM -0300, Luiz Capitulino wrote:
> On Fri, 17 Aug 2012 10:11:29 -0700 (PDT)
> desi babu  wrote:
> 
> > Guest-Agent : Windows 2008 Error : Relase 1.1.90
> > 
> > error : internal error unable to execute QEMU command 
> > 'guest-fsfreeze-freeze': this feature or command is not currently supported.
> 
> That's correct, fsfreze is not supported on Windows.
> 
> > Guest-info shows the command is available.  Is there any information 
> > available on the list of commands supported inside Windows ? Appreciate if 
> > you have any pointers.
> 
> That's a qemu-ga bug. CC'ing Michael to check if he has a fix in mind for 
> this.
> 

I've been thinking about this one for a while. It's considered expected
behavior, but I realize it sucks for discoverability. I doubt we want to
do platform-specific QAPI schema definitions, so the only option I can
think of is some kind of [de-]registration mechanism where we can mark
commands as being not available for a particular build/platform in the
cases where we stub out command implementations.

I think we can expose this to existing clients by no longer listing commands
marked as unsupported in the list provided by the guest-info command. It
should "just work". Can probably do it for 1.3. For now, clients will
have to catch it in the error-handling path.



Re: [Qemu-devel] [Bug 1038070] [NEW] > qemu-kvm-1.1.1-r1 - USB activkey doesn't work anymore

2012-08-20 Thread Michael Roth
On Fri, Aug 17, 2012 at 12:50:14PM -, linuxale wrote:
> Public bug reported:
> 
> Linux Distro: Gentoo
> 
> Smartcard Activkey doesn't work anymore. I use it without problem till version
> qemu-kvm-1.0.1.
> 
> Follow a log extraction:
> 2012-08-14 16:27:34.751+: 5487: error : qemuProcessReadLogOutput:1298 :
> internal error Process exited while reading console log output: char device
> redirected to /dev/pts/40
> ccid-card-emulated: failed to initialize vcard
> qemu-system-x86_64: -device
> ccid-card-emulated,backend=nss-emulated,id=smartcard0,bus=ccid0.0: Device
> 'ccid-card-emulated' could not be initialized
> 
> 2012-08-14 16:28:01.018+: 5486: error : qemuProcessReadLogOutput:1298 :
> internal error Process exited while reading console log output: char device
> redirected to /dev/pts/40
> ccid-card-emulated: failed to initialize vcard
> qemu-system-x86_64: -device
> ccid-card-emulated,backend=nss-emulated,id=smartcard0,bus=ccid0.0: Device
> 'ccid-card-emulated' could not be initialized
> 
> If you need any other info please tell me.

I've tried 1.1.1 and current upstream with a Windows 7 guest and the
device seems to show up and function properly in both cases.

One way that I *can* reproduce the error is by running your command-line
with an NSS database at some place other than the default search path
(/etc/pki/nssdb in 1.1 and upstream). I don't think this has changed
since 1.0, but maybe something changed on the distro side?

Can you try reproducing by compiling from upstream source?

> 
> I've tried with git version with same problem.
> 
> ** Affects: qemu
>  Importance: Undecided
>  Status: New
> 
> -- 
> You received this bug notification because you are a member of qemu-
> devel-ml, which is subscribed to QEMU.
> https://bugs.launchpad.net/bugs/1038070
> 
> Title:
>   > qemu-kvm-1.1.1-r1 - USB activkey doesn't work anymore
> 
> Status in QEMU:
>   New
> 
> Bug description:
>   Linux Distro: Gentoo
> 
>   Smartcard Activkey doesn't work anymore. I use it without problem till 
> version
>   qemu-kvm-1.0.1.
> 
>   Follow a log extraction:
>   2012-08-14 16:27:34.751+: 5487: error : qemuProcessReadLogOutput:1298 :
>   internal error Process exited while reading console log output: char device
>   redirected to /dev/pts/40
>   ccid-card-emulated: failed to initialize vcard
>   qemu-system-x86_64: -device
>   ccid-card-emulated,backend=nss-emulated,id=smartcard0,bus=ccid0.0: Device
>   'ccid-card-emulated' could not be initialized
> 
>   2012-08-14 16:28:01.018+: 5486: error : qemuProcessReadLogOutput:1298 :
>   internal error Process exited while reading console log output: char device
>   redirected to /dev/pts/40
>   ccid-card-emulated: failed to initialize vcard
>   qemu-system-x86_64: -device
>   ccid-card-emulated,backend=nss-emulated,id=smartcard0,bus=ccid0.0: Device
>   'ccid-card-emulated' could not be initialized
> 
>   If you need any other info please tell me.
> 
>   I've tried with git version with same problem.
> 
> To manage notifications about this bug go to:
> https://bugs.launchpad.net/qemu/+bug/1038070/+subscriptions
> 



Re: [Qemu-devel] [PATCH for-1.2 v3] qemu-ga: report success-response field in guest-info

2012-08-21 Thread Michael Roth
On Tue, Aug 21, 2012 at 02:39:35PM +0200, Michal Privoznik wrote:
> This is a useful hint for users (or libvirt) whether a command returns
> anything success and hence wait for reply or not.

I'm not necessarilly against this patch, but I think we should clarify it's
purpose.

Commands that don't return success should still be "waited" on, since
they may still return an error. You can only stop waiting once you
recieve an error, a client-side timeout, or some "external" indicator
in the case of things like shutdown and suspend.

For guest-suspend*, this has always been the case, so there's no reason
to probe for their behavior.

For guest-shutdown, the semantics did change, but were considered
backward-compatible in that the new behavior would trigger a
client-side timeout for older clients, which was always a required
aspect of the protocol (since it's a connectionless protocol, possibly
malicious agent, etc), and the success response was always documented as
async and do-nothing.

So we only need to worry about how new clients deal with guest-shutdown,
Specifically, whether or not we will get a success response from the
agent. But since the success response was always meaningless, why
couldn't we just throw it away and continue waiting for a shutdown event
from QMP, or querying query-status for runstate change?

Would this solve the ambiguity? If so, we can get just update the
guest-shutdown documentation to detail how to handle "success" responses from
older agents (ignore them, basically). I think this is a nicer way to
handle newer clients than adding more things to probe for.

> ---
> diff to v2:
> -fixed typo and field description
> 
> diff to v1:
> -changed condition in qmp_command_reports_success per Paolo's advice
> 
>  qapi-schema-guest.json |6 +-
>  qapi/qmp-core.h|1 +
>  qapi/qmp-registry.c|   12 
>  qga/commands.c |1 +
>  4 files changed, 19 insertions(+), 1 deletions(-)
> 
> diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json
> index d955cf1..60872e5 100644
> --- a/qapi-schema-guest.json
> +++ b/qapi-schema-guest.json
> @@ -91,10 +91,14 @@
>  #
>  # @enabled: whether command is currently enabled by guest admin
>  #
> +# @success-response: true unless the command does not respond on success
> +#See 'guest-shutdown' command for more detailed info.
> +#
>  # Since 1.1.0
>  ##
>  { 'type': 'GuestAgentCommandInfo',
> -  'data': { 'name': 'str', 'enabled': 'bool' } }
> +  'data': { 'name': 'str', 'enabled': 'bool',
> +'success-response': 'bool'} }
> 
>  ##
>  # @GuestAgentInfo
> diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
> index 00446cf..271c3f2 100644
> --- a/qapi/qmp-core.h
> +++ b/qapi/qmp-core.h
> @@ -48,6 +48,7 @@ QObject *qmp_dispatch(QObject *request);
>  void qmp_disable_command(const char *name);
>  void qmp_enable_command(const char *name);
>  bool qmp_command_is_enabled(const char *name);
> +bool qmp_command_reports_success(const char *name);
>  char **qmp_get_command_list(void);
>  QObject *qmp_build_error_object(Error *errp);
> 
> diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
> index 5414613..3f7303c 100644
> --- a/qapi/qmp-registry.c
> +++ b/qapi/qmp-registry.c
> @@ -77,6 +77,18 @@ bool qmp_command_is_enabled(const char *name)
>  return false;
>  }
> 
> +bool qmp_command_reports_success(const char *name) {
> +QmpCommand *cmd;
> +
> +QTAILQ_FOREACH(cmd, &qmp_commands, node) {
> +if (strcmp(cmd->name, name) == 0) {
> +return (cmd->options & QCO_NO_SUCCESS_RESP) == 0;
> +}
> +}
> +
> +return true;
> +}
> +
>  char **qmp_get_command_list(void)
>  {
>  QmpCommand *cmd;
> diff --git a/qga/commands.c b/qga/commands.c
> index 46b0b08..9811221 100644
> --- a/qga/commands.c
> +++ b/qga/commands.c
> @@ -63,6 +63,7 @@ struct GuestAgentInfo *qmp_guest_info(Error **err)
>  cmd_info = g_malloc0(sizeof(GuestAgentCommandInfo));
>  cmd_info->name = strdup(*cmd_list);
>  cmd_info->enabled = qmp_command_is_enabled(cmd_info->name);
> +cmd_info->success_response = 
> qmp_command_reports_success(cmd_info->name);
> 
>  cmd_info_list = g_malloc0(sizeof(GuestAgentCommandInfoList));
>  cmd_info_list->value = cmd_info;
> -- 
> 1.7.8.6
> 
> 



[Qemu-devel] [PATCH for-1.2] libcacard: Fix segfault when no backend specified

2012-08-21 Thread Michael Roth
When a user does not specify a backend, a segfault can be triggered due
to a strcmp() being called on a NULL char*:

$ gdb --args qemu -usb -device usb-ccid \
  -device ccid-card-emulated,id=smartcard0 \
  ...

(gdb) s
emulated_initfn (base=0x56cb2e70) at
/home/mdroth/w/qemu.git/hw/ccid-card-emulated.c:503
503 card->backend = parse_enumeration(card->backend_str,
backend_enum_table, 0);
(gdb) s
parse_enumeration (not_found_value=0, table=0x55b9b3c0, str=0x0) at
/home/mdroth/w/qemu.git/hw/ccid-card-emulated.c:476
476 while (table->name != NULL) {
(gdb) s
477 if (strcmp(table->name, str) == 0) {
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x760df09a in ?? () from /lib/x86_64-linux-gnu/libc.so.6

After the fix:

$ qemu -usb -device usb-ccid \
 -device ccid-card-emulated,id=smartcard0 \
 ...
unknown backend, must be one of:
nss-emulated
certificates
qemu-system-x86_64: -device
ccid-card-emulated,id=smartcard0,backend=nss-certificates: Device
'ccid-card-emulated' could not be initialized

Signed-off-by: Michael Roth 
---
 hw/ccid-card-emulated.c |3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
index f4a6da4..740e8df 100644
--- a/hw/ccid-card-emulated.c
+++ b/hw/ccid-card-emulated.c
@@ -473,6 +473,9 @@ static uint32_t parse_enumeration(char *str,
 {
 uint32_t ret = not_found_value;
 
+if (!str) {
+return ret;
+}
 while (table->name != NULL) {
 if (strcmp(table->name, str) == 0) {
 ret = table->value;
-- 
1.7.9.5




[Qemu-devel] [PATCH 16/23] check-qjson: add test for large JSON objects

2012-08-21 Thread Michael Roth
Signed-off-by: Michael Roth 
Signed-off-by: Anthony Liguori 
(cherry picked from commit 7109edfeb69c1d3c2164175837784dfcd210fed0)

Signed-off-by: Michael Roth 
---
 tests/check-qjson.c |   53 +++
 1 file changed, 53 insertions(+)

diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index 526e25e..3b896f5 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -466,6 +466,58 @@ static void simple_dict(void)
 }
 }
 
+/*
+ * this generates json of the form:
+ * a(0,m) = [0, 1, ..., m-1]
+ * a(n,m) = {
+ *'key0': a(0,m),
+ *'key1': a(1,m),
+ *...
+ *'key(n-1)': a(n-1,m)
+ *  }
+ */
+static void gen_test_json(GString *gstr, int nest_level_max,
+  int elem_count)
+{
+int i;
+
+g_assert(gstr);
+if (nest_level_max == 0) {
+g_string_append(gstr, "[");
+for (i = 0; i < elem_count; i++) {
+g_string_append_printf(gstr, "%d", i);
+if (i < elem_count - 1) {
+g_string_append_printf(gstr, ", ");
+}
+}
+g_string_append(gstr, "]");
+return;
+}
+
+g_string_append(gstr, "{");
+for (i = 0; i < nest_level_max; i++) {
+g_string_append_printf(gstr, "'key%d': ", i);
+gen_test_json(gstr, i, elem_count);
+if (i < nest_level_max - 1) {
+g_string_append(gstr, ",");
+}
+}
+g_string_append(gstr, "}");
+}
+
+static void large_dict(void)
+{
+GString *gstr = g_string_new("");
+QObject *obj;
+
+gen_test_json(gstr, 10, 100);
+obj = qobject_from_json(gstr->str);
+g_assert(obj != NULL);
+
+qobject_decref(obj);
+g_string_free(gstr, true);
+}
+
 static void simple_list(void)
 {
 int i;
@@ -706,6 +758,7 @@ int main(int argc, char **argv)
 g_test_add_func("/literals/keyword", keyword_literal);
 
 g_test_add_func("/dicts/simple_dict", simple_dict);
+g_test_add_func("/dicts/large_dict", large_dict);
 g_test_add_func("/lists/simple_list", simple_list);
 
 g_test_add_func("/whitespace/simple_whitespace", simple_whitespace);
-- 
1.7.9.5




[Qemu-devel] [PATCH 02/23] configure: Don't override user's --cpu on MacOS and Solaris

2012-08-21 Thread Michael Roth
From: Peter Maydell 

Both MacOS and Solaris have special case handling for the CPU
type, because the check_define probes will return i386 even if
the hardware is 64 bit and x86_64 would be preferable. Move
these checks earlier in the configure probing so that we can
do them only if the user didn't specify a CPU with --cpu. This
fixes a bug where the user's command line argument was being
ignored.

Reviewed-by: Andreas F=E4rber 
Signed-off-by: Peter Maydell 
Signed-off-by: Anthony Liguori 
(cherry picked from commit bbea4050802a2e7e0296a21823c0925782c02b93)

Signed-off-by: Michael Roth 
---
 configure |   60 +++-
 1 file changed, 35 insertions(+), 25 deletions(-)

diff --git a/configure b/configure
index 72d16a4..df29c2f 100755
--- a/configure
+++ b/configure
@@ -275,6 +275,41 @@ EOF
   compile_object
 }
 
+if check_define __linux__ ; then
+  targetos="Linux"
+elif check_define _WIN32 ; then
+  targetos='MINGW32'
+elif check_define __OpenBSD__ ; then
+  targetos='OpenBSD'
+elif check_define __sun__ ; then
+  targetos='SunOS'
+elif check_define __HAIKU__ ; then
+  targetos='Haiku'
+else
+  targetos=`uname -s`
+fi
+
+# Some host OSes need non-standard checks for which CPU to use.
+# Note that these checks are broken for cross-compilation: if you're
+# cross-compiling to one of these OSes then you'll need to specify
+# the correct CPU with the --cpu option.
+case $targetos in
+Darwin)
+  # on Leopard most of the system is 32-bit, so we have to ask the kernel if 
we can
+  # run 64-bit userspace code.
+  # If the user didn't specify a CPU explicitly and the kernel says this is
+  # 64 bit hw, then assume x86_64. Otherwise fall through to the usual 
detection code.
+  if test -z "$cpu" && test "$(sysctl -n hw.optional.x86_64)" = "1"; then
+cpu="x86_64"
+  fi
+  ;;
+SunOS)
+  # `uname -m` returns i86pc even on an x86_64 box, so default based on isainfo
+  if test -z "$cpu" && test "$(isainfo -k)" = "amd64"; then
+cpu="x86_64"
+  fi
+esac
+
 if test ! -z "$cpu" ; then
   # command line argument
   :
@@ -349,19 +384,6 @@ if test -z "$ARCH"; then
 fi
 
 # OS specific
-if check_define __linux__ ; then
-  targetos="Linux"
-elif check_define _WIN32 ; then
-  targetos='MINGW32'
-elif check_define __OpenBSD__ ; then
-  targetos='OpenBSD'
-elif check_define __sun__ ; then
-  targetos='SunOS'
-elif check_define __HAIKU__ ; then
-  targetos='Haiku'
-else
-  targetos=`uname -s`
-fi
 
 case $targetos in
 CYGWIN*)
@@ -411,12 +433,6 @@ OpenBSD)
 Darwin)
   bsd="yes"
   darwin="yes"
-  # on Leopard most of the system is 32-bit, so we have to ask the kernel it 
if we can
-  # run 64-bit userspace code
-  if [ "$cpu" = "i386" ] ; then
-is_x86_64=`sysctl -n hw.optional.x86_64`
-[ "$is_x86_64" = "1" ] && cpu=x86_64
-  fi
   if [ "$cpu" = "x86_64" ] ; then
 QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS"
 LDFLAGS="-arch x86_64 $LDFLAGS"
@@ -437,12 +453,6 @@ SunOS)
   smbd="${SMBD-/usr/sfw/sbin/smbd}"
   needs_libsunmath="no"
   solarisrev=`uname -r | cut -f2 -d.`
-  # have to select again, because `uname -m` returns i86pc
-  # even on an x86_64 box.
-  solariscpu=`isainfo -k`
-  if test "${solariscpu}" = "amd64" ; then
-cpu="x86_64"
-  fi
   if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
 if test "$solarisrev" -le 9 ; then
   if test -f /opt/SUNWspro/prod/lib/libsunmath.so.1; then
-- 
1.7.9.5




[Qemu-devel] [PATCH 23/23] update VERSION for 1.1.2

2012-08-21 Thread Michael Roth
Signed-off-by: Michael Roth 
---
 VERSION |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/VERSION b/VERSION
index 524cb55..45a1b3f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.1
+1.1.2
-- 
1.7.9.5




[Qemu-devel] [PATCH 15/23] json-parser: don't replicate tokens at each level of recursion

2012-08-21 Thread Michael Roth
Currently, when parsing a stream of tokens we make a copy of the token
list at the beginning of each level of recursion so that we do not
modify the original list in cases where we need to fall back to an
earlier state.

In the worst case, we will only read 1 or 2 tokens off the list before
recursing again, which means an upper bound of roughly N^2 token allocations.

For a "reasonably" sized QMP request (in this a QMP representation of
cirrus_vga's device state, generated via QIDL, being passed in via
qom-set), this caused my 16GB's of memory to be exhausted before any
noticeable progress was made by the parser.

This patch works around the issue by using single copy of the token list
in the form of an indexable array so that we can save/restore state by
manipulating indices.

A subsequent commit adds a "large_dict" test case which exhibits the
same behavior as above. With this patch applied the test case successfully
completes in under a second.

Tested with valgrind, make check, and QMP.

Reviewed-by: Eric Blake 
Signed-off-by: Michael Roth 
Signed-off-by: Anthony Liguori 
(cherry picked from commit 65c0f1e9558c7c762cdb333406243fff1d687117)

Signed-off-by: Michael Roth 
---
 json-parser.c |  230 +++--
 1 file changed, 142 insertions(+), 88 deletions(-)

diff --git a/json-parser.c b/json-parser.c
index 849e215..457291b 100644
--- a/json-parser.c
+++ b/json-parser.c
@@ -27,6 +27,11 @@
 typedef struct JSONParserContext
 {
 Error *err;
+struct {
+QObject **buf;
+size_t pos;
+size_t count;
+} tokens;
 } JSONParserContext;
 
 #define BUG_ON(cond) assert(!(cond))
@@ -40,7 +45,7 @@ typedef struct JSONParserContext
  * 4) deal with premature EOI
  */
 
-static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list 
*ap);
+static QObject *parse_value(JSONParserContext *ctxt, va_list *ap);
 
 /**
  * Token manipulators
@@ -270,27 +275,111 @@ out:
 return NULL;
 }
 
+static QObject *parser_context_pop_token(JSONParserContext *ctxt)
+{
+QObject *token;
+g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+token = ctxt->tokens.buf[ctxt->tokens.pos];
+ctxt->tokens.pos++;
+return token;
+}
+
+/* Note: parser_context_{peek|pop}_token do not increment the
+ * token object's refcount. In both cases the references will continue
+ * to be tracked and cleaned up in parser_context_free(), so do not
+ * attempt to free the token object.
+ */
+static QObject *parser_context_peek_token(JSONParserContext *ctxt)
+{
+QObject *token;
+g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+token = ctxt->tokens.buf[ctxt->tokens.pos];
+return token;
+}
+
+static JSONParserContext parser_context_save(JSONParserContext *ctxt)
+{
+JSONParserContext saved_ctxt = {0};
+saved_ctxt.tokens.pos = ctxt->tokens.pos;
+saved_ctxt.tokens.count = ctxt->tokens.count;
+saved_ctxt.tokens.buf = ctxt->tokens.buf;
+return saved_ctxt;
+}
+
+static void parser_context_restore(JSONParserContext *ctxt,
+   JSONParserContext saved_ctxt)
+{
+ctxt->tokens.pos = saved_ctxt.tokens.pos;
+ctxt->tokens.count = saved_ctxt.tokens.count;
+ctxt->tokens.buf = saved_ctxt.tokens.buf;
+}
+
+static void tokens_append_from_iter(QObject *obj, void *opaque)
+{
+JSONParserContext *ctxt = opaque;
+g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+ctxt->tokens.buf[ctxt->tokens.pos++] = obj;
+qobject_incref(obj);
+}
+
+static JSONParserContext *parser_context_new(QList *tokens)
+{
+JSONParserContext *ctxt;
+size_t count;
+
+if (!tokens) {
+return NULL;
+}
+
+count = qlist_size(tokens);
+if (count == 0) {
+return NULL;
+}
+
+ctxt = g_malloc0(sizeof(JSONParserContext));
+ctxt->tokens.pos = 0;
+ctxt->tokens.count = count;
+ctxt->tokens.buf = g_malloc(count * sizeof(QObject *));
+qlist_iter(tokens, tokens_append_from_iter, ctxt);
+ctxt->tokens.pos = 0;
+
+return ctxt;
+}
+
+/* to support error propagation, ctxt->err must be freed separately */
+static void parser_context_free(JSONParserContext *ctxt)
+{
+int i;
+if (ctxt) {
+for (i = 0; i < ctxt->tokens.count; i++) {
+qobject_decref(ctxt->tokens.buf[i]);
+}
+g_free(ctxt->tokens.buf);
+g_free(ctxt);
+}
+}
+
 /**
  * Parsing rules
  */
-static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, 
va_list *ap)
+static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
 {
 QObject *key = NULL, *token = NULL, *value, *peek;
-QList *working = qlist_copy(*tokens);
+JSONParserContext saved_ctxt = parser_context_save(ctxt);
 
-peek = qlist_peek(working);
+peek = parser_context_peek_token(ctxt);
 if (peek == NULL) {
   

[Qemu-devel] [PATCH 06/23] qdev: fix use-after-free in the error path of qdev_init_nofail

2012-08-21 Thread Michael Roth
From: Anthony Liguori 

>From Markus:

Before:

$ qemu-system-x86_64 -display none -drive if=ide
qemu-system-x86_64: Device needs media, but drive is empty
qemu-system-x86_64: Initialization of device ide-hd failed
[Exit 1 ]

After:

$ qemu-system-x86_64 -display none -drive if=ide
qemu-system-x86_64: Device needs media, but drive is empty
Segmentation fault (core dumped)
[Exit 139 (SIGSEGV)]

This error always existed as qdev_init() frees the object.  But QOM
goes a bit further and purposefully sets the class pointer to NULL to
help find use-after-free.  It worked :-)

Cc: Andreas Faerber 
Reported-by: Markus Armbruster 
Signed-off-by: Anthony Liguori 
(cherry picked from commit 7de3abe505e34398cef5bddf6c4d0bd9ee47007f)

Signed-off-by: Michael Roth 
---
 hw/qdev.c |5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/hw/qdev.c b/hw/qdev.c
index af419b9..8e8ca3f 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -256,9 +256,10 @@ int qdev_simple_unplug_cb(DeviceState *dev)
way is somewhat unclean, and best avoided.  */
 void qdev_init_nofail(DeviceState *dev)
 {
+const char *typename = object_get_typename(OBJECT(dev));
+
 if (qdev_init(dev) < 0) {
-error_report("Initialization of device %s failed",
- object_get_typename(OBJECT(dev)));
+error_report("Initialization of device %s failed", typename);
 exit(1);
 }
 }
-- 
1.7.9.5




[Qemu-devel] [PATCH 05/23] kvmvapic: Disable if there is insufficient memory

2012-08-21 Thread Michael Roth
From: Jan Kiszka 

We need at least 1M of RAM to map the option ROM. Otherwise, we will
corrupt host memory or even crash:

$ qemu-system-x86_64 -nodefaults --enable-kvm -vnc :0 -m 640k
Segmentation fault (core dumped)

Reported-and-tested-by: Markus Armbruster 
Signed-off-by: Jan Kiszka 
Signed-off-by: Marcelo Tosatti 
(cherry picked from commit a9605e0317c7a6d5e68f3a3b6708c8ef1096f4bc)

Signed-off-by: Michael Roth 
---
 hw/apic_common.c |4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/apic_common.c b/hw/apic_common.c
index 60b8259..e4612bb 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -289,7 +289,9 @@ static int apic_init_common(SysBusDevice *dev)
 
 sysbus_init_mmio(dev, &s->io_memory);
 
-if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK) {
+/* Note: We need at least 1M to map the VAPIC option ROM */
+if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
+ram_size >= 1024 * 1024) {
 vapic = sysbus_create_simple("kvmvapic", -1, NULL);
 }
 s->vapic = vapic;
-- 
1.7.9.5




[Qemu-devel] [PATCH 01/23] qtest: fix infinite loop when QEMU aborts abruptly

2012-08-21 Thread Michael Roth
From: Anthony Liguori 

>From Markus:

Makes "make check" hang:

QTEST_QEMU_BINARY=x86_64-softmmu/qemu-system-x86_64 gtester -k --verbose 
-m=quick tests/crash-test tests/rtc-test
TEST: tests/crash-test... (pid=972)
qemu-system-x86_64: Device needs media, but drive is empty
[Nothing happens, wait a while, then hit ^C]
make: *** [check-qtest-x86_64] Interrupt

This was due to the fact that we weren't checked for errors when
reading from the QMP socket.  This patch adds appropriate error
checking.

Reported-by: Markus Armbruster 
Signed-off-by: Anthony Liguori 
(cherry picked from commit 039380a8e18f618cdacf72486449c04dc1b70eef)

Signed-off-by: Michael Roth 
---
 tests/libqtest.c |5 +
 1 file changed, 5 insertions(+)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index 6d333ef..0664323 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -290,6 +290,11 @@ void qtest_qmp(QTestState *s, const char *fmt, ...)
 continue;
 }
 
+if (len == -1 || len == 0) {
+fprintf(stderr, "Broken pipe\n");
+exit(1);
+}
+
 switch (c) {
 case '{':
 nesting++;
-- 
1.7.9.5




[Qemu-devel] [PATCH 22/23] apic: Defer interrupt updates to VCPU thread

2012-08-21 Thread Michael Roth
From: Jan Kiszka 

KVM performs TPR raising asynchronously to QEMU, specifically outside
QEMU's global lock. When an interrupt is injected into the APIC and TPR
is checked to decide if this can be delivered, a stale TPR value may be
used, causing spurious interrupts in the end.

Fix this by deferring apic_update_irq to the context of the target VCPU.
We introduce a new interrupt flag for this, CPU_INTERRUPT_POLL. When it
is set, the VCPU calls apic_poll_irq before checking for further pending
interrupts. To avoid special-casing KVM, we also implement this logic
for TCG mode.

Signed-off-by: Jan Kiszka 
Signed-off-by: Avi Kivity 
(cherry picked from commit 5d62c43a17edaa7f6a88821c9086e6c8e0e5327d)

Signed-off-by: Michael Roth 
---
 cpu-exec.c |6 ++
 hw/apic.c  |5 -
 hw/apic.h  |1 +
 hw/apic_internal.h |1 -
 target-i386/cpu.h  |4 +++-
 target-i386/kvm.c  |4 
 6 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/cpu-exec.c b/cpu-exec.c
index 0344cd5..6db32cd 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -285,6 +285,12 @@ int cpu_exec(CPUArchState *env)
 }
 #endif
 #if defined(TARGET_I386)
+#if !defined(CONFIG_USER_ONLY)
+if (interrupt_request & CPU_INTERRUPT_POLL) {
+env->interrupt_request &= ~CPU_INTERRUPT_POLL;
+apic_poll_irq(env->apic_state);
+}
+#endif
 if (interrupt_request & CPU_INTERRUPT_INIT) {
 svm_check_intercept(env, SVM_EXIT_INIT);
 do_cpu_init(env);
diff --git a/hw/apic.c b/hw/apic.c
index e96402d..b2c6373 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -16,6 +16,7 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, see <http://www.gnu.org/licenses/>
  */
+#include "qemu-thread.h"
 #include "apic_internal.h"
 #include "apic.h"
 #include "ioapic.h"
@@ -369,7 +370,9 @@ static void apic_update_irq(APICCommonState *s)
 if (!(s->spurious_vec & APIC_SV_ENABLE)) {
 return;
 }
-if (apic_irq_pending(s) > 0) {
+if (!qemu_cpu_is_self(s->cpu_env)) {
+cpu_interrupt(s->cpu_env, CPU_INTERRUPT_POLL);
+} else if (apic_irq_pending(s) > 0) {
 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
 }
 }
diff --git a/hw/apic.h b/hw/apic.h
index 62179ce..a89542b 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -20,6 +20,7 @@ void apic_init_reset(DeviceState *s);
 void apic_sipi(DeviceState *s);
 void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
TPRAccess access);
+void apic_poll_irq(DeviceState *d);
 
 /* pc.c */
 int cpu_is_bsp(CPUX86State *env);
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
index 60a6a8b..4d8ff49 100644
--- a/hw/apic_internal.h
+++ b/hw/apic_internal.h
@@ -141,7 +141,6 @@ void apic_report_irq_delivered(int delivered);
 bool apic_next_timer(APICCommonState *s, int64_t current_time);
 void apic_enable_tpr_access_reporting(DeviceState *d, bool enable);
 void apic_enable_vapic(DeviceState *d, target_phys_addr_t paddr);
-void apic_poll_irq(DeviceState *d);
 
 void vapic_report_tpr_access(DeviceState *dev, void *cpu, target_ulong ip,
  TPRAccess access);
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 2460f63..8ff3f30 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -477,6 +477,7 @@
  for syscall instruction */
 
 /* i386-specific interrupt pending bits.  */
+#define CPU_INTERRUPT_POLL  CPU_INTERRUPT_TGT_EXT_1
 #define CPU_INTERRUPT_SMI   CPU_INTERRUPT_TGT_EXT_2
 #define CPU_INTERRUPT_NMI   CPU_INTERRUPT_TGT_EXT_3
 #define CPU_INTERRUPT_MCE   CPU_INTERRUPT_TGT_EXT_4
@@ -1029,7 +1030,8 @@ static inline void cpu_clone_regs(CPUX86State *env, 
target_ulong newsp)
 
 static inline bool cpu_has_work(CPUX86State *env)
 {
-return ((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+return ((env->interrupt_request & (CPU_INTERRUPT_HARD |
+   CPU_INTERRUPT_POLL)) &&
 (env->eflags & IF_MASK)) ||
(env->interrupt_request & (CPU_INTERRUPT_NMI |
   CPU_INTERRUPT_INIT |
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index e74a9e4..d8bbe4f 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1725,6 +1725,10 @@ int kvm_arch_process_async_events(CPUX86State *env)
 return 0;
 }
 
+if (env->interrupt_request & CPU_INTERRUPT_POLL) {
+env->interrupt_request &= ~CPU_INTERRUPT_POLL;
+apic_poll_irq(env->apic_state);
+}
 if (((env->interrupt_request & CPU_INTERRUPT_HARD) &&
  (env->eflags & IF_MASK)) ||
 (env->interrupt_request & CPU_INTERRUPT_NMI)) {
-- 
1.7.9.5




[Qemu-devel] [PATCH 14/23] qlist: add qlist_size()

2012-08-21 Thread Michael Roth
Signed-off-by: Michael Roth 
Reviewed-by: Eric Blake 
Signed-off-by: Michael Roth 
Signed-off-by: Anthony Liguori 
(cherry picked from commit a86a4c2f7b7f0b72816ea1c219d8140699b6665b)

Signed-off-by: Michael Roth 
---
 qlist.c |   13 +
 qlist.h |1 +
 2 files changed, 14 insertions(+)

diff --git a/qlist.c b/qlist.c
index 88498b1..b48ec5b 100644
--- a/qlist.c
+++ b/qlist.c
@@ -124,6 +124,19 @@ int qlist_empty(const QList *qlist)
 return QTAILQ_EMPTY(&qlist->head);
 }
 
+static void qlist_size_iter(QObject *obj, void *opaque)
+{
+size_t *count = opaque;
+(*count)++;
+}
+
+size_t qlist_size(const QList *qlist)
+{
+size_t count = 0;
+qlist_iter(qlist, qlist_size_iter, &count);
+return count;
+}
+
 /**
  * qobject_to_qlist(): Convert a QObject into a QList
  */
diff --git a/qlist.h b/qlist.h
index d426bd4..ae776f9 100644
--- a/qlist.h
+++ b/qlist.h
@@ -49,6 +49,7 @@ void qlist_iter(const QList *qlist,
 QObject *qlist_pop(QList *qlist);
 QObject *qlist_peek(QList *qlist);
 int qlist_empty(const QList *qlist);
+size_t qlist_size(const QList *qlist);
 QList *qobject_to_qlist(const QObject *obj);
 
 static inline const QListEntry *qlist_first(const QList *qlist)
-- 
1.7.9.5




[Qemu-devel] [PATCH 11/23] usb: restore USBDevice->attached on vmload

2012-08-21 Thread Michael Roth
From: Gerd Hoffmann 

Signed-off-by: Gerd Hoffmann 
(cherry picked from commit 495d544798151206bafca65ec588c0388637eb40)

Signed-off-by: Michael Roth 
---
 hw/usb/bus.c |   13 +
 1 file changed, 13 insertions(+)

diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index 2068640..77b2b99 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -27,10 +27,23 @@ static struct BusInfo usb_bus_info = {
 static int next_usb_bus = 0;
 static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
 
+static int usb_device_post_load(void *opaque, int version_id)
+{
+USBDevice *dev = opaque;
+
+if (dev->state == USB_STATE_NOTATTACHED) {
+dev->attached = 0;
+} else {
+dev->attached = 1;
+}
+return 0;
+}
+
 const VMStateDescription vmstate_usb_device = {
 .name = "USBDevice",
 .version_id = 1,
 .minimum_version_id = 1,
+.post_load = usb_device_post_load,
 .fields = (VMStateField []) {
 VMSTATE_UINT8(addr, USBDevice),
 VMSTATE_INT32(state, USBDevice),
-- 
1.7.9.5




[Qemu-devel] [PATCH 09/23] ehci: don't flush cache on doorbell rings.

2012-08-21 Thread Michael Roth
From: Gerd Hoffmann 

Commit 4be23939ab0d7019c7e59a37485b416fbbf0f073 makes ehci instantly
zap any unlinked queue heads when the guest rings the doorbell.

While hacking up uas support this turned out to be a problem.  The linux
kernel can unlink and instantly relink the very same queue head, thereby
killing any async packets in flight.  That alone isn't an issue yet, the
packet will canceled and resubmitted and everything is fine.  We'll run
into trouble though in case the async packet is completed already, so we
can't cancel it any more.  The transaction is simply lost then.

usb_ehci_qh_ptrs q (nil) - QH @ 39c4f000: next 39c4f122 qtds 
,0001,39c5
usb_ehci_qh_fields QH @ 39c4f000 - rl 0, mplen 0, eps 0, ep 0, dev 0
usb_ehci_qh_ptrs q 0x7f95feba90a0 - QH @ 39c4f000: next 39c4f122 qtds 
,0001,39c5
usb_ehci_qh_fields QH @ 39c4f000 - rl 0, mplen 0, eps 0, ep 0, dev 0
usb_ehci_qh_ptrs q 0x7f95fe515210 - QH @ 39c4f120: next 39c4f0c2 qtds 
29dbce40,29dbc4e0,0009
usb_ehci_qh_fields QH @ 39c4f120 - rl 4, mplen 512, eps 2, ep 1, dev 2
usb_ehci_packet_action q 0x7f95fe515210 p 0x7f95fdec32a0: alloc
usb_packet_state_change bus 0, port 2, ep 1, packet 0x7f95fdec32e0, state undef 
-> setup
usb_ehci_packet_action q 0x7f95fe515210 p 0x7f95fdec32a0: process
usb_uas_command dev 2, tag 0x2, lun 0, lun64 -
scsi_req_parsed target 0 lun 0 tag 2 command 42 dir 2 length 16384
scsi_req_parsed_lba target 0 lun 0 tag 2 command 42 lba 5933312
scsi_req_alloc target 0 lun 0 tag 2
scsi_req_continue target 0 lun 0 tag 2
scsi_req_data target 0 lun 0 tag 2 len 16384
usb_uas_scsi_data dev 2, tag 0x2, bytes 16384
usb_uas_write_ready dev 2, tag 0x2
usb_packet_state_change bus 0, port 2, ep 1, packet 0x7f95fdec32e0, state setup 
-> complete
usb_ehci_packet_action q 0x7f95fe515210 p 0x7f95fdec32a0: free
usb_ehci_qh_ptrs q 0x7f95fdec3210 - QH @ 39c4f0c0: next 39c4f002 qtds 
29dbce40,0001,0009
usb_ehci_qh_fields QH @ 39c4f0c0 - rl 4, mplen 512, eps 2, ep 2, dev 2
usb_ehci_queue_action q 0x7f95fe5152a0: free
usb_packet_state_change bus 0, port 2, ep 2, packet 0x7f95feba9170, state async 
-> complete
^^^ async packets completes.
usb_ehci_packet_action q 0x7f95fdec3210 p 0x7f95feba9130: wakeup

usb_ehci_qh_ptrs q (nil) - QH @ 39c4f000: next 39c4f122 qtds 
,0001,39c5
usb_ehci_qh_fields QH @ 39c4f000 - rl 0, mplen 0, eps 0, ep 0, dev 0
usb_ehci_qh_ptrs q 0x7f95feba90a0 - QH @ 39c4f000: next 39c4f122 qtds 
,0001,39c5
usb_ehci_qh_fields QH @ 39c4f000 - rl 0, mplen 0, eps 0, ep 0, dev 0
usb_ehci_qh_ptrs q 0x7f95fe515210 - QH @ 39c4f120: next 39c4f002 qtds 
29dbc4e0,29dbc8a0,0009
usb_ehci_qh_fields QH @ 39c4f120 - rl 4, mplen 512, eps 2, ep 1, dev 2
usb_ehci_queue_action q 0x7f95fdec3210: free
usb_ehci_packet_action q 0x7f95fdec3210 p 0x7f95feba9130: free
^^^ endpoint #2 queue head removed from schedule, doorbell makes ehci zap the 
queue,
the (completed) usb packet is freed too and gets lost.

usb_ehci_qh_ptrs q (nil) - QH @ 39c4f000: next 39c4f0c2 qtds 
,0001,39c5
usb_ehci_qh_fields QH @ 39c4f000 - rl 0, mplen 0, eps 0, ep 0, dev 0
usb_ehci_qh_ptrs q 0x7f95feba90a0 - QH @ 39c4f000: next 39c4f0c2 qtds 
,0001,39c5
usb_ehci_qh_fields QH @ 39c4f000 - rl 0, mplen 0, eps 0, ep 0, dev 0
usb_ehci_queue_action q 0x7f9600dff570: alloc
usb_ehci_qh_ptrs q 0x7f9600dff570 - QH @ 39c4f0c0: next 39c4f122 qtds 
29dbce40,0001,0009
usb_ehci_qh_fields QH @ 39c4f0c0 - rl 4, mplen 512, eps 2, ep 2, dev 2
usb_ehci_packet_action q 0x7f9600dff570 p 0x7f95feba9130: alloc
usb_packet_state_change bus 0, port 2, ep 2, packet 0x7f95feba9170, state undef 
-> setup
usb_ehci_packet_action q 0x7f9600dff570 p 0x7f95feba9130: process
usb_packet_state_change bus 0, port 2, ep 2, packet 0x7f95feba9170, state setup 
-> async
usb_ehci_packet_action q 0x7f9600dff570 p 0x7f95feba9130: async
^^^ linux kernel relinked the queue head, ehci creates a new usb packet,
but we should have delivered the completed one instead.
usb_ehci_qh_ptrs q 0x7f95fe515210 - QH @ 39c4f120: next 39c4f002 qtds 
29dbc4e0,29dbc8a0,0009
usb_ehci_qh_fields QH @ 39c4f120 - rl 4, mplen 512, eps 2, ep 1, dev 2

So instead of instantly zapping the queue we'll set a flag that the
queue needs revalidation in case we'll see it again in the schedule.
ehci then checks that the queue head fields addressing / describing the
endpoint and the qtd pointer match the cached content before reusing it.

Cc: Hans de Goede 
Signed-off-by: Gerd Hoffmann 
(cherry picked from commit 9bc3a3a216e2689bfcdd36c3e079333bbdbf3ba0)

Conflicts:

    hw/usb/hcd-ehci.c

Signed-off-by: Michael Roth 
---
 hw/usb/hcd-ehci.c |   34 --
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 5855c5d..ce8b405 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -348,6 +348,7 @@ struct

[Qemu-devel] [PATCH 18/23] slirp: Ensure smbd and shared directory exist when enable smb

2012-08-21 Thread Michael Roth
From: Dunrong Huang 

Users may pass the following parameters to qemu:
$ qemu-kvm -net nic -net user,smb= ...
$ qemu-kvm -net nic -net user,smb ...
$ qemu-kvm -net nic -net user,smb=bad_directory ...

In these cases, qemu started successfully while samba server
failed to start. Users will confuse since samba server
failed silently without any indication of what it did wrong.

To avoid it, we check whether the shared directory exist and
if users have permission to access this directory when QEMU's
"built-in" SMB server is enabled.

Signed-off-by: Dunrong Huang 
Signed-off-by: Jan Kiszka 
(cherry picked from commit 927d811b282ffdf5386bd63f435c1507634ba49a)

Signed-off-by: Michael Roth 
---
 net/slirp.c |   12 
 1 file changed, 12 insertions(+)

diff --git a/net/slirp.c b/net/slirp.c
index c73610e..d3fcbf4 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -497,6 +497,18 @@ static int slirp_smb(SlirpState* s, const char 
*exported_dir,
 return -1;
 }
 
+if (access(CONFIG_SMBD_COMMAND, F_OK)) {
+error_report("could not find '%s', please install it",
+ CONFIG_SMBD_COMMAND);
+return -1;
+}
+
+if (access(exported_dir, R_OK | X_OK)) {
+error_report("no such directory '%s', or you do not have permission "
+ "to access it, please check it", exported_dir);
+return -1;
+}
+
 snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d",
  (long)getpid(), instance++);
 if (mkdir(s->smb_dir, 0700) < 0) {
-- 
1.7.9.5




[Qemu-devel] [PATCH 04/23] s390: Fix error handling and condition code of service call

2012-08-21 Thread Michael Roth
From: Christian Borntraeger 

Invalid sccb addresses will cause specification or addressing exception.
Lets add those checks. Furthermore, the good case (cc=0) was incorrect
for KVM, we did not set the CC at all. We now use return codes < 0
as program checks and return codes > 0 as condition code values.

Signed-off-by: Christian Borntraeger 
Signed-off-by: Alexander Graf 
(cherry picked from commit 9abf567d95a4e840df868ca993219175fbef8c22)

Signed-off-by: Michael Roth 
---
 target-s390x/kvm.c   |5 +++--
 target-s390x/op_helper.c |   27 ++-
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 90aad61..e4e6f15 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -238,9 +238,10 @@ static int kvm_sclp_service_call(CPUS390XState *env, 
struct kvm_run *run,
 code = env->regs[(ipbh0 & 0xf0) >> 4];
 
 r = sclp_service_call(env, sccb, code);
-if (r) {
-setcc(env, 3);
+if (r < 0) {
+enter_pgmcheck(env, -r);
 }
+setcc(env, r);
 
 return 0;
 }
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
index 7b72473..91dd8dc 100644
--- a/target-s390x/op_helper.c
+++ b/target-s390x/op_helper.c
@@ -19,6 +19,8 @@
  */
 
 #include "cpu.h"
+#include "memory.h"
+#include "cputlb.h"
 #include "dyngen-exec.h"
 #include "host-utils.h"
 #include "helper.h"
@@ -2366,6 +2368,9 @@ static void ext_interrupt(CPUS390XState *env, int type, 
uint32_t param,
 cpu_inject_ext(env, type, param, param64);
 }
 
+/*
+ * ret < 0 indicates program check, ret = 0,1,2,3 -> cc
+ */
 int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
 {
 int r = 0;
@@ -2375,10 +2380,12 @@ int sclp_service_call(CPUS390XState *env, uint32_t 
sccb, uint64_t code)
 printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
 #endif
 
+/* basic checks */
+if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) {
+return -PGM_ADDRESSING;
+}
 if (sccb & ~0x7ff8ul) {
-fprintf(stderr, "KVM: invalid sccb address 0x%x\n", sccb);
-r = -1;
-goto out;
+return -PGM_SPECIFICATION;
 }
 
 switch(code) {
@@ -2405,22 +2412,24 @@ int sclp_service_call(CPUS390XState *env, uint32_t 
sccb, uint64_t code)
 #ifdef DEBUG_HELPER
 printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, 
code);
 #endif
-r = -1;
+r = 3;
 break;
 }
 
-out:
 return r;
 }
 
 /* SCLP service call */
 uint32_t HELPER(servc)(uint32_t r1, uint64_t r2)
 {
-if (sclp_service_call(env, r1, r2)) {
-return 3;
-}
+int r;
 
-return 0;
+r = sclp_service_call(env, r1, r2);
+if (r < 0) {
+program_interrupt(env, -r, 4);
+return 0;
+}
+return r;
 }
 
 /* DIAG */
-- 
1.7.9.5




[Qemu-devel] [PATCH 03/23] ppc: Fix bug in handling of PAPR hypercall exits

2012-08-21 Thread Michael Roth
From: David Gibson 

Currently for powerpc, kvm_arch_handle_exit() always returns 1, meaning
that its caller - kvm_cpu_exec() - will always exit immediately afterwards
to the loop in qemu_kvm_cpu_thread_fn().

There's no need to do this.  Once we've handled the hypercall there's no
reason we can't go straight around and KVM_RUN again, which is what ret = 0
will signal.  The only exception might be for hypercalls which affect the
state of cpu_can_run(), however the only one that might do this is H_CEDE
and for kvm that is always handled in the kernel, not qemu.

Furtherm setting ret = 0 means that when exit_requested is set from a
hypercall, we will enter KVM_RUN once more with a signal which lets the
the kernel do its internal logic to complete the hypercall with out
actually executing any more guest code.  This is important if our hypercall
also triggered a reset, which previously would re-initialize everything
without completing the hypercall.  This caused the kernel to get confused
because it thought the guest was still in the middle of a hypercall when
it has actually been reset.

This patch therefore changes to ret = 0, which is both a bugfix and a small
optimization.

Signed-off-by: David Gibson 
Signed-off-by: Alexander Graf 
(cherry picked from commit 78e8fde26c032931ca2ae13bfc7c59e38afd17ee)

Signed-off-by: Michael Roth 
---
 target-ppc/kvm.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index c09cc39..29997af 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -558,7 +558,7 @@ int kvm_arch_handle_exit(CPUPPCState *env, struct kvm_run 
*run)
 dprintf("handle PAPR hypercall\n");
 run->papr_hcall.ret = spapr_hypercall(env, run->papr_hcall.nr,
   run->papr_hcall.args);
-ret = 1;
+ret = 0;
 break;
 #endif
 default:
-- 
1.7.9.5




[Qemu-devel] [PATCH 07/23] virtio-blk: fix use-after-free while handling scsi commands

2012-08-21 Thread Michael Roth
From: Avi Kivity 

The scsi passthrough handler falls through after completing a
request into the failure path, resulting in a use after free.

Reproducible by running a guest with aio=native on a block device.

Reported-by: Stefan Priebe 
Signed-off-by: Avi Kivity 
Signed-off-by: Stefan Hajnoczi 
Signed-off-by: Kevin Wolf 
(cherry picked from commit 730a9c53b4e52681fcfe31cf38854cbf91e132c7)

Signed-off-by: Michael Roth 
---
 hw/virtio-blk.c |1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index fe07746..f44d244 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -253,6 +253,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
 
 virtio_blk_req_complete(req, status);
 g_free(req);
+return;
 #else
 abort();
 #endif
-- 
1.7.9.5




[Qemu-devel] [PATCH 21/23] apic: Reevaluate pending interrupts on LVT_LINT0 changes

2012-08-21 Thread Michael Roth
From: Jan Kiszka 

When the guest modifies the LVT_LINT0 register, we need to check if some
pending PIC interrupt can now be delivered.

Signed-off-by: Jan Kiszka 
Signed-off-by: Avi Kivity 
(cherry picked from commit a94820ddc36f8c452b37f9dcb323f55ffdbc75f9)

Signed-off-by: Michael Roth 
---
 hw/apic.c |   18 ++
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/hw/apic.c b/hw/apic.c
index ec8f9ba..e96402d 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -540,6 +540,15 @@ static void apic_deliver(DeviceState *d, uint8_t dest, 
uint8_t dest_mode,
 apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
 }
 
+static bool apic_check_pic(APICCommonState *s)
+{
+if (!apic_accept_pic_intr(&s->busdev.qdev) || !pic_get_output(isa_pic)) {
+return false;
+}
+apic_deliver_pic_intr(&s->busdev.qdev, 1);
+return true;
+}
+
 int apic_get_interrupt(DeviceState *d)
 {
 APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
@@ -567,9 +576,7 @@ int apic_get_interrupt(DeviceState *d)
 apic_sync_vapic(s, SYNC_TO_VAPIC);
 
 /* re-inject if there is still a pending PIC interrupt */
-if (apic_accept_pic_intr(&s->busdev.qdev) && pic_get_output(isa_pic)) {
-apic_deliver_pic_intr(&s->busdev.qdev, 1);
-}
+apic_check_pic(s);
 
 apic_update_irq(s);
 
@@ -812,8 +819,11 @@ static void apic_mem_writel(void *opaque, 
target_phys_addr_t addr, uint32_t val)
 {
 int n = index - 0x32;
 s->lvt[n] = val;
-if (n == APIC_LVT_TIMER)
+if (n == APIC_LVT_TIMER) {
 apic_timer_update(s, qemu_get_clock_ns(vm_clock));
+} else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) {
+apic_update_irq(s);
+}
 }
 break;
 case 0x38:
-- 
1.7.9.5




[Qemu-devel] [PATCH 20/23] apic: Resolve potential endless loop around apic_update_irq

2012-08-21 Thread Michael Roth
From: Jan Kiszka 

Commit d96e173769 refactored the reinjection of pending PIC interrupts.
However, it missed the potential loop of apic_update_irq ->
apic_deliver_pic_intr -> apic_local_deliver -> apic_set_irq ->
apic_update_irq that /could/ occur if LINT0 is injected as APIC_DM_FIXED
and that vector is currently blocked via TPR.

Resolve this by reinjecting only where it matters: inside
apic_get_interrupt. This function may clear a vector while a
PIC-originated reason still exists.

Signed-off-by: Jan Kiszka 
Signed-off-by: Avi Kivity 
(cherry picked from commit 3db3659bf60094657e1465cc809acb09551816ee)

Signed-off-by: Michael Roth 
---
 hw/apic.c |   10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/hw/apic.c b/hw/apic.c
index 4eeaf88..ec8f9ba 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -371,9 +371,6 @@ static void apic_update_irq(APICCommonState *s)
 }
 if (apic_irq_pending(s) > 0) {
 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
-} else if (apic_accept_pic_intr(&s->busdev.qdev) &&
-   pic_get_output(isa_pic)) {
-apic_deliver_pic_intr(&s->busdev.qdev, 1);
 }
 }
 
@@ -568,7 +565,14 @@ int apic_get_interrupt(DeviceState *d)
 reset_bit(s->irr, intno);
 set_bit(s->isr, intno);
 apic_sync_vapic(s, SYNC_TO_VAPIC);
+
+/* re-inject if there is still a pending PIC interrupt */
+if (apic_accept_pic_intr(&s->busdev.qdev) && pic_get_output(isa_pic)) {
+apic_deliver_pic_intr(&s->busdev.qdev, 1);
+}
+
 apic_update_irq(s);
+
 return intno;
 }
 
-- 
1.7.9.5




[Qemu-devel] [PATCH 13/23] usb-ehci: Fix an assert whenever isoc transfers are used

2012-08-21 Thread Michael Roth
From: Hans de Goede 

hcd-ehci.c is missing an usb_packet_init() call for the ipacket UsbPacket
it uses for isoc transfers, triggering an assert (taking the entire vm down)
in usb_packet_setup as soon as any isoc transfers are done by a high speed
USB device.

Signed-off-by: Hans de Goede 
Signed-off-by: Gerd Hoffmann 
(cherry picked from commit 7341ea075c09258b98a1d0efc60efd402cbfc9b4)

Signed-off-by: Michael Roth 
---
 hw/usb/hcd-ehci.c |1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index ce8b405..41c9d84 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -2324,6 +2324,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
 s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s);
 QTAILQ_INIT(&s->aqueues);
 QTAILQ_INIT(&s->pqueues);
+usb_packet_init(&s->ipacket);
 
 qemu_register_reset(ehci_reset, s);
 
-- 
1.7.9.5




[Qemu-devel] [PATCH 19/23] slirp: Improve error reporting of inaccessible smb directories

2012-08-21 Thread Michael Roth
From: Jan Kiszka 

Instead of guessing, print the error code returned by access.

Signed-off-by: Jan Kiszka 
(cherry picked from commit 22a61f365df83d5d7884cceb1c462295977cb2db)

Signed-off-by: Michael Roth 
---
 net/slirp.c |4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/slirp.c b/net/slirp.c
index d3fcbf4..49f55bc 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -504,8 +504,8 @@ static int slirp_smb(SlirpState* s, const char 
*exported_dir,
 }
 
 if (access(exported_dir, R_OK | X_OK)) {
-error_report("no such directory '%s', or you do not have permission "
- "to access it, please check it", exported_dir);
+error_report("error accessing shared directory '%s': %s",
+ exported_dir, strerror(errno));
 return -1;
 }
 
-- 
1.7.9.5




[Qemu-devel] [PATCH 12/23] usb-redir: Correctly handle the usb_redir_babble usbredir status

2012-08-21 Thread Michael Roth
From: Hans de Goede 

Signed-off-by: Hans de Goede 
Signed-off-by: Gerd Hoffmann 
(cherry picked from commit adae502c0ae4572ef08f71cb5b5ed5a8e90299fe)

Signed-off-by: Michael Roth 
---
 hw/usb/redirect.c |2 ++
 1 file changed, 2 insertions(+)

diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 51c27b4..1fd903a 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1031,6 +1031,8 @@ static int usbredir_handle_status(USBRedirDevice *dev,
 case usb_redir_inval:
 WARNING("got invalid param error from usb-host?\n");
 return USB_RET_NAK;
+case usb_redir_babble:
+return USB_RET_BABBLE;
 case usb_redir_ioerror:
 case usb_redir_timeout:
 default:
-- 
1.7.9.5




[Qemu-devel] [PATCH 17/23] slirp: Enforce host-side user of smb share

2012-08-21 Thread Michael Roth
From: Jan Kiszka 

Windows 7 (and possibly other versions) cannot connect to the samba
share if the exported host directory is not world-readable. This can be
resolved by forcing the username used for access checks to the one
under which QEMU and smbd are running.

Signed-off-by: Jan Kiszka 
(cherry picked from commit 1cb1c5d10bb9e180bd3f7be2c10b212ed86a97b4)

Signed-off-by: Michael Roth 
---
 net/slirp.c |   14 --
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/net/slirp.c b/net/slirp.c
index 96f5032..c73610e 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -26,6 +26,7 @@
 #include "config-host.h"
 
 #ifndef _WIN32
+#include 
 #include 
 #endif
 #include "net.h"
@@ -487,8 +488,15 @@ static int slirp_smb(SlirpState* s, const char 
*exported_dir,
 static int instance;
 char smb_conf[128];
 char smb_cmdline[128];
+struct passwd *passwd;
 FILE *f;
 
+passwd = getpwuid(geteuid());
+if (!passwd) {
+error_report("failed to retrieve user name");
+return -1;
+}
+
 snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d",
  (long)getpid(), instance++);
 if (mkdir(s->smb_dir, 0700) < 0) {
@@ -517,14 +525,16 @@ static int slirp_smb(SlirpState* s, const char 
*exported_dir,
 "[qemu]\n"
 "path=%s\n"
 "read only=no\n"
-"guest ok=yes\n",
+"guest ok=yes\n"
+"force user=%s\n",
 s->smb_dir,
 s->smb_dir,
 s->smb_dir,
 s->smb_dir,
 s->smb_dir,
 s->smb_dir,
-exported_dir
+exported_dir,
+passwd->pw_name
 );
 fclose(f);
 
-- 
1.7.9.5




[Qemu-devel] [PATCH 10/23] uhci: fix uhci_async_cancel_all

2012-08-21 Thread Michael Roth
From: Gerd Hoffmann 

We update the QTAILQ in the loop, thus we must use the SAFE version
to make sure we don't touch the queue struct after freeing it.

https://bugzilla.novell.com/show_bug.cgi?id=766310

Signed-off-by: Gerd Hoffmann 
(cherry picked from commit 77fa9aee38758a078870e25f0dcf642066b4d5cc)

Signed-off-by: Michael Roth 
---
 hw/usb/hcd-uhci.c |4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 9e211a0..3803f52 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -288,10 +288,10 @@ static void uhci_async_cancel_device(UHCIState *s, 
USBDevice *dev)
 
 static void uhci_async_cancel_all(UHCIState *s)
 {
-UHCIQueue *queue;
+UHCIQueue *queue, *nq;
 UHCIAsync *curr, *n;
 
-QTAILQ_FOREACH(queue, &s->queues, next) {
+QTAILQ_FOREACH_SAFE(queue, &s->queues, next, nq) {
 QTAILQ_FOREACH_SAFE(curr, &queue->asyncs, next, n) {
 uhci_async_unlink(curr);
 uhci_async_cancel(curr);
-- 
1.7.9.5




[Qemu-devel] [stable-1.1] Patch Round-up for stable 1.1.2

2012-08-21 Thread Michael Roth
This is the current list of candidates for QEMU 1.1.2, which we're planning
to release on Friday. Please review and respond with any additional patches
you think should be included. These are also available at:

  git://github.com/mdroth/qemu.git stable-1.1-staging

There's a few that Michael Tokarov had mentioned to me that are not
upstream yet that I'd also like to pull in:

"ahci: fix cdrom read corruption"
http://thread.gmane.org/gmane.comp.emulators.qemu/163543

"commit da57febfed "qdev: give all devices a canonical path" broke usb_ [...]"
http://thread.gmane.org/gmane.comp.emulators.qemu/164180/focus=164185

And one I just sent out:

"libcacard: Fix segfault when no backend specified"

Queued patches follow:

Anthony Liguori (2):
  qtest: fix infinite loop when QEMU aborts abruptly
  qdev: fix use-after-free in the error path of qdev_init_nofail

Avi Kivity (1):
  virtio-blk: fix use-after-free while handling scsi commands

Christian Borntraeger (1):
  s390: Fix error handling and condition code of service call

David Gibson (1):
  ppc: Fix bug in handling of PAPR hypercall exits

Dunrong Huang (1):
  slirp: Ensure smbd and shared directory exist when enable smb

Gerd Hoffmann (4):
  ehci: fix reset
  ehci: don't flush cache on doorbell rings.
  uhci: fix uhci_async_cancel_all
  usb: restore USBDevice->attached on vmload

Hans de Goede (2):
  usb-redir: Correctly handle the usb_redir_babble usbredir status
  usb-ehci: Fix an assert whenever isoc transfers are used

Jan Kiszka (6):
  kvmvapic: Disable if there is insufficient memory
  slirp: Enforce host-side user of smb share
  slirp: Improve error reporting of inaccessible smb directories
  apic: Resolve potential endless loop around apic_update_irq
  apic: Reevaluate pending interrupts on LVT_LINT0 changes
  apic: Defer interrupt updates to VCPU thread

Michael Roth (4):
  qlist: add qlist_size()
  json-parser: don't replicate tokens at each level of recursion
  check-qjson: add test for large JSON objects
  update VERSION for 1.1.2

Peter Maydell (1):
  configure: Don't override user's --cpu on MacOS and Solaris

 VERSION  |2 +-
 configure|   60 +++-
 cpu-exec.c   |6 ++
 hw/apic.c|   27 +-
 hw/apic.h|1 +
 hw/apic_common.c |4 +-
 hw/apic_internal.h   |1 -
 hw/qdev.c|5 +-
 hw/usb/bus.c |   13 +++
 hw/usb/hcd-ehci.c|   45 +++--
 hw/usb/hcd-uhci.c|4 +-
 hw/usb/redirect.c|2 +
 hw/virtio-blk.c  |1 +
 json-parser.c|  230 --
 net/slirp.c  |   26 +-
 qlist.c  |   13 +++
 qlist.h  |1 +
 target-i386/cpu.h|4 +-
 target-i386/kvm.c|4 +
 target-ppc/kvm.c |2 +-
 target-s390x/kvm.c   |5 +-
 target-s390x/op_helper.c |   27 --
 tests/check-qjson.c  |   53 +++
 tests/libqtest.c |5 +
 24 files changed, 391 insertions(+), 150 deletions(-)




[Qemu-devel] [PATCH 08/23] ehci: fix reset

2012-08-21 Thread Michael Roth
From: Gerd Hoffmann 

Check for the reset bit first when processing USBCMD register writes.
Also break out of the switch, there is no need to check the other bits.

Signed-off-by: Gerd Hoffmann 
(cherry picked from commit 7046530c36fa3a3f87692bdb54556f5d891a9c03)

Signed-off-by: Michael Roth 
---
 hw/usb/hcd-ehci.c |   10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index e759c99..5855c5d 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1064,6 +1064,12 @@ static void ehci_mem_writel(void *ptr, 
target_phys_addr_t addr, uint32_t val)
 /* Do any register specific pre-write processing here.  */
 switch(addr) {
 case USBCMD:
+if (val & USBCMD_HCRESET) {
+ehci_reset(s);
+val = s->usbcmd;
+break;
+}
+
 if ((val & USBCMD_RUNSTOP) && !(s->usbcmd & USBCMD_RUNSTOP)) {
 qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
 SET_LAST_RUN_CLOCK(s);
@@ -1077,10 +1083,6 @@ static void ehci_mem_writel(void *ptr, 
target_phys_addr_t addr, uint32_t val)
 ehci_set_usbsts(s, USBSTS_HALT);
 }
 
-if (val & USBCMD_HCRESET) {
-ehci_reset(s);
-val = s->usbcmd;
-}
 
 /* not supporting dynamic frame list size at the moment */
 if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
-- 
1.7.9.5




Re: [Qemu-devel] [PATCH] Add guest-get-hostname to retrieve the guests current hostname

2012-08-23 Thread Michael Roth
On Thu, Aug 23, 2012 at 09:48:54AM -0300, Luiz Capitulino wrote:
> On Tue, 21 Aug 2012 13:57:54 +0200
> Guido Günther  wrote:
> 
> > This allows to retrieve the guest's hostname via gethostname(2).
> > 
> > This can be useful to identify a VM e.g. one without network.
> > 
> > Signed-off-by: Guido Günther 
> > ---
> > We have an API in libvirt for that (virDomainGetHostname).
> > Cheers
> >  -- Guido
> > 
> >  qapi-schema-guest.json |   12 
> >  qga/commands-posix.c   |   12 
> >  qga/commands-win32.c   |6 ++
> >  3 files changed, 30 insertions(+)
> > 
> > diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json
> > index d955cf1..8c7a4a5 100644
> > --- a/qapi-schema-guest.json
> > +++ b/qapi-schema-guest.json
> > @@ -515,3 +515,15 @@
> >  ##
> >  { 'command': 'guest-network-get-interfaces',
> >'returns': ['GuestNetworkInterface'] }
> > +
> > +##
> > +# @guest-get-hostname:
> > +#
> > +# Get the guest's hostname
> > +#
> > +# Returns: The guest's hostname
> > +#
> > +# Since: 1.2
> 
> Won't make it for 1.2 because we're in hard-freeze.
> 
> > +##
> > +{ 'command': 'guest-get-hostname',
> > +  'returns': 'str' }
> > diff --git a/qga/commands-posix.c b/qga/commands-posix.c
> > index ce90421..9223f18 100644
> > --- a/qga/commands-posix.c
> > +++ b/qga/commands-posix.c
> > @@ -15,6 +15,7 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include 
> >  #include "qga/guest-agent-core.h"
> >  #include "qga-qmp-commands.h"
> >  #include "qerror.h"
> > @@ -993,6 +994,17 @@ void qmp_guest_fstrim(bool has_minimum, int64_t 
> > minimum, Error **err)
> >  }
> >  #endif
> >  
> > +char *qmp_guest_get_hostname(Error **err)
> > +{
> > +char hostname[HOST_NAME_MAX];
> > +
> > +if (gethostname(hostname, HOST_NAME_MAX)) {
> > +error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
> 
> You shouldn't use that macro, you can do something like this instead:
> 
>  error_set(err, "can't get hostname: %s", strerror(errno));
> 
> Michael, do you think that's fine for new error messages or do you think it's
> worth it to add a "guest-agent: " prefix to all guest agent error messages?
> 

I think that's fine. libvirt or QMP (if we integrate the qemu-ga
commands with QMP) can tack on a prefix for cases where we need to distinguish
where in the stack the error occurred, but for direct communication with
qemu-ga it's unambiguous, so might as well save the keystrokes.

> > +return NULL;
> > +}
> > +return g_strdup(hostname);
> > +}
> > +
> >  /* register init/cleanup routines for stateful command groups */
> >  void ga_command_state_init(GAState *s, GACommandState *cs)
> >  {
> > diff --git a/qga/commands-win32.c b/qga/commands-win32.c
> > index 54bc546..55e8162 100644
> > --- a/qga/commands-win32.c
> > +++ b/qga/commands-win32.c
> > @@ -280,6 +280,12 @@ GuestNetworkInterfaceList 
> > *qmp_guest_network_get_interfaces(Error **err)
> >  return NULL;
> >  }
> >  
> > +char *qmp_guest_get_hostname(Error **err)
> > +{
> > +error_set(err, QERR_UNSUPPORTED);
> > +return NULL;
> > +}
> > +
> >  /* register init/cleanup routines for stateful command groups */
> >  void ga_command_state_init(GAState *s, GACommandState *cs)
> >  {
> 
> 



Re: [Qemu-devel] [PATCH 1/7] qemu-ga: move channel/transport functionality into wrapper class

2012-01-23 Thread Michael Roth

On 01/23/2012 02:24 PM, Anthony Liguori wrote:

On 01/23/2012 08:21 AM, Michael Roth wrote:

This is monstly in preparation for the win32 port, which won't use
GIO channels for reasons that will be made clearer later. Here the
GAChannel class is just a loose wrapper around GIOChannel
calls/callbacks, but we also roll the logic/configuration for handling
FDs and also for managing unix socket connections into it, which makes
the abstraction much more complete and further aids in the win32 port
since isa-serial/unix-listen will not be supported initially.

There's also a bit of refactoring in the main logic to consolidate the
exit paths so we can do common cleanup for things like pid files, which
weren't always cleaned up previously.

Signed-off-by: Michael Roth


This doesn't apply very well. Can you rebase?


I think the issue is that it depends on the 4 patches I mentioned that 
are currently floating around on the list (the first 2 for patchability, 
the latter 2 for functional/performance issues):


[PATCH] qemu-ga: Add schema documentation for types
[PATCH] qemu-ga: add guest-set-support-level command
[PATCH] main-loop: Fix SetEvent() on uninitialized handle on win32
[PATCH] main-loop: For tools, initialize timers as part of 
qemu_init_main_loop()


I think the first 2 are more likely to get merged along with Luiz's 
guest-suspend series, so I was hesitant to re-include them here as 1 
unit (since that would break Luiz's patches).


The git repo has the whole series though. Can also resubmit in a 
different form if preferred.




Regards,

Anthony Liguori


---
Makefile.objs | 1 +
qemu-ga.c | 306 
qga/channel-posix.c | 246 ++
qga/channel.h | 33 +
qga/guest-agent-core.h | 2 +-
5 files changed, 355 insertions(+), 233 deletions(-)
create mode 100644 qga/channel-posix.c
create mode 100644 qga/channel.h

diff --git a/Makefile.objs b/Makefile.objs
index f94c881..72141cc 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -417,6 +417,7 @@ common-obj-y += qmp.o hmp.o
# guest agent

qga-nested-y = guest-agent-commands.o guest-agent-command-state.o
+qga-nested-y += channel-posix.o
qga-obj-y = $(addprefix qga/, $(qga-nested-y))
qga-obj-y += qemu-ga.o qemu-sockets.o module.o qemu-option.o
qga-obj-$(CONFIG_WIN32) += oslib-win32.o
diff --git a/qemu-ga.c b/qemu-ga.c
index 8e5b075..5f89ab9 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -15,9 +15,7 @@
#include
#include
#include
-#include
#include
-#include "qemu_socket.h"
#include "json-streamer.h"
#include "json-parser.h"
#include "qint.h"
@@ -29,19 +27,15 @@
#include "error_int.h"
#include "qapi/qmp-core.h"
#include "qga-qapi-types.h"
+#include "qga/channel.h"

#define QGA_VIRTIO_PATH_DEFAULT
"/dev/virtio-ports/org.qemu.guest_agent.0"
#define QGA_PIDFILE_DEFAULT "/var/run/qemu-ga.pid"
-#define QGA_BAUDRATE_DEFAULT B38400 /* for isa-serial channels */
-#define QGA_TIMEOUT_DEFAULT 30*1000 /* ms */

struct GAState {
JSONMessageParser parser;
GMainLoop *main_loop;
- GIOChannel *conn_channel;
- GIOChannel *listen_channel;
- const char *path;
- const char *method;
+ GAChannel *channel;
bool virtio; /* fastpath to check for virtio to deal with poll()
quirks */
GACommandState *command_state;
GLogLevelFlags log_level;
@@ -60,7 +54,7 @@ static void quit_handler(int sig)
}
}

-static void register_signal_handlers(void)
+static gboolean register_signal_handlers(void)
{
struct sigaction sigact;
int ret;
@@ -71,12 +65,14 @@ static void register_signal_handlers(void)
ret = sigaction(SIGINT,&sigact, NULL);
if (ret == -1) {
g_error("error configuring signal handler: %s", strerror(errno));
- exit(EXIT_FAILURE);
+ return false;
}
ret = sigaction(SIGTERM,&sigact, NULL);
if (ret == -1) {
g_error("error configuring signal handler: %s", strerror(errno));
+ return false;
}
+ return true;
}

static void usage(const char *cmd)
@@ -101,8 +97,6 @@ static void usage(const char *cmd)
, cmd, QGA_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT);
}

-static void conn_channel_close(GAState *s);
-
static GuestAgentSupportLevel ga_support_level;

static int ga_cmp_support_levels(GuestAgentSupportLevel a,
@@ -250,40 +244,13 @@ fail:
exit(EXIT_FAILURE);
}

-static int conn_channel_send_buf(GIOChannel *channel, const char *buf,
- gsize count)
+static int send_response(GAState *s, QObject *payload)
{
- GError *err = NULL;
- gsize written = 0;
- GIOStatus status;
-
- while (count) {
- status = g_io_channel_write_chars(channel, buf, count,&written,&err);
- g_debug("sending data, count: %d", (int)count);
- if (err != NULL) {
- g_warning("error sending newline: %s", err->message);
- return err->code;
- }
- if (status == G_IO_STATUS_ERROR || status == G_IO_STATUS_EOF) {
- return -EPIPE;
- }
-
- if (status == G_IO_STATUS_NORMAL) {
- c

[Qemu-devel] [PULL 0/6] qemu-ga queue and qemu-tool fixes

2012-01-25 Thread Michael Roth
This pull adds 2 RPCs (guest-suspend and guest-set-support-level) to qemu-ga 
and some includes fixes/workarounds for building tools on Windows.

The following changes since commit 5b4448d27d7c6ff6e18a1edc8245cb1db783e37c:

  Merge remote-tracking branch 'qemu-kvm/uq/master' into staging (2012-01-23 
11:00:26 -0600)

are available in the git repository at:

  git://github.com/mdroth/qemu.git qga-pull-2012-01-23

Luiz Capitulino (2):
  qemu-ga: set O_NONBLOCK for serial channels
  qemu-ga: Add the guest-suspend command

Michael Roth (4):
  main-loop: Fix SetEvent() on uninitialized handle on win32
  main-loop: For tools, initialize timers as part of qemu_init_main_loop()
  qemu-ga: Add schema documentation for types
  qemu-ga: add guest-set-support-level command

 main-loop.c|7 +-
 main-loop.h|   12 ++
 qapi-schema-guest.json |  217 
 qemu-ga.c  |   66 -
 qemu-tool.c|3 +-
 qga/guest-agent-commands.c |  239 
 qga/guest-agent-core.h |   11 ++
 vl.c   |5 +
 8 files changed, 533 insertions(+), 27 deletions(-)




[Qemu-devel] [PATCH 1/6] main-loop: Fix SetEvent() on uninitialized handle on win32

2012-01-25 Thread Michael Roth
The __attribute__((constructor)) init_main_loop() automatically get
called if qemu-tool.o is linked in. On win32, this leads to
a qemu_notify_event() call which attempts to SetEvent() on a HANDLE that
won't be initialized until qemu_init_main_loop() is manually called,
breaking qemu-tools.o programs on Windows at runtime.

This patch checks for an initialized event handle before attempting to
set it, which is analoguous to how we deal with an unitialized
io_thread_fd in the posix implementation.

Signed-off-by: Michael Roth 
---
 main-loop.c |5 -
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/main-loop.c b/main-loop.c
index 692381c..62d95b9 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -164,7 +164,7 @@ static int qemu_signal_init(void)
 
 #else /* _WIN32 */
 
-HANDLE qemu_event_handle;
+HANDLE qemu_event_handle = NULL;
 
 static void dummy_event_handler(void *opaque)
 {
@@ -183,6 +183,9 @@ static int qemu_event_init(void)
 
 void qemu_notify_event(void)
 {
+if (!qemu_event_handle) {
+return;
+}
 if (!SetEvent(qemu_event_handle)) {
 fprintf(stderr, "qemu_notify_event: SetEvent failed: %ld\n",
 GetLastError());
-- 
1.7.4.1




[Qemu-devel] [PATCH 5/6] qemu-ga: set O_NONBLOCK for serial channels

2012-01-25 Thread Michael Roth
From: Luiz Capitulino 

This fixes a bug when using -m isa-serial where qemu-ga will
hang on a read()'s when communicating to the host via isa-serial.

Original fix by Michael Roth.

Signed-off-by: Luiz Capitulino 
Signed-off-by: Michael Roth 
---
 qemu-ga.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/qemu-ga.c b/qemu-ga.c
index 8e5b075..d63b17c 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -544,7 +544,7 @@ static void init_guest_agent(GAState *s)
 exit(EXIT_FAILURE);
 }
 } else if (strcmp(s->method, "isa-serial") == 0) {
-fd = qemu_open(s->path, O_RDWR | O_NOCTTY);
+fd = qemu_open(s->path, O_RDWR | O_NOCTTY | O_NONBLOCK);
 if (fd == -1) {
 g_critical("error opening channel: %s", strerror(errno));
 exit(EXIT_FAILURE);
-- 
1.7.4.1




[Qemu-devel] [PATCH 6/6] qemu-ga: Add the guest-suspend command

2012-01-25 Thread Michael Roth
From: Luiz Capitulino 

The guest-suspend command supports three modes:

 o hibernate (suspend to disk)
 o sleep (suspend to ram)
 o hybrid(save RAM contents to disk, but suspend instead of
  powering off)

Before trying to suspend, the command queries the guest in order
to know whether the given mode is supported. The sleep and hybrid
modes are only supported in QEMU 1.1 and later though, because
QEMU's S3 support is broken in previous versions.

The guest-suspend command will use the scripts provided by the
pm-utils package if they are available. If they aren't, a manual
process which directly writes to the "/sys/power/state" file is
used.

To reap terminated children, a new signal handler is installed in
the parent to catch SIGCHLD signals and a non-blocking call to
waitpid() is done to collect their exit statuses. The statuses,
however, are discarded.

The approach used to query the guest for suspend support deserves
some explanation. It's implemented by bios_supports_mode() and shown
below:

   qemu-ga
 |
 create pipe
 |
   fork()
 -
 |   |
 |   |
 | fork()
 |   --
 |   ||
 |   ||
 |   |   exec('pm-is-supported')
 |   |
 |  wait()
 |   write exit status to pipe
 |  exit
 |
  read pipe

This might look complex, but the resulting code is quite simple.
The purpose of that approach is to allow qemu-ga to reap its
children (semi-)automatically from its SIGCHLD handler.

Implementing this the obvious way, that's, doing the exec() call
from the first child process, would force us to introduce a more
complex way to reap qemu-ga's children. Like registering PIDs to
be reaped and having a way to wait for them when returning their
exit status to qemu-ga is necessary. The approach explained
above avoids that complexity.

Signed-off-by: Luiz Capitulino 
Signed-off-by: Michael Roth 
---
 qapi-schema-guest.json |   32 ++
 qemu-ga.c  |   18 -
 qga/guest-agent-commands.c |  226 
 3 files changed, 275 insertions(+), 1 deletions(-)

diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json
index 81cd773..9b1ab1c 100644
--- a/qapi-schema-guest.json
+++ b/qapi-schema-guest.json
@@ -360,3 +360,35 @@
 ##
 { 'command': 'guest-fsfreeze-thaw',
   'returns': 'int' }
+
+##
+# @guest-suspend
+#
+# Suspend guest execution by entering ACPI power state S3 or S4.
+#
+# This command tries to execute the scripts provided by the pm-utils
+# package. If they are not available, it will perform the suspend
+# operation by manually writing to a sysfs file.
+#
+# For the best results it's strongly recommended to have the pm-utils
+# package installed in the guest.
+#
+# @mode: 'hibernate' RAM content is saved to the disk and the guest is
+#powered off (this corresponds to ACPI S4)
+#'sleep' execution is suspended but the RAM retains its contents
+#(this corresponds to ACPI S3)
+#'hybrid'RAM content is saved to the disk but the guest is
+#suspended instead of powering off
+#
+# Returns: nothing on success
+#  If @mode is not supported by the guest, Unsupported
+#
+# Notes: o This is an asynchronous request. There's no guarantee a response
+#  will be sent.
+#o Errors will be logged to guest's syslog.
+#o It's strongly recommended to issue the guest-sync command before
+#  sending commands when the guest resumes.
+#
+# Since: 1.1
+##
+{ 'command': 'guest-suspend', 'data': { 'mode': 'str' } }
diff --git a/qemu-ga.c b/qemu-ga.c
index d63b17c..f8b12c7 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -17,6 +17,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "qemu_socket.h"
 #include "json-streamer.h"
 #include "json-parser.h"
@@ -60,9 +61,16 @@ static void quit_handler(int sig)
 }
 }
 
+/* reap _all_ terminated children */
+static void child_handler(int sig)
+{
+int status;
+while (waitpid(-1, &status, WNOHANG) > 0) /* NOTHING */;
+}
+
 static void register_signal_handlers(void)
 {
-struct sigaction sigact;
+struct sigaction sigact, sigact_chld;
 int ret;
 
 memset(&sigact, 0, sizeof(struct sigaction));
@@ -77,6 +85,14 @@ static void register_signal_handlers(void)
 if (ret == -1) {
 g_error("error configuring signal handler: %s", strerror(errno));
 }
+
+memset(&sigact_chld, 0, sizeof(struct sigaction));
+sigact_chld.sa_handler = child_handler;
+sigact_ch

[Qemu-devel] [PATCH 3/6] qemu-ga: Add schema documentation for types

2012-01-25 Thread Michael Roth
Document guest agent schema types in similar fashion as qmp schema
types.

Signed-off-by: Michael Roth 
---
 qapi-schema-guest.json |  118 +++-
 1 files changed, 97 insertions(+), 21 deletions(-)

diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json
index 5f8a18d..706925d 100644
--- a/qapi-schema-guest.json
+++ b/qapi-schema-guest.json
@@ -37,17 +37,42 @@
 { 'command': 'guest-ping' }
 
 ##
-# @guest-info:
+# @GuestAgentCommandInfo:
 #
-# Get some information about the guest agent.
+# Information about guest agent commands.
 #
-# Since: 0.15.0
+# @name: name of the command
+#
+# @enabled: whether command is currently enabled by guest admin
+#
+# Since 1.1.0
 ##
 { 'type': 'GuestAgentCommandInfo',
   'data': { 'name': 'str', 'enabled': 'bool' } }
+
+##
+# @GuestAgentInfo
+#
+# Information about guest agent.
+#
+# @version: guest agent version
+#
+# @supported_commands: Information about guest agent commands
+#
+# Since 0.15.0
+##
 { 'type': 'GuestAgentInfo',
   'data': { 'version': 'str',
 'supported_commands': ['GuestAgentCommandInfo'] } }
+##
+# @guest-info:
+#
+# Get some information about the guest agent.
+#
+# Returns: @GuestAgentInfo
+#
+# Since: 0.15.0
+##
 { 'command': 'guest-info',
   'returns': 'GuestAgentInfo' }
 
@@ -98,6 +123,23 @@
   'data': { 'handle': 'int' } }
 
 ##
+# @GuestFileRead
+#
+# Result of guest agent file-read operation
+#
+# @count: number of bytes read (note: count is *before*
+# base64-encoding is applied)
+#
+# @buf-b64: base64-encoded bytes read
+#
+# @eof: whether EOF was encountered during read operation.
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestFileRead',
+  'data': { 'count': 'int', 'buf-b64': 'str', 'eof': 'bool' } }
+
+##
 # @guest-file-read:
 #
 # Read from an open file in the guest. Data will be base64-encoded
@@ -106,19 +148,30 @@
 #
 # @count: #optional maximum number of bytes to read (default is 4KB)
 #
-# Returns: GuestFileRead on success. Note: count is number of bytes read
-#  *before* base64 encoding bytes read.
+# Returns: @GuestFileRead on success.
 #
 # Since: 0.15.0
 ##
-{ 'type': 'GuestFileRead',
-  'data': { 'count': 'int', 'buf-b64': 'str', 'eof': 'bool' } }
-
 { 'command': 'guest-file-read',
   'data':{ 'handle': 'int', '*count': 'int' },
   'returns': 'GuestFileRead' }
 
 ##
+# @GuestFileWrite
+#
+# Result of guest agent file-write operation
+#
+# @count: number of bytes written (note: count is actual bytes
+# written, after base64-decoding of provided buffer)
+#
+# @eof: whether EOF was encountered during write operation.
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestFileWrite',
+  'data': { 'count': 'int', 'eof': 'bool' } }
+
+##
 # @guest-file-write:
 #
 # Write to an open file in the guest.
@@ -130,17 +183,29 @@
 # @count: #optional bytes to write (actual bytes, after base64-decode),
 # default is all content in buf-b64 buffer after base64 decoding
 #
-# Returns: GuestFileWrite on success. Note: count is the number of bytes
-#  base64-decoded bytes written
+# Returns: @GuestFileWrite on success.
 #
 # Since: 0.15.0
 ##
-{ 'type': 'GuestFileWrite',
-  'data': { 'count': 'int', 'eof': 'bool' } }
 { 'command': 'guest-file-write',
   'data':{ 'handle': 'int', 'buf-b64': 'str', '*count': 'int' },
   'returns': 'GuestFileWrite' }
 
+
+##
+# @GuestFileSeek
+#
+# Result of guest agent file-seek operation
+#
+# @position: current file position
+#
+# @eof: whether EOF was encountered during file seek
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestFileSeek',
+  'data': { 'position': 'int', 'eof': 'bool' } }
+
 ##
 # @guest-file-seek:
 #
@@ -154,13 +219,10 @@
 #
 # @whence: SEEK_SET, SEEK_CUR, or SEEK_END, as with fseek()
 #
-# Returns: GuestFileSeek on success.
+# Returns: @GuestFileSeek on success.
 #
 # Since: 0.15.0
 ##
-{ 'type': 'GuestFileSeek',
-  'data': { 'position': 'int', 'eof': 'bool' } }
-
 { 'command': 'guest-file-seek',
   'data':{ 'handle': 'int', 'offset': 'int', 'whence': 'in

[Qemu-devel] [PATCH 4/6] qemu-ga: add guest-set-support-level command

2012-01-25 Thread Michael Roth
Recently commands where introduced on the mailing that involved adding
commands to the guest agent that could potentially break older versions
of QEMU. While it's okay to expect that qemu-ga can be updated to support
newer host features, it's unrealistic to require a host to be updated to
support qemu-ga features, or to expect that qemu-ga should be downgraded
in these circumstances, especially considering that a large mix of
guests/agents may be running on a particular host.

To address this, we introduce here a mechanism to set qemu-ga's
feature-set to one that is known to be compatible with
the host/QEMU running the guest. As new commands/options are added, we
can maintain backward-compatibility by adding conditional checks to filter
out host-incompatible functionality based on the host-specified support
level (generally analogous to the host QEMU version) set by the
client.

The current default/minimum support level supports all versions of QEMU
that have had qemu-ga in-tree (0.15.0, 1.0.0) and so should be
backward-compatible with existing hosts/clients.

Signed-off-by: Michael Roth 
---
 qapi-schema-guest.json |   67 +++-
 qemu-ga.c  |   46 ++
 qga/guest-agent-commands.c |   13 
 qga/guest-agent-core.h |   11 +++
 4 files changed, 136 insertions(+), 1 deletions(-)

diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json
index 706925d..81cd773 100644
--- a/qapi-schema-guest.json
+++ b/qapi-schema-guest.json
@@ -51,6 +51,27 @@
   'data': { 'name': 'str', 'enabled': 'bool' } }
 
 ##
+# @GuestAgentSupportLevel
+#
+# Guest agent support/compatability level (as configured by
+# guest agent defaults of guest-set-support-level command)
+#
+# Three numerical fields describe the support level:
+#
+# ..
+#
+# @major: As above
+#
+# @minor: As above
+#
+# @micro: As above
+#
+# Since 1.1.0
+##
+{ 'type': 'GuestAgentSupportLevel',
+  'data': { 'major': 'int', 'minor': 'int', 'micro': 'int' } }
+
+##
 # @GuestAgentInfo
 #
 # Information about guest agent.
@@ -59,11 +80,17 @@
 #
 # @supported_commands: Information about guest agent commands
 #
+# @support_level: Current support/compatability level, as set by
+# guest agent defaults or guest-set-support-level
+# command.
+#
 # Since 0.15.0
 ##
 { 'type': 'GuestAgentInfo',
   'data': { 'version': 'str',
-'supported_commands': ['GuestAgentCommandInfo'] } }
+'supported_commands': ['GuestAgentCommandInfo']
+'support_level': 'GuestAgentSupportLevel' } }
+
 ##
 # @guest-info:
 #
@@ -77,6 +104,44 @@
   'returns': 'GuestAgentInfo' }
 
 ##
+# @guest-set-support-level:
+#
+# Set guest agent feature-set to one that is compatible with/supported by
+# the host.
+#
+# Certain commands/options may have dependencies on host
+# version/support-level, such as specific QEMU features (such
+# dependencies will be noted in this schema). By default we assume 1.0.0,
+# which is backward-compatible with QEMU 0.15.0/1.0, and should be compatible
+# with later versions of QEMU as well. To enable newer guest agent features,
+# this command must be issued to raise the support-level to one corresponding
+# to supported host QEMU/KVM/etc capabilities.
+#
+# The host support-level is generally <= host QEMU version
+# level. Note that undefined behavior may occur if a support-level is
+# provided that exceeds the capabilities of the version of QEMU currently
+# running the guest. Any level specified below 1.0.0 will default to 1.0.0.
+#
+# The currently set support level is obtainable via the guest-info command.
+#
+# Three numerical fields describe the host support/compatability level:
+#
+# ..
+#
+# @major: As above
+#
+# @minor: As above
+#
+# @micro: As above
+#
+# Returns: Nothing on success
+#
+# Since: 1.1.0
+##
+{ 'command': 'guest-set-support-level',
+  'data':{ 'major': 'int', 'minor': 'int', '*micro': 'int' } }
+
+##
 # @guest-shutdown:
 #
 # Initiate guest-activated shutdown. Note: this is an asynchronous
diff --git a/qemu-ga.c b/qemu-ga.c
index 29e4f64..8e5b075 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -28,6 +28,7 @@
 #include "qerror.h"
 #include "error_int.h"
 #include "qapi/qmp-core.h"
+#include "qga-qapi-types.h"
 
 #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0"
 #define QGA_PIDFILE_DEFAULT "/var/run/qemu-ga.pid"
@@ -102,6 +103,45 @@ static void usage(const char *cmd)
 
 static void conn_channel_close(GAState *s);
 
+static GuestAgentSupportL

[Qemu-devel] [PATCH 2/6] main-loop: For tools, initialize timers as part of qemu_init_main_loop()

2012-01-25 Thread Michael Roth
In some cases initializing the alarm timers can lead to non-negligable
overhead from programs that link against qemu-tool.o. At least,
setting a max-resolution WinMM alarm timer via mm_start_timer() (the
current default for Windows) can increase the "tick rate" on Windows
OSs and affect frequency scaling, and in the case of tools that run
in guest OSs such has qemu-ga, the impact can be fairly dramatic
(+20%/20% user/sys time on a core 2 processor was observed from an idle
Windows XP guest).

This patch doesn't address the issue directly (not sure what a good
solution would be for Windows, or what other situations it might be
noticeable), but it at least limits the scope of the issue to programs
that "opt-in" to using the main-loop.c functions by only enabling alarm
timers when qemu_init_main_loop() is called, which is already required
to make use of those facilities, so existing users shouldn't be
affected.

Signed-off-by: Michael Roth 
---
 main-loop.c |2 +-
 main-loop.h |   12 
 qemu-tool.c |3 ++-
 vl.c|5 +
 4 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/main-loop.c b/main-loop.c
index 62d95b9..db23de0 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -199,7 +199,7 @@ static int qemu_signal_init(void)
 }
 #endif
 
-int qemu_init_main_loop(void)
+int main_loop_init(void)
 {
 int ret;
 
diff --git a/main-loop.h b/main-loop.h
index f971013..4987041 100644
--- a/main-loop.h
+++ b/main-loop.h
@@ -41,10 +41,22 @@
  * SIGUSR2, thread signals (SIGFPE, SIGILL, SIGSEGV, SIGBUS) and real-time
  * signals if available.  Remember that Windows in practice does not have
  * signals, though.
+ *
+ * In the case of QEMU tools, this will also start/initialize timers.
  */
 int qemu_init_main_loop(void);
 
 /**
+ * main_loop_init: Initializes main loop
+ *
+ * Internal (but shared for compatibility reasons) initialization routine
+ * for the main loop. This should not be used by applications directly,
+ * use qemu_init_main_loop() instead.
+ *
+ */
+int main_loop_init(void);
+
+/**
  * main_loop_wait: Run one iteration of the main loop.
  *
  * If @nonblocking is true, poll for events, otherwise suspend until
diff --git a/qemu-tool.c b/qemu-tool.c
index 6b69668..183a583 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -83,11 +83,12 @@ void qemu_clock_warp(QEMUClock *clock)
 {
 }
 
-static void __attribute__((constructor)) init_main_loop(void)
+int qemu_init_main_loop(void)
 {
 init_clocks();
 init_timer_alarm();
 qemu_clock_enable(vm_clock, false);
+return main_loop_init();
 }
 
 void slirp_select_fill(int *pnfds, fd_set *readfds,
diff --git a/vl.c b/vl.c
index 57378b6..9d14cc8 100644
--- a/vl.c
+++ b/vl.c
@@ -2159,6 +2159,11 @@ static void free_and_trace(gpointer mem)
 free(mem);
 }
 
+int qemu_init_main_loop(void)
+{
+return main_loop_init();
+}
+
 int main(int argc, char **argv, char **envp)
 {
 const char *gdbstub_dev = NULL;
-- 
1.7.4.1




Re: [Qemu-devel] [libvirt] [PATCH RFC 0/4] Allow hibernation on guests

2012-01-26 Thread Michael Roth

On 01/26/2012 02:13 PM, Luiz Capitulino wrote:

On Thu, 26 Jan 2012 20:41:13 +0100
Michal Privoznik  wrote:


On 26.01.2012 20:35, Luiz Capitulino wrote:

On Thu, 26 Jan 2012 08:18:03 -0700
Eric Blake  wrote:


[adding qemu-devel]

On 01/26/2012 07:46 AM, Daniel P. Berrange wrote:

One thing, that you'll probably notice is this
'set-support-level' command. Basically, it tells GA what qemu version
is it running on. Ideally, this should be done as soon as
GA starts up. However, that cannot be determined from outside
world as GA doesn't emit any events yet.
Ideally^2 this command should be left out as it should be qemu
who tells its own agent this kind of information.
Anyway, I was going to call this command in qemuProcess{Startup,
Reconnect,Attach}, but it won't work. We need to un-pause guest CPUs
so guest can boot and start GA, but that implies returning from qemuProcess*.

So I am setting this just before 'guest-suspend' command, as
there is one more thing about GA. It is unable to remember anything
upon its restart (GA process). Which has BTW show flaw
in our current code with FS freeze&  thaw. If we freeze guest
FS, and somebody restart GA, the simple FS Thaw will not succeed as
GA thinks FS are not frozen. But that's a different cup of tea.

Because of what written above, we need to call set-level
on every suspend.



IMHO all this says that the 'set-level' command is a conceptually
unfixably broken design&  should be killed in QEMU before it turns
into an even bigger mess.


Can you elaborate on this? Michal and I talked on irc about making the
compatibility level persistent, would that help?


Once we're in a situation where we need to call 'set-level' prior
to every single invocation, you might as well just allow the QEMU
version number to be passed in directly as an arg to the command
you are running directly thus avoiding this horrificness.


Qemu folks, would you care to chime in on this?

Exactly how is the set-level command supposed to work?  As I understand
it, the goal is that if the guest has qemu-ga 1.1 installed, but is
being run by qemu 1.0, then we want to ensure that any guest agent
command supported by qemu-ga 1.1 but requiring features of qemu not
present in qemu 1.0 will be properly rejected.


Not exactly, the default support of qemu-ga is qemu 1.0. This means that by
default qemu-ga will only support qemu 1.0 even when running on qemu 2.0. This
way the set-support-level command allows you to specify that qemu 2.0 features
are supported.

Note that this is only about specific features that depend on host support,
like S3 suspend which is known to be buggy in current and old qemu.


But whose job is it to tell the guest agent what version of qemu is
running?  Based on the above conversation, it looks like the current
qemu implementation does not do any handshaking on its own when the
guest agent first comes alive, which means that you are forcing the work
on the management app (libvirt).  And this is inherently racy - if the
guest is allowed to restart its qemu-ga process at will, and each
restart of that guest process triggers a need to redo the handshake,
then libvirt can never reliably know what version the agent is running at.


Making the set-support-level persistent would solve it, wouldn't it?


Yes and no. We still need an event when GA come to live. Because if
anybody tries to write something for GA which is not running (and for
purpose of this scenario assume it never will), like 'set-support-level'
and wait for answer (which will never come) he will be blocked
indefinitely. However, if he writes it after 1st event come, everything
is OK.


What if the event never reach libvirt?

This problem is a lot more general and is not related to the
set-support-level command. Maybe adding shutdown&  start events can serve as
good hints, but they won't fix the problem.


Yah, start up events are a good indicator to issue the guest-sync 
sequence (we had them at one point, and planned to re-add them for QMP 
integration, and since libvirt is taking on this role for now it might 
make sense to re-add it now), but once that sequence is issued the agent 
can still be manually stopped, or the guest-sync sequence itself can 
timeout.


And there's no way to reliably send a stop indicator, maybe to capture 
shutdown events, but not consistently enough that we can base the 
protocol on it (agent might get pkill -9'd for instance, and 
virtio-serial doesn't currently plumb a guest-side disconnect to the 
chardev front-end, so you'd never know).


So, the only indication you'll ever get that your "session" ended is 
either a timeout, or, if we add it, a start up event. In either case the 
response is to issue the reset sequence.


The way it would need to work with resets is everytime a command times 
out you:


1) report the timeout error to libvirt client/management app. set 
guest-agent_available = 0, such that further libvirt calls that depend 
on it would return "not currently available",

Re: [Qemu-devel] [libvirt] [PATCH RFC 0/4] Allow hibernation on guests

2012-01-26 Thread Michael Roth

On 01/26/2012 09:18 AM, Eric Blake wrote:

[adding qemu-devel]

On 01/26/2012 07:46 AM, Daniel P. Berrange wrote:

One thing, that you'll probably notice is this
'set-support-level' command. Basically, it tells GA what qemu version
is it running on. Ideally, this should be done as soon as
GA starts up. However, that cannot be determined from outside
world as GA doesn't emit any events yet.
Ideally^2 this command should be left out as it should be qemu
who tells its own agent this kind of information.
Anyway, I was going to call this command in qemuProcess{Startup,
Reconnect,Attach}, but it won't work. We need to un-pause guest CPUs
so guest can boot and start GA, but that implies returning from qemuProcess*.

So I am setting this just before 'guest-suspend' command, as
there is one more thing about GA. It is unable to remember anything
upon its restart (GA process). Which has BTW show flaw
in our current code with FS freeze&  thaw. If we freeze guest
FS, and somebody restart GA, the simple FS Thaw will not succeed as
GA thinks FS are not frozen. But that's a different cup of tea.


We could drop the state tracking (guest-fsfreeze-status) and issue the 
freeze/thaw unconditionally. Talked with Anthony and going stateless in 
general seems to solve a lot of nastiness that might pop up with the 
current implementation. I'll send some patches out soon for fsfreeze, 
guest-file* may end up getting similar treatment in the 
not-too-distant-future.





[Qemu-devel] [PATCH v2] main-loop: Fix SetEvent() on uninitialized handle on win32

2012-01-27 Thread Michael Roth
The __attribute__((constructor)) init_main_loop() automatically get
called if qemu-tool.o is linked in. On win32, this leads to
a qemu_notify_event() call which attempts to SetEvent() on a HANDLE that
won't be initialized until qemu_init_main_loop() is manually called,
breaking qemu-tools.o programs on Windows at runtime.

This patch checks for an initialized event handle before attempting to
set it, which is analoguous to how we deal with an unitialized
io_thread_fd in the posix implementation.

Signed-off-by: Michael Roth 
---
 main-loop.c |3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/main-loop.c b/main-loop.c
index 692381c..db90ace 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -183,6 +183,9 @@ static int qemu_event_init(void)
 
 void qemu_notify_event(void)
 {
+if (!qemu_event_handle) {
+return;
+}
 if (!SetEvent(qemu_event_handle)) {
 fprintf(stderr, "qemu_notify_event: SetEvent failed: %ld\n",
 GetLastError());
-- 
1.7.4.1




Re: [Qemu-devel] [libvirt] [PATCH RFC 0/4] Allow hibernation on guests

2012-01-30 Thread Michael Roth

On 01/30/2012 06:57 AM, Luiz Capitulino wrote:

On Thu, 26 Jan 2012 16:57:01 -0600
Anthony Liguori  wrote:


On 01/26/2012 01:35 PM, Luiz Capitulino wrote:

On Thu, 26 Jan 2012 08:18:03 -0700
Eric Blake   wrote:


[adding qemu-devel]

On 01/26/2012 07:46 AM, Daniel P. Berrange wrote:

One thing, that you'll probably notice is this
'set-support-level' command. Basically, it tells GA what qemu version
is it running on. Ideally, this should be done as soon as
GA starts up. However, that cannot be determined from outside
world as GA doesn't emit any events yet.
Ideally^2 this command should be left out as it should be qemu
who tells its own agent this kind of information.
Anyway, I was going to call this command in qemuProcess{Startup,
Reconnect,Attach}, but it won't work. We need to un-pause guest CPUs
so guest can boot and start GA, but that implies returning from qemuProcess*.

So I am setting this just before 'guest-suspend' command, as
there is one more thing about GA. It is unable to remember anything
upon its restart (GA process). Which has BTW show flaw
in our current code with FS freeze&   thaw. If we freeze guest
FS, and somebody restart GA, the simple FS Thaw will not succeed as
GA thinks FS are not frozen. But that's a different cup of tea.

Because of what written above, we need to call set-level
on every suspend.



IMHO all this says that the 'set-level' command is a conceptually
unfixably broken design&   should be killed in QEMU before it turns
into an even bigger mess.


Can you elaborate on this? Michal and I talked on irc about making the
compatibility level persistent, would that help?


Once we're in a situation where we need to call 'set-level' prior
to every single invocation, you might as well just allow the QEMU
version number to be passed in directly as an arg to the command
you are running directly thus avoiding this horrificness.


Qemu folks, would you care to chime in on this?

Exactly how is the set-level command supposed to work?  As I understand
it, the goal is that if the guest has qemu-ga 1.1 installed, but is
being run by qemu 1.0, then we want to ensure that any guest agent
command supported by qemu-ga 1.1 but requiring features of qemu not
present in qemu 1.0 will be properly rejected.


Not exactly, the default support of qemu-ga is qemu 1.0. This means that by
default qemu-ga will only support qemu 1.0 even when running on qemu 2.0. This
way the set-support-level command allows you to specify that qemu 2.0 features
are supported.


Version numbers are meaningless.  What happens when a bunch of features get
backported by RHEL such that qemu-ga 1.0 ends up being a frankenstein version of
2.0?

The feature negotiation mechanism we have in QMP is the existence of a command.
   If we're in a position where we're trying to disable part of a command, it
simply means that we should have multiple commands such that we can just remove
the disabled part entirely.


You may have a point that we shouldn't be using the version number for that,
but just switching to multiple commands doesn't solve the fundamental problem.


Agreed, but the multiple commands isn't really the fix here, it's 
libvirt querying for the "wakeup" command that Gerd's patches add.


We implemented set-version-level as a way to let management tools 
obliviously report something simple, like the version information it 
parses from QEMU already, to let the guest agent Do The Right Thing 
without any deep insight into what it's host requirements are (which is 
also why we opted for versions over specific capabilities flags).


But we can't rely on version levels applying in all cases, a distro 
might backport s3 support for 1.0, modify the guest agent version level 
dependencies accordingly, and thus render the that agent incompatible 
with, say, RHEL.


So it was a naive approach on my part, and the issues the libvirt folks 
noted with not knowing if a reset occurred since the last 
set-support-level make it even less desirable (we could persist it as 
you suggested, and I am working on patches to persist fsfreeze state, 
but it's not worth trying to fix set-support-level).


And at least in this case we have an easy out: libvirt knows it can't 
resume a guest without the presence of a QMP command to do so, and that 
doesn't require any intimate knowledge of how the agent works, it's just 
common sense.


Breaking the suspend/hibernate stuff into multiple commands avoids the 
need for libvirt to special case based on specific parameters to the 
command. We can also imagine distro-specific implementations of the 
agent disabling s4 due to things like not having s4 patches for virtio 
in place, so it makes it easier (possible) to discover those situations 
as well. It may be that we opt for a single command for libvirt, but at 
least on the agent side it should be multiple discoverable ones.


Hopefully this doesn't set anyone back too much :( IMHO it's the right 
way to go though.




The fundamental problem is t

Re: [Qemu-devel] [libvirt] [PATCH RFC 0/4] Allow hibernation on guests

2012-01-30 Thread Michael Roth

On 01/30/2012 08:44 AM, Luiz Capitulino wrote:

On Mon, 30 Jan 2012 07:54:56 -0600
Anthony Liguori  wrote:


On 01/30/2012 06:57 AM, Luiz Capitulino wrote:

On Thu, 26 Jan 2012 16:57:01 -0600
Anthony Liguori   wrote:


On 01/26/2012 01:35 PM, Luiz Capitulino wrote:

On Thu, 26 Jan 2012 08:18:03 -0700
Eric Blakewrote:


[adding qemu-devel]

On 01/26/2012 07:46 AM, Daniel P. Berrange wrote:

One thing, that you'll probably notice is this
'set-support-level' command. Basically, it tells GA what qemu version
is it running on. Ideally, this should be done as soon as
GA starts up. However, that cannot be determined from outside
world as GA doesn't emit any events yet.
Ideally^2 this command should be left out as it should be qemu
who tells its own agent this kind of information.
Anyway, I was going to call this command in qemuProcess{Startup,
Reconnect,Attach}, but it won't work. We need to un-pause guest CPUs
so guest can boot and start GA, but that implies returning from qemuProcess*.

So I am setting this just before 'guest-suspend' command, as
there is one more thing about GA. It is unable to remember anything
upon its restart (GA process). Which has BTW show flaw
in our current code with FS freeze&thaw. If we freeze guest
FS, and somebody restart GA, the simple FS Thaw will not succeed as
GA thinks FS are not frozen. But that's a different cup of tea.

Because of what written above, we need to call set-level
on every suspend.



IMHO all this says that the 'set-level' command is a conceptually
unfixably broken design&should be killed in QEMU before it turns
into an even bigger mess.


Can you elaborate on this? Michal and I talked on irc about making the
compatibility level persistent, would that help?


Once we're in a situation where we need to call 'set-level' prior
to every single invocation, you might as well just allow the QEMU
version number to be passed in directly as an arg to the command
you are running directly thus avoiding this horrificness.


Qemu folks, would you care to chime in on this?

Exactly how is the set-level command supposed to work?  As I understand
it, the goal is that if the guest has qemu-ga 1.1 installed, but is
being run by qemu 1.0, then we want to ensure that any guest agent
command supported by qemu-ga 1.1 but requiring features of qemu not
present in qemu 1.0 will be properly rejected.


Not exactly, the default support of qemu-ga is qemu 1.0. This means that by
default qemu-ga will only support qemu 1.0 even when running on qemu 2.0. This
way the set-support-level command allows you to specify that qemu 2.0 features
are supported.


Version numbers are meaningless.  What happens when a bunch of features get
backported by RHEL such that qemu-ga 1.0 ends up being a frankenstein version of
2.0?

The feature negotiation mechanism we have in QMP is the existence of a command.
If we're in a position where we're trying to disable part of a command, it
simply means that we should have multiple commands such that we can just remove
the disabled part entirely.


You may have a point that we shouldn't be using the version number for that,
but just switching to multiple commands doesn't solve the fundamental problem.

The fundamental problem is that, S3 in current (and old) qemu has two known 
bugs:

   1. The screen is left black after S3 (it's a bug in seabios)
   2. QEMU resumes the guest immediately (Gerd posted patches to address this)

We're going to address both issues in 1.1. However, if qemu-ga is installed in
an old qemu and S3 is used, the bugs will be triggered.


It's a management tool problem.

Before a management tool issues a command, it should query the existence of the
command to determine whether this version of QEMU has that capability.  If the
tool needs to use two commands, it should query the existence of both of them.

In this case, the management tool needs a qemu-ga command *and* a QEMU command
(to resume from suspend) so it should query both of them.

Obviously, we wouldn't have a resume-from-suspend command in QEMU unless it S3
worked in QEMU as expected.


That's right, it's a coincidence, but I don't see why this wouldn't work.

I think we should do the following then:

  1. Drop the set-support-level command
  2. Split the guest-suspend command into guest-suspend-ram, 
guest-suspend-hybrid,
 guest-suspend-disk
  3. Libvirt should query for _QEMU_'s 'wakeup' command before issuing
 the guest-suspend-ram command

Michal, Michael, do you agree?


Yup yup, looks sound to me.




Alternatively, if there really was no reason to have a resume-from-suspend
command, this would be the point where we would add a capabilities command
adding the "working-s3" capability.

But with capabilities, this is a direct QEMU->management tool interaction, not a
proxy through the guest agent.

We shouldn't trust the guest agent and we certainly don't want to rely on the
guest agent to avoid sending an improper command to QEMU!  That would be a
security 

Re: [Qemu-devel] [libvirt] [PATCH RFC 0/4] Allow hibernation on guests

2012-01-30 Thread Michael Roth

On 01/30/2012 09:58 AM, Eric Blake wrote:

On 01/30/2012 07:44 AM, Luiz Capitulino wrote:

I think we should do the following then:

  1. Drop the set-support-level command
  2. Split the guest-suspend command into guest-suspend-ram, 
guest-suspend-hybrid,
 guest-suspend-disk
  3. Libvirt should query for _QEMU_'s 'wakeup' command before issuing
 the guest-suspend-ram command

Michal, Michael, do you agree?


I'm not Michal, but speaking for libvirt, this definitely sounds like
the way to go.

Questions:

Should libvirt also check for 'wakeup' before attempting
guest-suspend-hybrid?

With guest-suspend-disk, what happens when the suspend completes?  Does
this look like a normal case of the guest powering down, which qemu then
passes as an event to libvirt and libvirt then ends the qemu process?
That would mean that the only difference from a normal guest shutdown is
that on the next guest boot the guest's disk image allows to recover
state from disk rather than booting from scratch; either way, a new qemu
process is created to resume the guest, and qemu is doing nothing
different in how it starts the guest (it's just that the guest itself
does something different based on what it stored into the disk images
before shutting down).

Also, I know there has been talk about a qemu-ga command to resync
clocks after a resume from S3 and/or 'loadvm'; is this command fully in
place yet, and is it another command that libvirt should be checking for
prior to allowing any S3 attempts?



Hi Eric,

I'm not aware of a clock re-sync command being worked on.. are we maybe 
talking about the guest-sync command qemu-ga currently has in place to 
re-sync the protocol stream after a client-side timeout?





Re: [Qemu-devel] [RFC Patch 3/7]Qemu: Cmd "block_set_hostcache" for dynamic cache change

2012-02-01 Thread Michael Roth

On 01/31/2012 09:06 PM, Supriya Kannery wrote:

New command "block_set_hostcache" added for dynamically changing
host pagecache setting of a block device.

Usage:
  block_set_hostcache  
  = block device
  = on/off

Example:
  (qemu) block_set_hostcache ide0-hd0 off

Signed-off-by: Supriya Kannery

---
  block.c |   54 ++
  block.h |2 ++
  blockdev.c  |   26 ++
  blockdev.h  |2 ++
  hmp-commands.hx |   14 ++
  qmp-commands.hx |   27 +++
  6 files changed, 125 insertions(+)

Index: qemu/block.c
===
--- qemu.orig/block.c
+++ qemu/block.c
@@ -808,6 +808,35 @@ unlink_and_fail:
  return ret;
  }

+int bdrv_reopen(BlockDriverState *bs, int bdrv_flags)
+{
+BlockDriver *drv = bs->drv;
+int ret = 0, open_flags;
+
+/* Quiesce IO for the given block device */
+qemu_aio_flush();
+ret = bdrv_flush(bs);
+if (ret != 0) {
+qerror_report(QERR_DATA_SYNC_FAILED, bs->device_name);
+return ret;
+}
+open_flags = bs->open_flags;
+bdrv_close(bs);
+
+ret = bdrv_open(bs, bs->filename, bdrv_flags, drv);
+if (ret<  0) {
+/* Reopen failed. Try to open with original flags */
+qerror_report(QERR_REOPEN_FILE_FAILED, bs->filename);
+ret = bdrv_open(bs, bs->filename, open_flags, drv);
+if (ret<  0) {
+/* Reopen failed with orig and modified flags */
+abort();
+}
+}
+
+return ret;
+}
+
  void bdrv_close(BlockDriverState *bs)
  {
  if (bs->drv) {
@@ -870,6 +899,33 @@ void bdrv_drain_all(void)
  }
  }

+int bdrv_change_hostcache(BlockDriverState *bs, bool enable_host_cache)
+{
+int bdrv_flags = bs->open_flags;
+
+/* set hostcache flags (without changing WCE/flush bits) */
+if (enable_host_cache) {
+bdrv_flags&= ~BDRV_O_NOCACHE;
+} else {
+bdrv_flags |= BDRV_O_NOCACHE;
+}
+
+/* If no change in flags, no need to reopen */
+if (bdrv_flags == bs->open_flags) {
+return 0;
+}
+
+if (bdrv_is_inserted(bs)) {
+/* Reopen file with changed set of flags */
+bdrv_flags&= ~BDRV_O_CACHE_WB;
+return bdrv_reopen(bs, bdrv_flags);


It seems like the real interface we're wanting here is bdrv_set_flags(), 
or something along that line, with the re-opening being more of an 
implementation detail.


For instance, with raw-posix.c:raw_reopen_prepare() we'll end up 
skipping the re-opening completely if fcntl() is sufficient.



+} else {
+/* Save hostcache change for future use */
+bs->open_flags = bdrv_flags;
+return 0;
+}
+}
+
  /* make a BlockDriverState anonymous by removing from bdrv_state list.
 Also, NULL terminate the device_name to prevent double remove */
  void bdrv_make_anon(BlockDriverState *bs)
Index: qemu/block.h
===
--- qemu.orig/block.h
+++ qemu/block.h
@@ -119,6 +119,7 @@ int bdrv_parse_cache_flags(const char *m
  int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
  int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
BlockDriver *drv);
+int bdrv_reopen(BlockDriverState *bs, int bdrv_flags);
  void bdrv_close(BlockDriverState *bs);
  int bdrv_attach_dev(BlockDriverState *bs, void *dev);
  void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev);
@@ -160,6 +161,7 @@ void bdrv_commit_all(void);
  int bdrv_change_backing_file(BlockDriverState *bs,
  const char *backing_file, const char *backing_fmt);
  void bdrv_register(BlockDriver *bdrv);
+int bdrv_change_hostcache(BlockDriverState *bs, bool enable_host_cache);


  typedef struct BdrvCheckResult {
Index: qemu/blockdev.c
===
--- qemu.orig/blockdev.c
+++ qemu/blockdev.c
@@ -1080,3 +1080,29 @@ BlockJobInfoList *qmp_query_block_jobs(E
  bdrv_iterate(do_qmp_query_block_jobs_one,&prev);
  return dummy.next;
  }
+
+
+/*
+ * Change host page cache setting while guest is running.
+*/
+int do_block_set_hostcache(Monitor *mon, const QDict *qdict,
+   QObject **ret_data)
+{
+BlockDriverState *bs = NULL;
+int enable;
+const char *device;
+
+/* Validate device */
+device = qdict_get_str(qdict, "device");
+bs = bdrv_find(device);
+if (!bs) {
+qerror_report(QERR_DEVICE_NOT_FOUND, device);
+return -1;
+}
+
+/* Read hostcache setting */
+enable = qdict_get_bool(qdict, "option");
+return bdrv_change_hostcache(bs, enable);
+
+}
+
Index: qemu/blockdev.h
===
--- qemu.orig/blockdev.h
+++ qemu/blockdev.h
@@ -62,4 +62,6 @@ void qmp_change_blockdev(const char *dev
   bool has_format, c

Re: [Qemu-devel] [RFC Patch 5/7]Qemu: raw-posix image file reopen

2012-02-01 Thread Michael Roth

On 01/31/2012 09:07 PM, Supriya Kannery wrote:

raw-posix driver changes for bdrv_reopen_xx functions to
safely reopen image files. Reopening of image files while
changing hostcache dynamically is handled here.

Signed-off-by: Supriya Kannery

Index: qemu/block/raw.c
===
--- qemu.orig/block/raw.c
+++ qemu/block/raw.c
@@ -9,6 +9,22 @@ static int raw_open(BlockDriverState *bs
  return 0;
  }

+static int raw_reopen_prepare(BlockDriverState *bs, BDRVReopenState **prs,
+  int flags)
+{
+return bdrv_reopen_prepare(bs->file, prs, flags);
+}
+
+static void raw_reopen_commit(BlockDriverState *bs, BDRVReopenState *rs)
+{
+bdrv_reopen_commit(bs->file, rs);
+}
+
+static void raw_reopen_abort(BlockDriverState *bs, BDRVReopenState *rs)
+{
+bdrv_reopen_abort(bs->file, rs);
+}
+
  static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num,
   int nb_sectors, QEMUIOVector *qiov)
  {
@@ -109,6 +125,10 @@ static BlockDriver bdrv_raw = {
  .instance_size  = 1,

  .bdrv_open  = raw_open,
+.bdrv_reopen_prepare
+= raw_reopen_prepare,
+.bdrv_reopen_commit = raw_reopen_commit,
+.bdrv_reopen_abort  = raw_reopen_abort,
  .bdrv_close = raw_close,

  .bdrv_co_readv  = raw_co_readv,
Index: qemu/block/raw-posix.c
===
--- qemu.orig/block/raw-posix.c
+++ qemu/block/raw-posix.c
@@ -136,6 +136,11 @@ typedef struct BDRVRawState {
  #endif
  } BDRVRawState;

+typedef struct BDRVRawReopenState {
+BDRVReopenState reopen_state;
+BDRVRawState *stash_s;
+} BDRVRawReopenState;
+
  static int fd_open(BlockDriverState *bs);
  static int64_t raw_getlength(BlockDriverState *bs);

@@ -279,6 +284,71 @@ static int raw_open(BlockDriverState *bs
  return raw_open_common(bs, filename, flags, 0);
  }

+static int raw_reopen_prepare(BlockDriverState *bs, BDRVReopenState **prs,
+  int flags)
+{
+BDRVRawReopenState *raw_rs = g_malloc0(sizeof(BDRVRawReopenState));
+BDRVRawState *s = bs->opaque;
+int ret = 0;
+
+raw_rs->reopen_state.bs = bs;
+
+/* stash state before reopen */
+raw_rs->stash_s = g_malloc0(sizeof(BDRVRawState));
+memcpy(raw_rs->stash_s, s, sizeof(BDRVRawState));
+s->fd = dup(raw_rs->stash_s->fd);
+
+*prs =&(raw_rs->reopen_state);
+
+/* Flags that can be set using fcntl */
+int fcntl_flags = BDRV_O_NOCACHE;
+
+if ((bs->open_flags&  ~fcntl_flags) == (flags&  ~fcntl_flags)) {
+if ((flags&  BDRV_O_NOCACHE)) {
+s->open_flags |= O_DIRECT;
+} else {
+s->open_flags&= ~O_DIRECT;
+}
+printf("O_DIRECT flag\n");
+ret = fcntl_setfl(s->fd, s->open_flags);


raw-posix.c:raw_aio_submit() does some extra alignment work if 
s->aligned_buf was set due to the image being opened O_DIRECT initially, 
not sure what the impact is but probably want to clean that up here.



+} else {
+
+printf("close and open with new flags\n");
+/* close and reopen using new flags */
+bs->drv->bdrv_close(bs);
+ret = bs->drv->bdrv_file_open(bs, bs->filename, flags);
+}
+return ret;
+}
+
+static void raw_reopen_commit(BlockDriverState *bs, BDRVReopenState *rs)
+{
+BDRVRawReopenState *raw_rs;
+
+raw_rs = container_of(rs, BDRVRawReopenState, reopen_state);
+
+/* clean up stashed state */
+close(raw_rs->stash_s->fd);
+g_free(raw_rs->stash_s);
+g_free(raw_rs);
+}
+
+static void raw_reopen_abort(BlockDriverState *bs, BDRVReopenState *rs)
+{
+BDRVRawReopenState *raw_rs;
+BDRVRawState *s = bs->opaque;
+
+raw_rs = container_of(rs, BDRVRawReopenState, reopen_state);
+
+/* revert to stashed state */
+if (s->fd != -1) {
+close(s->fd);
+}
+memcpy(s, raw_rs->stash_s, sizeof(BDRVRawState));
+g_free(raw_rs->stash_s);
+g_free(raw_rs);
+}
+
  /* XXX: use host sector size if necessary with:
  #ifdef DIOCGSECTORSIZE
  {
@@ -631,6 +701,9 @@ static BlockDriver bdrv_file = {
  .instance_size = sizeof(BDRVRawState),
  .bdrv_probe = NULL, /* no probe for protocols */
  .bdrv_file_open = raw_open,
+.bdrv_reopen_prepare = raw_reopen_prepare,
+.bdrv_reopen_commit = raw_reopen_commit,
+.bdrv_reopen_abort = raw_reopen_abort,
  .bdrv_close = raw_close,
  .bdrv_create = raw_create,
  .bdrv_co_discard = raw_co_discard,







[Qemu-devel] [PATCH v2 0/8] qemu-ga: add support for Windows

2012-02-02 Thread Michael Roth
These patches apply on top of qemu.git master, and can also be obtained from:
git://github.com/mdroth/qemu.git qga-win32-v2

Luiz/Gal, I decided not to roll the suspend/hibernate stuff into this series
since the s3 situation isn't fully sorted out yet. The file structure is a
little different now, posix/linux-specific stuff goes in qga/commands-posix.c,
win32-specific stuff in qga/commands-win32.c, but other than that it should be
a straightforward rebase if this gets merged first.

CHANGES SINCE V1:

- Dropped guest-set-support-level patch dependency
- Rebased on master and re-tested
- Spelling/grammar fixes in commits/comments

OVERVIEW:

These patches add support for Windows to the QEMU guest agent. With these
patches the following guest agent commands are supported on Windows:

guest-ping
guest-info
guest-sync
guest-shutdown

The guest-file* commands can essentially be enabled for Windows as-is, but since
mingw does not honor the O_NONBLOCK flag, they'll need to be reworked if we're
to retain the current non-blocking behavior.

The rest of the commands are currently stubbed out for Windows (qemu-ga will
return an "unsupported" error), but it should be easy to implement these going
forward with basic Windows support/infrastructure in place.

The build was tested using Fedora15 with a MinGW cross-build target via:

configure --enable-guest-agent --cross-prefix=i686-pc-mingw32-
make qemu-ga.exe

The executable was tested using Windows XP SP3, and partially tested using
Windows Server 2008 and Windows 7 (no I/O for the latter 2, having issues with
virtio-win drivers). GLib 2.28+ for Windows is required. You can install qemu-ga
as a load-on-boot service by running:

./qemu-ga --service install

And start/stop manually via:

net start qemu-ga
net stop qemu-ga

Many thanks to Gal Hammer for contributing the service integration and shutdown
code.

 Makefile   |2 +-
 Makefile.objs  |8 +-
 configure  |2 +-
 qapi-schema-guest.json |  118 --
 qemu-ga.c  |  413 ++-
 qga/channel-posix.c|  246 +++
 qga/channel-win32.c|  337 +
 qga/channel.h  |   33 +++
 qga/commands-posix.c   |  528 +++
 qga/commands-win32.c   |  130 ++
 qga/commands.c |   73 ++
 qga/guest-agent-commands.c |  585 
 qga/guest-agent-core.h |3 +-
 qga/service-win32.c|  114 +
 qga/service-win32.h|   30 +++
 15 files changed, 1782 insertions(+), 840 deletions(-)




[Qemu-devel] [PATCH v2 2/8] qemu-ga: move channel/transport functionality into wrapper class

2012-02-02 Thread Michael Roth
This is mostly in preparation for the win32 port, which won't use
GIO channels for reasons that will be made clearer later. Here the
GAChannel class is just a loose wrapper around GIOChannel
calls/callbacks, but we also roll in the logic/configuration for
various channel types and managing unix socket connections, which makes
the abstraction much more complete and further aids in the win32 port
since isa-serial/unix-listen will not be supported initially.

There's also a bit of refactoring in the main logic to consolidate the
exit paths so we can do common cleanup for things like pid files, which
weren't always cleaned up previously.

Signed-off-by: Michael Roth 
---
 Makefile.objs  |1 +
 qemu-ga.c  |  306 
 qga/channel-posix.c|  246 ++
 qga/channel.h  |   33 +
 qga/guest-agent-core.h |2 +-
 5 files changed, 355 insertions(+), 233 deletions(-)
 create mode 100644 qga/channel-posix.c
 create mode 100644 qga/channel.h

diff --git a/Makefile.objs b/Makefile.objs
index b942625..27ff919 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -425,6 +425,7 @@ common-obj-y += qmp.o hmp.o
 # guest agent
 
 qga-nested-y = guest-agent-commands.o guest-agent-command-state.o
+qga-nested-y += channel-posix.o
 qga-obj-y = $(addprefix qga/, $(qga-nested-y))
 qga-obj-y += qemu-ga.o qemu-sockets.o module.o qemu-option.o
 qga-obj-$(CONFIG_WIN32) += oslib-win32.o
diff --git a/qemu-ga.c b/qemu-ga.c
index 29e4f64..2e8af02 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -15,9 +15,7 @@
 #include 
 #include 
 #include 
-#include 
 #include 
-#include "qemu_socket.h"
 #include "json-streamer.h"
 #include "json-parser.h"
 #include "qint.h"
@@ -28,19 +26,15 @@
 #include "qerror.h"
 #include "error_int.h"
 #include "qapi/qmp-core.h"
+#include "qga/channel.h"
 
 #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0"
 #define QGA_PIDFILE_DEFAULT "/var/run/qemu-ga.pid"
-#define QGA_BAUDRATE_DEFAULT B38400 /* for isa-serial channels */
-#define QGA_TIMEOUT_DEFAULT 30*1000 /* ms */
 
 struct GAState {
 JSONMessageParser parser;
 GMainLoop *main_loop;
-GIOChannel *conn_channel;
-GIOChannel *listen_channel;
-const char *path;
-const char *method;
+GAChannel *channel;
 bool virtio; /* fastpath to check for virtio to deal with poll() quirks */
 GACommandState *command_state;
 GLogLevelFlags log_level;
@@ -59,7 +53,7 @@ static void quit_handler(int sig)
 }
 }
 
-static void register_signal_handlers(void)
+static gboolean register_signal_handlers(void)
 {
 struct sigaction sigact;
 int ret;
@@ -70,12 +64,14 @@ static void register_signal_handlers(void)
 ret = sigaction(SIGINT, &sigact, NULL);
 if (ret == -1) {
 g_error("error configuring signal handler: %s", strerror(errno));
-exit(EXIT_FAILURE);
+return false;
 }
 ret = sigaction(SIGTERM, &sigact, NULL);
 if (ret == -1) {
 g_error("error configuring signal handler: %s", strerror(errno));
+return false;
 }
+return true;
 }
 
 static void usage(const char *cmd)
@@ -100,8 +96,6 @@ static void usage(const char *cmd)
 , cmd, QGA_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT);
 }
 
-static void conn_channel_close(GAState *s);
-
 static const char *ga_log_level_str(GLogLevelFlags level)
 {
 switch (level & G_LOG_LEVEL_MASK) {
@@ -210,40 +204,13 @@ fail:
 exit(EXIT_FAILURE);
 }
 
-static int conn_channel_send_buf(GIOChannel *channel, const char *buf,
- gsize count)
-{
-GError *err = NULL;
-gsize written = 0;
-GIOStatus status;
-
-while (count) {
-status = g_io_channel_write_chars(channel, buf, count, &written, &err);
-g_debug("sending data, count: %d", (int)count);
-if (err != NULL) {
-g_warning("error sending newline: %s", err->message);
-return err->code;
-}
-if (status == G_IO_STATUS_ERROR || status == G_IO_STATUS_EOF) {
-return -EPIPE;
-}
-
-if (status == G_IO_STATUS_NORMAL) {
-count -= written;
-}
-}
-
-return 0;
-}
-
-static int conn_channel_send_payload(GIOChannel *channel, QObject *payload)
+static int send_response(GAState *s, QObject *payload)
 {
-int ret = 0;
 const char *buf;
 QString *payload_qstr;
-GError *err = NULL;
+GIOStatus status;
 
-g_assert(payload && channel);
+g_assert(payload && s->channel);
 
 payload_qstr = qobject_to_json(payload);
 if (!payload_qstr) {
@@ -252,24 +219,13 @@ static int conn_channel_send_payload(GIOChannel *channel, 
QObject *payload)
 
 qstring_append_chr(payload_qstr, '\n&#x

[Qemu-devel] [PATCH v2 1/8] qemu-ga: Add schema documentation for types

2012-02-02 Thread Michael Roth
Document guest agent schema types in similar fashion as qmp schema
types.

Signed-off-by: Michael Roth 
---
 qapi-schema-guest.json |  118 +++-
 1 files changed, 97 insertions(+), 21 deletions(-)

diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json
index 5f8a18d..706925d 100644
--- a/qapi-schema-guest.json
+++ b/qapi-schema-guest.json
@@ -37,17 +37,42 @@
 { 'command': 'guest-ping' }
 
 ##
-# @guest-info:
+# @GuestAgentCommandInfo:
 #
-# Get some information about the guest agent.
+# Information about guest agent commands.
 #
-# Since: 0.15.0
+# @name: name of the command
+#
+# @enabled: whether command is currently enabled by guest admin
+#
+# Since 1.1.0
 ##
 { 'type': 'GuestAgentCommandInfo',
   'data': { 'name': 'str', 'enabled': 'bool' } }
+
+##
+# @GuestAgentInfo
+#
+# Information about guest agent.
+#
+# @version: guest agent version
+#
+# @supported_commands: Information about guest agent commands
+#
+# Since 0.15.0
+##
 { 'type': 'GuestAgentInfo',
   'data': { 'version': 'str',
 'supported_commands': ['GuestAgentCommandInfo'] } }
+##
+# @guest-info:
+#
+# Get some information about the guest agent.
+#
+# Returns: @GuestAgentInfo
+#
+# Since: 0.15.0
+##
 { 'command': 'guest-info',
   'returns': 'GuestAgentInfo' }
 
@@ -98,6 +123,23 @@
   'data': { 'handle': 'int' } }
 
 ##
+# @GuestFileRead
+#
+# Result of guest agent file-read operation
+#
+# @count: number of bytes read (note: count is *before*
+# base64-encoding is applied)
+#
+# @buf-b64: base64-encoded bytes read
+#
+# @eof: whether EOF was encountered during read operation.
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestFileRead',
+  'data': { 'count': 'int', 'buf-b64': 'str', 'eof': 'bool' } }
+
+##
 # @guest-file-read:
 #
 # Read from an open file in the guest. Data will be base64-encoded
@@ -106,19 +148,30 @@
 #
 # @count: #optional maximum number of bytes to read (default is 4KB)
 #
-# Returns: GuestFileRead on success. Note: count is number of bytes read
-#  *before* base64 encoding bytes read.
+# Returns: @GuestFileRead on success.
 #
 # Since: 0.15.0
 ##
-{ 'type': 'GuestFileRead',
-  'data': { 'count': 'int', 'buf-b64': 'str', 'eof': 'bool' } }
-
 { 'command': 'guest-file-read',
   'data':{ 'handle': 'int', '*count': 'int' },
   'returns': 'GuestFileRead' }
 
 ##
+# @GuestFileWrite
+#
+# Result of guest agent file-write operation
+#
+# @count: number of bytes written (note: count is actual bytes
+# written, after base64-decoding of provided buffer)
+#
+# @eof: whether EOF was encountered during write operation.
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestFileWrite',
+  'data': { 'count': 'int', 'eof': 'bool' } }
+
+##
 # @guest-file-write:
 #
 # Write to an open file in the guest.
@@ -130,17 +183,29 @@
 # @count: #optional bytes to write (actual bytes, after base64-decode),
 # default is all content in buf-b64 buffer after base64 decoding
 #
-# Returns: GuestFileWrite on success. Note: count is the number of bytes
-#  base64-decoded bytes written
+# Returns: @GuestFileWrite on success.
 #
 # Since: 0.15.0
 ##
-{ 'type': 'GuestFileWrite',
-  'data': { 'count': 'int', 'eof': 'bool' } }
 { 'command': 'guest-file-write',
   'data':{ 'handle': 'int', 'buf-b64': 'str', '*count': 'int' },
   'returns': 'GuestFileWrite' }
 
+
+##
+# @GuestFileSeek
+#
+# Result of guest agent file-seek operation
+#
+# @position: current file position
+#
+# @eof: whether EOF was encountered during file seek
+#
+# Since: 0.15.0
+##
+{ 'type': 'GuestFileSeek',
+  'data': { 'position': 'int', 'eof': 'bool' } }
+
 ##
 # @guest-file-seek:
 #
@@ -154,13 +219,10 @@
 #
 # @whence: SEEK_SET, SEEK_CUR, or SEEK_END, as with fseek()
 #
-# Returns: GuestFileSeek on success.
+# Returns: @GuestFileSeek on success.
 #
 # Since: 0.15.0
 ##
-{ 'type': 'GuestFileSeek',
-  'data': { 'position': 'int', 'eof': 'bool' } }
-
 { 'command': 'guest-file-seek',
   'data':{ 'handle': 'int', 'offset': 'int', 'whence': 'in

[Qemu-devel] [PATCH v2 8/8] qemu-ga: add win32 guest-shutdown command

2012-02-02 Thread Michael Roth
Implement guest-shutdown RPC for Windows. Functionally this should be
equivalent to the posix implementation.

Original patch by Gal Hammer 

Signed-off-by: Michael Roth 
---
 qga/commands-win32.c |   41 -
 1 files changed, 40 insertions(+), 1 deletions(-)

diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index d96f1ad..4aa0f0d 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -15,9 +15,48 @@
 #include "qga-qmp-commands.h"
 #include "qerror.h"
 
+#ifndef SHTDN_REASON_FLAG_PLANNED
+#define SHTDN_REASON_FLAG_PLANNED 0x8000
+#endif
+
 void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
 {
-error_set(err, QERR_UNSUPPORTED);
+HANDLE token;
+TOKEN_PRIVILEGES priv;
+UINT shutdown_flag = EWX_FORCE;
+
+slog("guest-shutdown called, mode: %s", mode);
+
+if (!has_mode || strcmp(mode, "powerdown") == 0) {
+shutdown_flag |= EWX_POWEROFF;
+} else if (strcmp(mode, "halt") == 0) {
+shutdown_flag |= EWX_SHUTDOWN;
+} else if (strcmp(mode, "reboot") == 0) {
+shutdown_flag |= EWX_REBOOT;
+} else {
+error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
+  "halt|powerdown|reboot");
+return;
+}
+
+/* Request a shutdown privilege, but try to shut down the system
+   anyway. */
+if (OpenProcessToken(GetCurrentProcess(),
+TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token))
+{
+LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
+&priv.Privileges[0].Luid);
+
+priv.PrivilegeCount = 1;
+priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, 0);
+}
+
+if (!ExitWindowsEx(shutdown_flag, SHTDN_REASON_FLAG_PLANNED)) {
+slog("guest-shutdown failed: %d", GetLastError());
+error_set(err, QERR_UNDEFINED_ERROR);
+}
 }
 
 int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, 
Error **err)
-- 
1.7.4.1




[Qemu-devel] [PATCH v2 3/8] qemu-ga: separate out common commands from posix-specific ones

2012-02-02 Thread Michael Roth
Many of the current RPC implementations are very much POSIX-specific
and require complete re-writes for Windows. There are however a small
set of core guest agent commands that are common to both, and other
commands such as guest-file-* which *may* be portable. So we introduce
commands.c for the latter, and will rename guest-agent-commands.c to
commands-posix.c in a future commit. Windows implementations will go in
commands-win32.c, eventually.

Signed-off-by: Michael Roth 
---
 Makefile.objs  |2 +-
 qga/commands.c |   73 
 qga/guest-agent-commands.c |   59 +---
 qga/guest-agent-core.h |1 +
 4 files changed, 76 insertions(+), 59 deletions(-)
 create mode 100644 qga/commands.c

diff --git a/Makefile.objs b/Makefile.objs
index 27ff919..d70cebe 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -424,7 +424,7 @@ common-obj-y += qmp.o hmp.o
 ##
 # guest agent
 
-qga-nested-y = guest-agent-commands.o guest-agent-command-state.o
+qga-nested-y = commands.o guest-agent-commands.o guest-agent-command-state.o
 qga-nested-y += channel-posix.o
 qga-obj-y = $(addprefix qga/, $(qga-nested-y))
 qga-obj-y += qemu-ga.o qemu-sockets.o module.o qemu-option.o
diff --git a/qga/commands.c b/qga/commands.c
new file mode 100644
index 000..b27407d
--- /dev/null
+++ b/qga/commands.c
@@ -0,0 +1,73 @@
+/*
+ * QEMU Guest Agent common/cross-platform command implementations
+ *
+ * Copyright IBM Corp. 2012
+ *
+ * Authors:
+ *  Michael Roth  
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include 
+#include "qga/guest-agent-core.h"
+#include "qga-qmp-commands.h"
+#include "qerror.h"
+
+/* Note: in some situations, like with the fsfreeze, logging may be
+ * temporarilly disabled. if it is necessary that a command be able
+ * to log for accounting purposes, check ga_logging_enabled() beforehand,
+ * and use the QERR_QGA_LOGGING_DISABLED to generate an error
+ */
+void slog(const gchar *fmt, ...)
+{
+va_list ap;
+
+va_start(ap, fmt);
+g_logv("syslog", G_LOG_LEVEL_INFO, fmt, ap);
+va_end(ap);
+}
+
+int64_t qmp_guest_sync(int64_t id, Error **errp)
+{
+return id;
+}
+
+void qmp_guest_ping(Error **err)
+{
+slog("guest-ping called");
+}
+
+struct GuestAgentInfo *qmp_guest_info(Error **err)
+{
+GuestAgentInfo *info = g_malloc0(sizeof(GuestAgentInfo));
+GuestAgentCommandInfo *cmd_info;
+GuestAgentCommandInfoList *cmd_info_list;
+char **cmd_list_head, **cmd_list;
+
+info->version = g_strdup(QGA_VERSION);
+
+cmd_list_head = cmd_list = qmp_get_command_list();
+if (*cmd_list_head == NULL) {
+goto out;
+}
+
+while (*cmd_list) {
+cmd_info = g_malloc0(sizeof(GuestAgentCommandInfo));
+cmd_info->name = strdup(*cmd_list);
+cmd_info->enabled = qmp_command_is_enabled(cmd_info->name);
+
+cmd_info_list = g_malloc0(sizeof(GuestAgentCommandInfoList));
+cmd_info_list->value = cmd_info;
+cmd_info_list->next = info->supported_commands;
+info->supported_commands = cmd_info_list;
+
+g_free(*cmd_list);
+cmd_list++;
+}
+
+out:
+g_free(cmd_list_head);
+return info;
+}
diff --git a/qga/guest-agent-commands.c b/qga/guest-agent-commands.c
index a09c8ca..126127a 100644
--- a/qga/guest-agent-commands.c
+++ b/qga/guest-agent-commands.c
@@ -1,5 +1,5 @@
 /*
- * QEMU Guest Agent commands
+ * QEMU Guest Agent POSIX-specific command implementations
  *
  * Copyright IBM Corp. 2011
  *
@@ -30,63 +30,6 @@
 
 static GAState *ga_state;
 
-/* Note: in some situations, like with the fsfreeze, logging may be
- * temporarilly disabled. if it is necessary that a command be able
- * to log for accounting purposes, check ga_logging_enabled() beforehand,
- * and use the QERR_QGA_LOGGING_DISABLED to generate an error
- */
-static void slog(const char *fmt, ...)
-{
-va_list ap;
-
-va_start(ap, fmt);
-g_logv("syslog", G_LOG_LEVEL_INFO, fmt, ap);
-va_end(ap);
-}
-
-int64_t qmp_guest_sync(int64_t id, Error **errp)
-{
-return id;
-}
-
-void qmp_guest_ping(Error **err)
-{
-slog("guest-ping called");
-}
-
-struct GuestAgentInfo *qmp_guest_info(Error **err)
-{
-GuestAgentInfo *info = g_malloc0(sizeof(GuestAgentInfo));
-GuestAgentCommandInfo *cmd_info;
-GuestAgentCommandInfoList *cmd_info_list;
-char **cmd_list_head, **cmd_list;
-
-info->version = g_strdup(QGA_VERSION);
-
-cmd_list_head = cmd_list = qmp_get_command_list();
-if (*cmd_list_head == NULL) {
-goto out;
-}
-
-while (*cmd_list) {
-cmd_info = g_malloc0(sizeof(GuestAgentCommandInfo));
-cmd_info->name = strdup(*cmd_list);
-cmd

[Qemu-devel] [PATCH v2 6/8] qemu-ga: add initial win32 support

2012-02-02 Thread Michael Roth
This adds a win32 channel implementation that makes qemu-ga functional
on Windows using virtio-serial (unix-listen/isa-serial not currently
implemented). Unlike with the posix implementation, we do not use
GIOChannel for the following reasons:

 - glib calls stat() on an fd to check whether S_IFCHR is set, which is
   the case for virtio-serial on win32. Because of that, a one-time
   check to determine whether the channel is readable is done by making
   a call to PeekConsoleInput(), which reports the underlying handle is
   not a valid console handle, and thus we can never read from the
   channel.

 - if one goes as far as to "trick" glib into thinking it is a normal
   file descripter, the buffering is done in such a way that data
   written to the output stream will subsequently result in that same
   data being read back as if it were input, causing an error loop.
   furthermore, a forced flush of the channel only moves the data into a
   secondary buffer managed by glib, so there's no way to prevent output
   from getting read back as input.

The implementation here ties into the glib main loop by implementing a
custom GSource that continually submits asynchronous/overlapped I/O to
fill an GAChannel-managed read buffer, and tells glib to poll the
corresponding event handle for a completion whenever there is no
data/RPC in the read buffer to notify the main application about.

Signed-off-by: Michael Roth 
---
 Makefile.objs   |2 +-
 qemu-ga.c   |4 +
 qga/channel-win32.c |  337 +++
 3 files changed, 342 insertions(+), 1 deletions(-)
 create mode 100644 qga/channel-win32.c

diff --git a/Makefile.objs b/Makefile.objs
index 18e79ce..e1cb54a 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -426,7 +426,7 @@ common-obj-y += qmp.o hmp.o
 
 qga-nested-y = commands.o guest-agent-command-state.o
 qga-nested-$(CONFIG_POSIX) += commands-posix.o channel-posix.o
-qga-nested-$(CONFIG_WIN32) += commands-win32.o
+qga-nested-$(CONFIG_WIN32) += commands-win32.o channel-win32.o
 qga-obj-y = $(addprefix qga/, $(qga-nested-y))
 qga-obj-y += qemu-ga.o module.o
 qga-obj-$(CONFIG_WIN32) += oslib-win32.o
diff --git a/qemu-ga.c b/qemu-ga.c
index 93ebc3e..8e517b5 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -30,7 +30,11 @@
 #include "qapi/qmp-core.h"
 #include "qga/channel.h"
 
+#ifndef _WIN32
 #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0"
+#else
+#define QGA_VIRTIO_PATH_DEFAULT ".\\Global\\org.qemu.guest_agent.0"
+#endif
 #define QGA_PIDFILE_DEFAULT "/var/run/qemu-ga.pid"
 
 struct GAState {
diff --git a/qga/channel-win32.c b/qga/channel-win32.c
new file mode 100644
index 000..9d8601a
--- /dev/null
+++ b/qga/channel-win32.c
@@ -0,0 +1,337 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "qga/guest-agent-core.h"
+#include "qga/channel.h"
+
+typedef struct GAChannelReadState {
+guint thread_id;
+uint8_t *buf;
+size_t buf_size;
+size_t cur; /* current buffer start */
+size_t pending; /* pending buffered bytes to read */
+OVERLAPPED ov;
+bool ov_pending; /* whether on async read is outstanding */
+} GAChannelReadState;
+
+struct GAChannel {
+HANDLE handle;
+GAChannelCallback cb;
+gpointer user_data;
+GAChannelReadState rstate;
+GIOCondition pending_events; /* TODO: use GAWatch.pollfd.revents */
+GSource *source;
+};
+
+typedef struct GAWatch {
+GSource source;
+GPollFD pollfd;
+GAChannel *channel;
+GIOCondition events_mask;
+} GAWatch;
+
+/*
+ * Called by glib prior to polling to set up poll events if polling is needed.
+ *
+ */
+static gboolean ga_channel_prepare(GSource *source, gint *timeout_ms)
+{
+GAWatch *watch = (GAWatch *)source;
+GAChannel *c = (GAChannel *)watch->channel;
+GAChannelReadState *rs = &c->rstate;
+DWORD count_read, count_to_read = 0;
+bool success;
+GIOCondition new_events = 0;
+
+g_debug("prepare");
+/* go ahead and submit another read if there's room in the buffer
+ * and no previous reads are outstanding
+ */
+if (!rs->ov_pending) {
+if (rs->cur + rs->pending >= rs->buf_size) {
+if (rs->cur) {
+memmove(rs->buf, rs->buf + rs->cur, rs->pending);
+rs->cur = 0;
+}
+}
+count_to_read = rs->buf_size - rs->cur - rs->pending;
+}
+
+if (rs->ov_pending || count_to_read <= 0) {
+goto out;
+}
+
+/* submit the read */
+success = ReadFile(c->handle, rs->buf + rs->cur + rs->pending,
+   count_to_read, &count_read, &rs->ov);
+if (success) {
+rs->pending += count_read;
+rs->ov_pending = false;
+} else {
+if (GetLastError() ==

[Qemu-devel] [PATCH v2 4/8] qemu-ga: rename guest-agent-commands.c -> commands-posix.c

2012-02-02 Thread Michael Roth

Signed-off-by: Michael Roth 
---
 Makefile.objs  |2 +-
 qga/commands-posix.c   |  528 
 qga/guest-agent-commands.c |  528 
 3 files changed, 529 insertions(+), 529 deletions(-)
 create mode 100644 qga/commands-posix.c
 delete mode 100644 qga/guest-agent-commands.c

diff --git a/Makefile.objs b/Makefile.objs
index d70cebe..2e2efb4 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -424,7 +424,7 @@ common-obj-y += qmp.o hmp.o
 ##
 # guest agent
 
-qga-nested-y = commands.o guest-agent-commands.o guest-agent-command-state.o
+qga-nested-y = commands.o commands-posix.o guest-agent-command-state.o
 qga-nested-y += channel-posix.o
 qga-obj-y = $(addprefix qga/, $(qga-nested-y))
 qga-obj-y += qemu-ga.o qemu-sockets.o module.o qemu-option.o
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
new file mode 100644
index 000..126127a
--- /dev/null
+++ b/qga/commands-posix.c
@@ -0,0 +1,528 @@
+/*
+ * QEMU Guest Agent POSIX-specific command implementations
+ *
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Michael Roth  
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include 
+
+#if defined(__linux__)
+#include 
+#include 
+
+#if defined(__linux__) && defined(FIFREEZE)
+#define CONFIG_FSFREEZE
+#endif
+#endif
+
+#include 
+#include 
+#include "qga/guest-agent-core.h"
+#include "qga-qmp-commands.h"
+#include "qerror.h"
+#include "qemu-queue.h"
+
+static GAState *ga_state;
+
+void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
+{
+int ret;
+const char *shutdown_flag;
+
+slog("guest-shutdown called, mode: %s", mode);
+if (!has_mode || strcmp(mode, "powerdown") == 0) {
+shutdown_flag = "-P";
+} else if (strcmp(mode, "halt") == 0) {
+shutdown_flag = "-H";
+} else if (strcmp(mode, "reboot") == 0) {
+shutdown_flag = "-r";
+} else {
+error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
+  "halt|powerdown|reboot");
+return;
+}
+
+ret = fork();
+if (ret == 0) {
+/* child, start the shutdown */
+setsid();
+fclose(stdin);
+fclose(stdout);
+fclose(stderr);
+
+ret = execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
+"hypervisor initiated shutdown", (char*)NULL);
+if (ret) {
+slog("guest-shutdown failed: %s", strerror(errno));
+}
+exit(!!ret);
+} else if (ret < 0) {
+error_set(err, QERR_UNDEFINED_ERROR);
+}
+}
+
+typedef struct GuestFileHandle {
+uint64_t id;
+FILE *fh;
+QTAILQ_ENTRY(GuestFileHandle) next;
+} GuestFileHandle;
+
+static struct {
+QTAILQ_HEAD(, GuestFileHandle) filehandles;
+} guest_file_state;
+
+static void guest_file_handle_add(FILE *fh)
+{
+GuestFileHandle *gfh;
+
+gfh = g_malloc0(sizeof(GuestFileHandle));
+gfh->id = fileno(fh);
+gfh->fh = fh;
+QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
+}
+
+static GuestFileHandle *guest_file_handle_find(int64_t id)
+{
+GuestFileHandle *gfh;
+
+QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
+{
+if (gfh->id == id) {
+return gfh;
+}
+}
+
+return NULL;
+}
+
+int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, 
Error **err)
+{
+FILE *fh;
+int fd;
+int64_t ret = -1;
+
+if (!has_mode) {
+mode = "r";
+}
+slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
+fh = fopen(path, mode);
+if (!fh) {
+error_set(err, QERR_OPEN_FILE_FAILED, path);
+return -1;
+}
+
+/* set fd non-blocking to avoid common use cases (like reading from a
+ * named pipe) from hanging the agent
+ */
+fd = fileno(fh);
+ret = fcntl(fd, F_GETFL);
+ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
+if (ret == -1) {
+error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
+fclose(fh);
+return -1;
+}
+
+guest_file_handle_add(fh);
+slog("guest-file-open, handle: %d", fd);
+return fd;
+}
+
+void qmp_guest_file_close(int64_t handle, Error **err)
+{
+GuestFileHandle *gfh = guest_file_handle_find(handle);
+int ret;
+
+slog("guest-file-close called, handle: %ld", handle);
+if (!gfh) {
+error_set(err, QERR_FD_NOT_FOUND, "handle");
+return;
+}
+
+ret = fclose(gfh->fh);
+if (ret == -1) {
+error_set(err, QERR_QGA_COMMAND

[Qemu-devel] [PATCH v2 7/8] qemu-ga: add Windows service integration

2012-02-02 Thread Michael Roth
This allows qemu-ga to function as a Windows service:

 - to install the service (will auto-start on boot):
 qemu-ga --service install
 - to start the service:
 net start qemu-ga
 - to stop the service:
 net stop qemu-ga
 - to uninstall service:
 qemu-ga --service uninstall

Original patch by Gal Hammer 

Signed-off-by: Michael Roth 
---
 Makefile.objs   |2 +-
 qemu-ga.c   |  103 --
 qga/service-win32.c |  114 +++
 qga/service-win32.h |   30 +
 4 files changed, 244 insertions(+), 5 deletions(-)
 create mode 100644 qga/service-win32.c
 create mode 100644 qga/service-win32.h

diff --git a/Makefile.objs b/Makefile.objs
index e1cb54a..3b08e70 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -426,7 +426,7 @@ common-obj-y += qmp.o hmp.o
 
 qga-nested-y = commands.o guest-agent-command-state.o
 qga-nested-$(CONFIG_POSIX) += commands-posix.o channel-posix.o
-qga-nested-$(CONFIG_WIN32) += commands-win32.o channel-win32.o
+qga-nested-$(CONFIG_WIN32) += commands-win32.o channel-win32.o service-win32.o
 qga-obj-y = $(addprefix qga/, $(qga-nested-y))
 qga-obj-y += qemu-ga.o module.o
 qga-obj-$(CONFIG_WIN32) += oslib-win32.o
diff --git a/qemu-ga.c b/qemu-ga.c
index 8e517b5..92f81ed 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -29,6 +29,10 @@
 #include "error_int.h"
 #include "qapi/qmp-core.h"
 #include "qga/channel.h"
+#ifdef _WIN32
+#include "qga/service-win32.h"
+#include 
+#endif
 
 #ifndef _WIN32
 #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0"
@@ -46,11 +50,19 @@ struct GAState {
 GLogLevelFlags log_level;
 FILE *log_file;
 bool logging_enabled;
+#ifdef _WIN32
+GAService service;
+#endif
 };
 
 static struct GAState *ga_state;
 
-#ifndef _WIN32
+#ifdef _WIN32
+DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type, LPVOID data,
+  LPVOID ctx);
+VOID WINAPI service_main(DWORD argc, TCHAR *argv[]);
+#endif
+
 static void quit_handler(int sig)
 {
 g_debug("received signal num %d, quitting", sig);
@@ -60,6 +72,7 @@ static void quit_handler(int sig)
 }
 }
 
+#ifndef _WIN32
 static gboolean register_signal_handlers(void)
 {
 struct sigaction sigact;
@@ -95,8 +108,9 @@ static void usage(const char *cmd)
 "  -f, --pidfile specify pidfile (default is %s)\n"
 "  -v, --verbose log extra debugging information\n"
 "  -V, --version print version information and exit\n"
-#ifndef _WIN32
 "  -d, --daemonize   become a daemon\n"
+#ifdef _WIN32
+"  -s, --service service commands: install, uninstall\n"
 #endif
 "  -b, --blacklist   comma-separated list of RPCs to disable (no spaces, \"?\""
 "to list available RPCs)\n"
@@ -394,10 +408,64 @@ static gboolean channel_init(GAState *s, const gchar 
*method, const gchar *path)
 return true;
 }
 
+#ifdef _WIN32
+DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type, LPVOID data,
+  LPVOID ctx)
+{
+DWORD ret = NO_ERROR;
+GAService *service = &ga_state->service;
+
+switch (ctrl)
+{
+case SERVICE_CONTROL_STOP:
+case SERVICE_CONTROL_SHUTDOWN:
+quit_handler(SIGTERM);
+service->status.dwCurrentState = SERVICE_STOP_PENDING;
+SetServiceStatus(service->status_handle, &service->status);
+break;
+
+default:
+ret = ERROR_CALL_NOT_IMPLEMENTED;
+}
+return ret;
+}
+
+VOID WINAPI service_main(DWORD argc, TCHAR *argv[])
+{
+GAService *service = &ga_state->service;
+
+service->status_handle = RegisterServiceCtrlHandlerEx(QGA_SERVICE_NAME,
+service_ctrl_handler, NULL);
+
+if (service->status_handle == 0) {
+g_critical("Failed to register extended requests function!\n");
+return;
+}
+
+service->status.dwServiceType = SERVICE_WIN32;
+service->status.dwCurrentState = SERVICE_RUNNING;
+service->status.dwControlsAccepted = SERVICE_ACCEPT_STOP | 
SERVICE_ACCEPT_SHUTDOWN;
+service->status.dwWin32ExitCode = NO_ERROR;
+service->status.dwServiceSpecificExitCode = NO_ERROR;
+service->status.dwCheckPoint = 0;
+service->status.dwWaitHint = 0;
+SetServiceStatus(service->status_handle, &service->status);
+
+g_main_loop_run(ga_state->main_loop);
+
+service->status.dwCurrentState = SERVICE_STOPPED;
+SetServiceStatus(service->status_handle, &service->status);
+}
+#endif
+
 int main(int argc, char **argv)
 {
-const char *sopt = "hVvdm:p:l:f:b:";
+const char *sopt = "hVvdm:p:l:f:b:s:";
 const char *method = NULL, *path = NULL, *pidfile = QGA_PIDFILE_DEFAULT;
+const char *log_file_name =

[Qemu-devel] [PATCH v2 5/8] qemu-ga: fixes for win32 build of qemu-ga

2012-02-02 Thread Michael Roth
Various stubs and #ifdefs to compile for Windows using mingw
cross-build. Still has 1 linker error due to a dependency on the
forthcoming win32 versions of the GAChannel/transport class.

Signed-off-by: Michael Roth 
---
 Makefile |2 +-
 Makefile.objs|9 +++--
 configure|2 +-
 qemu-ga.c|   16 +
 qga/commands-win32.c |   91 ++
 5 files changed, 114 insertions(+), 6 deletions(-)
 create mode 100644 qga/commands-win32.c

diff --git a/Makefile b/Makefile
index 2560b59..9baa532 100644
--- a/Makefile
+++ b/Makefile
@@ -199,7 +199,7 @@ QGALIB_GEN=$(addprefix $(qapi-dir)/, qga-qapi-types.h 
qga-qapi-visit.h qga-qmp-c
 $(QGALIB_OBJ): $(QGALIB_GEN) $(GENERATED_HEADERS)
 $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) $(GENERATED_HEADERS)
 
-qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(qapi-obj-y) $(tools-obj-y) 
$(qobject-obj-y) $(version-obj-y) $(QGALIB_OBJ)
+qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(tools-obj-y) $(qapi-obj-y) 
$(qobject-obj-y) $(version-obj-y) $(QGALIB_OBJ)
 
 QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
 
diff --git a/Makefile.objs b/Makefile.objs
index 2e2efb4..18e79ce 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -424,12 +424,13 @@ common-obj-y += qmp.o hmp.o
 ##
 # guest agent
 
-qga-nested-y = commands.o commands-posix.o guest-agent-command-state.o
-qga-nested-y += channel-posix.o
+qga-nested-y = commands.o guest-agent-command-state.o
+qga-nested-$(CONFIG_POSIX) += commands-posix.o channel-posix.o
+qga-nested-$(CONFIG_WIN32) += commands-win32.o
 qga-obj-y = $(addprefix qga/, $(qga-nested-y))
-qga-obj-y += qemu-ga.o qemu-sockets.o module.o qemu-option.o
+qga-obj-y += qemu-ga.o module.o
 qga-obj-$(CONFIG_WIN32) += oslib-win32.o
-qga-obj-$(CONFIG_POSIX) += oslib-posix.o
+qga-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-sockets.o qemu-option.o
 
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
diff --git a/configure b/configure
index 3b0b300..aaf8171 100755
--- a/configure
+++ b/configure
@@ -508,7 +508,7 @@ if test "$mingw32" = "yes" ; then
   bindir="\${prefix}"
   sysconfdir="\${prefix}"
   confsuffix=""
-  guest_agent="no"
+  libs_qga="-lws2_32 -lwinmm $lib_qga"
 fi
 
 werror=""
diff --git a/qemu-ga.c b/qemu-ga.c
index 2e8af02..93ebc3e 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -15,7 +15,9 @@
 #include 
 #include 
 #include 
+#ifndef _WIN32
 #include 
+#endif
 #include "json-streamer.h"
 #include "json-parser.h"
 #include "qint.h"
@@ -44,6 +46,7 @@ struct GAState {
 
 static struct GAState *ga_state;
 
+#ifndef _WIN32
 static void quit_handler(int sig)
 {
 g_debug("received signal num %d, quitting", sig);
@@ -73,6 +76,7 @@ static gboolean register_signal_handlers(void)
 }
 return true;
 }
+#endif
 
 static void usage(const char *cmd)
 {
@@ -87,7 +91,9 @@ static void usage(const char *cmd)
 "  -f, --pidfile specify pidfile (default is %s)\n"
 "  -v, --verbose log extra debugging information\n"
 "  -V, --version print version information and exit\n"
+#ifndef _WIN32
 "  -d, --daemonize   become a daemon\n"
+#endif
 "  -b, --blacklist   comma-separated list of RPCs to disable (no spaces, \"?\""
 "to list available RPCs)\n"
 "  -h, --helpdisplay this help and exit\n"
@@ -143,9 +149,13 @@ static void ga_log(const gchar *domain, GLogLevelFlags 
level,
 }
 
 level &= G_LOG_LEVEL_MASK;
+#ifndef _WIN32
 if (domain && strcmp(domain, "syslog") == 0) {
 syslog(LOG_INFO, "%s: %s", level_str, msg);
 } else if (level & s->log_level) {
+#else
+if (level & s->log_level) {
+#endif
 g_get_current_time(&time);
 fprintf(s->log_file,
 "%lu.%lu: %s: %s\n", time.tv_sec, time.tv_usec, level_str, 
msg);
@@ -153,6 +163,7 @@ static void ga_log(const gchar *domain, GLogLevelFlags 
level,
 }
 }
 
+#ifndef _WIN32
 static void become_daemon(const char *pidfile)
 {
 pid_t pid, sid;
@@ -203,6 +214,7 @@ fail:
 g_critical("failed to daemonize");
 exit(EXIT_FAILURE);
 }
+#endif
 
 static int send_response(GAState *s, QObject *payload)
 {
@@ -466,10 +478,12 @@ int main(int argc, char **argv)
 }
 }
 
+#ifndef _WIN32
 if (daemonize) {
 g_debug("starting daemon");
 become_daemon(pidfile);
 }
+#endif
 
 s = g_malloc0(sizeof(GAState));
 s->log_file = log_file;
@@ -482,10 +496,12 @@ int main(int argc, char **argv)
 ga_command_state_init_all(s->command_state);
 json_message_parser_init(&s->parser, process_event);
 ga_state = s;
+#ifndef _WIN32
 if (!register_signal_handlers()) {
 g_critic

Re: [Qemu-devel] [PATCH v2 0/8] qemu-ga: add support for Windows

2012-02-03 Thread Michael Roth

On 02/03/2012 08:18 AM, Luiz Capitulino wrote:

On Thu,  2 Feb 2012 13:58:52 -0600
Michael Roth  wrote:


These patches apply on top of qemu.git master, and can also be obtained from:
git://github.com/mdroth/qemu.git qga-win32-v2

Luiz/Gal, I decided not to roll the suspend/hibernate stuff into this series
since the s3 situation isn't fully sorted out yet. The file structure is a
little different now, posix/linux-specific stuff goes in qga/commands-posix.c,
win32-specific stuff in qga/commands-win32.c, but other than that it should be
a straightforward rebase if this gets merged first.


I think I'll have to rebase my series on top of this one, when do you plan to
merge this?



Hopefully soon, was planning on waiting for the suspend/hibernate bits 
but we seem to be blocked on the s3 issues and I have other patches 
accumulating on top of win32 (hesitant to base those on master since 
this patchset does a lot of refactoring that might affect them), so I 
figured I'd push this for merge since it doesn't have any dependencies 
outside master.





Re: [Qemu-devel] [PATCH v2 2/8] qemu-ga: move channel/transport functionalit

2012-02-03 Thread Michael Roth

On 02/02/2012 10:25 PM, MATSUDA, Daiki wrote:

Hi, Michael!
Thank you for your working.

And I have a question the process id written in pid file.
If qemu-ga is ran as daemon, the parent process id not child is written
in pid file. So, id gotten by 'ps' command is different. Is it correct
work? Many other daemon writes child process id.

Regards
MATSUDA Daiki



Hi Matsuda,

Thank you for testing!

In the become_daemon() function, the parent exits immediately after the 
fork(), so only the child has the opportunity to write to the pid file. 
It calls getpid() to get the pid to write, which should be it's own 
lwpid. So I'm not seeing where there's an opportunity for the parent pid 
to be written.


Can you confirm? It seems to behave as expected for me:

[root@vm ~]# /home/mdroth/w/qemu-build/qemu-ga -d
** (process:7441): DEBUG: starting daemon
[root@vm ~]# ps aux | grep qemu-ga
root  7442  0.0  0.0  13792   348 ?Ss   10:56   0:00 
/home/mdroth/w/qemu-build/qemu-ga -d
root  7471  0.0  0.1 109108   816 pts/2R+   11:00   0:00 grep 
--color=auto qemu-ga

[root@vm ~]# cat /var/run/qemu-ga.pid
7442




Re: [Qemu-devel] [PATCH v2 0/8] qemu-ga: add support for Windows

2012-02-03 Thread Michael Roth

On 02/03/2012 10:45 AM, Luiz Capitulino wrote:

On Fri, 03 Feb 2012 10:37:25 -0600
Michael Roth  wrote:


On 02/03/2012 08:18 AM, Luiz Capitulino wrote:

On Thu,  2 Feb 2012 13:58:52 -0600
Michael Roth   wrote:


These patches apply on top of qemu.git master, and can also be obtained from:
git://github.com/mdroth/qemu.git qga-win32-v2

Luiz/Gal, I decided not to roll the suspend/hibernate stuff into this series
since the s3 situation isn't fully sorted out yet. The file structure is a
little different now, posix/linux-specific stuff goes in qga/commands-posix.c,
win32-specific stuff in qga/commands-win32.c, but other than that it should be
a straightforward rebase if this gets merged first.


I think I'll have to rebase my series on top of this one, when do you plan to
merge this?



Hopefully soon, was planning on waiting for the suspend/hibernate bits
but we seem to be blocked on the s3 issues and I have other patches
accumulating on top of win32 (hesitant to base those on master since
this patchset does a lot of refactoring that might affect them), so I
figured I'd push this for merge since it doesn't have any dependencies
outside master.


The S3 issues seem sorted to me, but I don't oppose having this series in first.



Thanks, in retrospect I probably should've just gotten these out of the 
way weeks ago since they'd immediately clobber git blame.


I'd been tracking Gerd's QMP wakeup series as the s3 resolution we need 
for guest-suspend, is that still the case? I guess those are coming 
through your QMP queue?





[Qemu-devel] [PATCH 0/1] qemu-ga: add guest-sync-delimited

2012-02-06 Thread Michael Roth
Sorry for the somewhat redundant cover letter, but needed to note that:

This applies on top of "[PATCH v2 0/8] qemu-ga: add support for Windows", and
can also be obtained from:
git://github.com/mdroth/qemu.git qga-guest-sync-delimited

As noted in the commit there's a wiki write-up with more details on what
exactly this is for:

http://wiki.qemu.org/Features/QAPI/GuestAgent#QEMU_Guest_Agent_Protocol

It's not absolutely required, but it does make dealing with some communication
corner cases a heck of a lot easier.




[Qemu-devel] [PATCH] qemu-ga: add guest-sync-delimited

2012-02-06 Thread Michael Roth
guest-sync leaves it as an exercise to the user as to how to reliably
obtain the response to guest-sync if the client had previously read in a
partial response (due qemu-ga previously being restarted mid-"sentence"
due to reboot, forced restart, etc).

qemu-ga handles this situation on its end by having a client precede
their guest-sync request with a 0xFF byte (invalid UTF-8), which
qemu-ga/QEMU JSON parsers will treat as a flush event. Thus we can
reliably flush the qemu-ga parser state in preparation for receiving
the guest-sync request.

guest-sync-delimited provides the same functionality for a client: when
a guest-sync-delimited is issued, qemu-ga will precede it's response
with a 0xFF byte that the client can use as an indicator to flush its
buffer/parser state in preparation for reliably receiving the
guest-sync-delimited response.

More information available on the wiki:

http://wiki.qemu.org/Features/QAPI/GuestAgent#QEMU_Guest_Agent_Protocol

Signed-off-by: Michael Roth 
---
 qapi-schema-guest.json |   42 +-
 qemu-ga.c  |   29 +++--
 qga/commands-posix.c   |3 ---
 qga/commands.c |6 ++
 qga/guest-agent-core.h |2 ++
 5 files changed, 72 insertions(+), 10 deletions(-)

diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json
index 706925d..1a44357 100644
--- a/qapi-schema-guest.json
+++ b/qapi-schema-guest.json
@@ -1,6 +1,40 @@
 # *-*- Mode: Python -*-*
 
 ##
+#
+# Echo back a unique integer value, and prepend to response a
+# leading sentinel byte (0xFF) the client can check scan for.
+#
+# This is used by clients talking to the guest agent over the
+# wire to ensure the stream is in sync and doesn't contain stale
+# data from previous client. It must be issued upon initial
+# connection, and after any client-side timeouts (including
+# timeouts on receiving a response to this command).
+#
+# After issuing this request, all guest agent responses should be
+# ignored until the response containing the unique integer value
+# the client passed in is returned. Receival of the 0xFF sentinel
+# byte must be handled as an indication that the client's
+# lexer/tokenizer/parser state should be flushed/reset in
+# preparation for reliably receiving the subsequent response.
+#
+# Similarly, clients should also precede this *request*
+# with a 0xFF byte to make sure the guest agent flushes any
+# partially read JSON data from a previous client connection.
+#
+# This command deprecates the guest-sync command.
+#
+# @id: randomly generated 64-bit integer
+#
+# Returns: The unique integer id passed in by the client
+#
+# Since: 1.1
+# ##
+{ 'command': 'guest-sync-delimited'
+  'data':{ 'id': 'int' },
+  'returns': 'int' }
+
+##
 # @guest-sync:
 #
 # Echo back a unique integer value
@@ -13,8 +47,12 @@
 # partially-delivered JSON text in such a way that this response
 # can be obtained.
 #
+# In cases where a partial stale response was previously
+# received by the client, this cannot always be done reliably.
+# Use guest-sync-delimited instead.
+#
 # Such clients should also precede this command
-# with a 0xFF byte to make such the guest agent flushes any
+# with a 0xFF byte to make sure the guest agent flushes any
 # partially read JSON data from a previous session.
 #
 # @id: randomly generated 64-bit integer
@@ -22,6 +60,8 @@
 # Returns: The unique integer id passed in by the client
 #
 # Since: 0.15.0
+# Deprecated since: 1.1
+# Deprecated by: guest-sync-delimited
 ##
 { 'command': 'guest-sync'
   'data':{ 'id': 'int' },
diff --git a/qemu-ga.c b/qemu-ga.c
index 92f81ed..d567241 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -40,6 +40,7 @@
 #define QGA_VIRTIO_PATH_DEFAULT ".\\Global\\org.qemu.guest_agent.0"
 #endif
 #define QGA_PIDFILE_DEFAULT "/var/run/qemu-ga.pid"
+#define QGA_SENTINEL_BYTE 0xFF
 
 struct GAState {
 JSONMessageParser parser;
@@ -53,9 +54,10 @@ struct GAState {
 #ifdef _WIN32
 GAService service;
 #endif
+bool delimit_response;
 };
 
-static struct GAState *ga_state;
+struct GAState *ga_state;
 
 #ifdef _WIN32
 DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type, LPVOID data,
@@ -140,6 +142,11 @@ static const char *ga_log_level_str(GLogLevelFlags level)
 }
 }
 
+void ga_set_response_delimited(GAState *s)
+{
+s->delimit_response = true;
+}
+
 bool ga_logging_enabled(GAState *s)
 {
 return s->logging_enabled;
@@ -236,8 +243,8 @@ fail:
 
 static int send_response(GAState *s, QObject *payload)
 {
-const char *buf;
-QString *payload_qstr;
+const char *buf, *buf2;
+QString *payload_qstr, *response_qstr;
 GIOStatus status;
 
 g_assert(payload && s->channel);
@@ -247,10 +254,20 @@ static int send_response(GAState *s, QObject *payload)
   

Re: [Qemu-devel] [PATCH 0/1] qemu-ga: add guest-sync-delimited

2012-02-06 Thread Michael Roth
On Mon, Feb 06, 2012 at 06:07:34PM -0600, Michael Roth wrote:
> Sorry for the somewhat redundant cover letter, but needed to note that:
> 
> This applies on top of "[PATCH v2 0/8] qemu-ga: add support for Windows", and
> can also be obtained from:
> git://github.com/mdroth/qemu.git qga-guest-sync-delimited
> 
> As noted in the commit there's a wiki write-up with more details on what
> exactly this is for:
> 
> http://wiki.qemu.org/Features/QAPI/GuestAgent#QEMU_Guest_Agent_Protocol
> 
> It's not absolutely required, but it does make dealing with some communication
> corner cases a heck of a lot easier.
> 

Actually, let me re-spin this without the deprecated flag for
guest-sync, since I suspect a more common client implementation would do
something like:

qga.write(obj_to_json_string(req_obj))
resp_obj = obj_from_json_string(qga.readline())

as opposed to the JSON streamer that qemu-ga/QMP uses. You might miss a
response doing the above approach if there was garbage in the channel,
but you'll always been able to recover on the second attempt. So
guest-sync is still useful there, assuming we codify 1-line-per-response
in the QGA protocol.



[Qemu-devel] [PATCH v2 0/1] qemu-ga: add guest-sync-delimited

2012-02-06 Thread Michael Roth
Sorry for the somewhat redundant cover letter, but needed to note that:

This applies on top of "[PATCH v2 0/8] qemu-ga: add support for Windows", and
can also be obtained from:
git://github.com/mdroth/qemu.git qga-guest-sync-delimited

CHANGES SINCE v1:

 - removed deprecation flag for guest-sync, still useful for some
   implementations

As noted in the commit there's a wiki write-up with more details on what
exactly this is for:

http://wiki.qemu.org/Features/QAPI/GuestAgent#QEMU_Guest_Agent_Protocol

It's not absolutely required, but it does make dealing with some communication
corner cases a heck of a lot easier for stream-based (as opposed to
readline-based) client implementations.




[Qemu-devel] [PATCH v2] qemu-ga: add guest-sync-delimited

2012-02-06 Thread Michael Roth
guest-sync leaves it as an exercise to the user as to how to reliably
obtain the response to guest-sync if the client had previously read in a
partial response (due qemu-ga previously being restarted mid-"sentence"
due to reboot, forced restart, etc).

qemu-ga handles this situation on its end by having a client precede
their guest-sync request with a 0xFF byte (invalid UTF-8), which
qemu-ga/QEMU JSON parsers will treat as a flush event. Thus we can
reliably flush the qemu-ga parser state in preparation for receiving
the guest-sync request.

guest-sync-delimited provides the same functionality for a client: when
a guest-sync-delimited is issued, qemu-ga will precede it's response
with a 0xFF byte that the client can use as an indicator to flush its
buffer/parser state in preparation for reliably receiving the
guest-sync-delimited response.

It is also useful as an optimization for clients, since, after issuing a
guest-sync-delimited, clients can safely discard all stale data read
from the channel until the 0xFF is found.

More information available on the wiki:

http://wiki.qemu.org/Features/QAPI/GuestAgent#QEMU_Guest_Agent_Protocol

Signed-off-by: Michael Roth 
---
 qapi-schema-guest.json |   48 +++-
 qemu-ga.c  |   29 +++--
 qga/commands-posix.c   |3 ---
 qga/commands.c |6 ++
 qga/guest-agent-core.h |2 ++
 5 files changed, 78 insertions(+), 10 deletions(-)

diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json
index 706925d..e2cb9ef 100644
--- a/qapi-schema-guest.json
+++ b/qapi-schema-guest.json
@@ -1,6 +1,41 @@
 # *-*- Mode: Python -*-*
 
 ##
+#
+# Echo back a unique integer value, and prepend to response a
+# leading sentinel byte (0xFF) the client can check scan for.
+#
+# This is used by clients talking to the guest agent over the
+# wire to ensure the stream is in sync and doesn't contain stale
+# data from previous client. It must be issued upon initial
+# connection, and after any client-side timeouts (including
+# timeouts on receiving a response to this command).
+#
+# After issuing this request, all guest agent responses should be
+# ignored until the response containing the unique integer value
+# the client passed in is returned. Receival of the 0xFF sentinel
+# byte must be handled as an indication that the client's
+# lexer/tokenizer/parser state should be flushed/reset in
+# preparation for reliably receiving the subsequent response. As
+# an optimization, clients may opt to ignore all data until a
+# sentinel value is receiving to avoid unecessary processing of
+# stale data.
+#
+# Similarly, clients should also precede this *request*
+# with a 0xFF byte to make sure the guest agent flushes any
+# partially read JSON data from a previous client connection.
+#
+# @id: randomly generated 64-bit integer
+#
+# Returns: The unique integer id passed in by the client
+#
+# Since: 1.1
+# ##
+{ 'command': 'guest-sync-delimited'
+  'data':{ 'id': 'int' },
+  'returns': 'int' }
+
+##
 # @guest-sync:
 #
 # Echo back a unique integer value
@@ -13,8 +48,19 @@
 # partially-delivered JSON text in such a way that this response
 # can be obtained.
 #
+# In cases where a partial stale response was previously
+# received by the client, this cannot always be done reliably.
+# One particular scenario being if qemu-ga responses are fed
+# character-by-character into a JSON parser. In these situations,
+# using guest-sync-delimited may be optimal.
+#
+# For clients that fetch responses line by line and convert them
+# to JSON objects, guest-sync should be sufficient, but note that
+# in cases where the channel is dirty some attempts at parsing the
+# response may result in a parser error.
+#
 # Such clients should also precede this command
-# with a 0xFF byte to make such the guest agent flushes any
+# with a 0xFF byte to make sure the guest agent flushes any
 # partially read JSON data from a previous session.
 #
 # @id: randomly generated 64-bit integer
diff --git a/qemu-ga.c b/qemu-ga.c
index 92f81ed..d567241 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -40,6 +40,7 @@
 #define QGA_VIRTIO_PATH_DEFAULT ".\\Global\\org.qemu.guest_agent.0"
 #endif
 #define QGA_PIDFILE_DEFAULT "/var/run/qemu-ga.pid"
+#define QGA_SENTINEL_BYTE 0xFF
 
 struct GAState {
 JSONMessageParser parser;
@@ -53,9 +54,10 @@ struct GAState {
 #ifdef _WIN32
 GAService service;
 #endif
+bool delimit_response;
 };
 
-static struct GAState *ga_state;
+struct GAState *ga_state;
 
 #ifdef _WIN32
 DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type, LPVOID data,
@@ -140,6 +142,11 @@ static const char *ga_log_level_str(GLogLevelFlags level)
 }
 }
 
+void ga_set_response_delimited(GAState *s)
+{
+s->delimit_response = true;
+}
+
 bool ga_logging_enabled(GAState *s)
 {
 return s->log

Re: [Qemu-devel] [PATCH v2] qemu-ga: add guest-sync-delimited

2012-02-07 Thread Michael Roth
On Tue, Feb 07, 2012 at 04:17:26PM +0100, Michal Privoznik wrote:
> On 07.02.2012 02:09, Michael Roth wrote:
> > guest-sync leaves it as an exercise to the user as to how to reliably
> > obtain the response to guest-sync if the client had previously read in a
> > partial response (due qemu-ga previously being restarted mid-"sentence"
> > due to reboot, forced restart, etc).
> > 
> > qemu-ga handles this situation on its end by having a client precede
> > their guest-sync request with a 0xFF byte (invalid UTF-8), which
> > qemu-ga/QEMU JSON parsers will treat as a flush event. Thus we can
> > reliably flush the qemu-ga parser state in preparation for receiving
> > the guest-sync request.
> > 
> > guest-sync-delimited provides the same functionality for a client: when
> > a guest-sync-delimited is issued, qemu-ga will precede it's response
> > with a 0xFF byte that the client can use as an indicator to flush its
> > buffer/parser state in preparation for reliably receiving the
> > guest-sync-delimited response.
> > 
> > It is also useful as an optimization for clients, since, after issuing a
> > guest-sync-delimited, clients can safely discard all stale data read
> > from the channel until the 0xFF is found.
> > 
> > More information available on the wiki:
> > 
> > http://wiki.qemu.org/Features/QAPI/GuestAgent#QEMU_Guest_Agent_Protocol
> > 
> > Signed-off-by: Michael Roth 
> 
> This makes sense. And it's workable for libvirt.
> IIUC, client can send 0xFF to the guest agent and vice versa, right?

Yup, and it should be considered a requirement to send the 0xFF before
guest-sync* to avoid some of the potential corner cases mentioned, since
on the qemu-ga side the 0xFF reliance is baked in.

Clients have a choice as to how they want to deal with this scenario so we
offer both guest-sync (no 0xFF) and guest-sync-delimited (precede response
with 0xFF).

> 
> Michal
> 



  1   2   3   4   5   6   7   8   9   10   >