diff mbox series

[v4,5/9] qapi: introduce new cmd option "allowed-in-preconfig"

Message ID 1520860275-101576-6-git-send-email-imammedo@redhat.com
State New
Headers show
Series enable numa configuration before machine_init() from QMP | expand

Commit Message

Igor Mammedov March 12, 2018, 1:11 p.m. UTC
New option will be used to allow commands, which are prepared/need
to run run in preconfig state. Other commands that should be able
to run in preconfig state, should be ammeded to not expect machine
in initialized state or deal with it.

For compatibility reasons, commands, that don't use new flag
'allowed-in-preconfig' explicitly, are not permited to run in
preconfig state but allowed in all other states like they used
to be.

Within this patch allow following commands in preconfig state:
   qmp_capabilities
   query-qmp-schema
   query-commands
   query-status
   cont
to allow qmp connection, basic introspection and moving to the next
state.

PS:
set-numa-node and query-hotpluggable-cpus will be enabled later in
a separate patch.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
v4:
  * replaces complex "universal" approach
     "[PATCH v3 5/9] QAPI: allow to specify valid runstates  per command"
    with a simpler new command flag "allowed-in-preconfig".
    (Eric Blake <eblake@redhat.com>)
---
 include/qapi/qmp/dispatch.h    |  3 ++-
 docs/devel/qapi-code-gen.txt   | 10 +++++++++-
 monitor.c                      |  5 +++--
 qapi/introspect.json           |  6 +++++-
 qapi/misc.json                 |  7 ++++---
 qapi/qmp-dispatch.c            |  8 ++++++++
 qapi/run-state.json            |  3 ++-
 scripts/qapi/commands.py       | 19 ++++++++++++++-----
 scripts/qapi/common.py         | 15 ++++++++++-----
 scripts/qapi/doc.py            |  2 +-
 scripts/qapi/introspect.py     | 10 ++++++++--
 tests/qapi-schema/test-qapi.py |  2 +-
 12 files changed, 67 insertions(+), 23 deletions(-)

Comments

Eric Blake March 23, 2018, 9:11 p.m. UTC | #1
On 03/12/2018 08:11 AM, Igor Mammedov wrote:
> New option will be used to allow commands, which are prepared/need
> to run run in preconfig state. Other commands that should be able

s/run run in/run, during/

> to run in preconfig state, should be ammeded to not expect machine

s/ammeded/amended/

> in initialized state or deal with it.
> 
> For compatibility reasons, commands, that don't use new flag

s/commands,/commands/

> 'allowed-in-preconfig' explicitly, are not permited to run in

s/explicitly,/explicitly/
s/permited/permitted/

> preconfig state but allowed in all other states like they used
> to be.
> 
> Within this patch allow following commands in preconfig state:
>     qmp_capabilities
>     query-qmp-schema
>     query-commands
>     query-status
>     cont
> to allow qmp connection, basic introspection and moving to the next
> state.

Looks like a reasonable list.  Maybe also query-command-line-options 
should be here?

> 
> PS:
> set-numa-node and query-hotpluggable-cpus will be enabled later in
> a separate patch.
> 
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> ---
> v4:
>    * replaces complex "universal" approach
>       "[PATCH v3 5/9] QAPI: allow to specify valid runstates  per command"
>      with a simpler new command flag "allowed-in-preconfig".
>      (Eric Blake <eblake@redhat.com>)

Thanks; it looks a lot more maintainable now.  However, you need to 
rebase, now that 'allow-oob' has already landed.

> +++ b/qapi/introspect.json
> @@ -259,12 +259,16 @@
>   #
>   # @ret-type: the name of the command's result type.
>   #
> +# @allowed-in-preconfig: command could be executed  in preconfig runstate,

s/could/can/
double space before in

> +#                        default: 'false' (Since 2.12)

/me must resist the urge to call out softfreeze ;)
Eduardo Habkost March 23, 2018, 9:28 p.m. UTC | #2
On Mon, Mar 12, 2018 at 02:11:11PM +0100, Igor Mammedov wrote:
> New option will be used to allow commands, which are prepared/need
> to run run in preconfig state. Other commands that should be able
> to run in preconfig state, should be ammeded to not expect machine
> in initialized state or deal with it.
> 
> For compatibility reasons, commands, that don't use new flag
> 'allowed-in-preconfig' explicitly, are not permited to run in
> preconfig state but allowed in all other states like they used
> to be.
> 
> Within this patch allow following commands in preconfig state:
>    qmp_capabilities
>    query-qmp-schema
>    query-commands
>    query-status
>    cont
> to allow qmp connection, basic introspection and moving to the next
> state.
> 
> PS:
> set-numa-node and query-hotpluggable-cpus will be enabled later in
> a separate patch.
> 
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>

I didn't review the code yet, but:

Shouldn't this be applied before patch 3/9, for bisectability?
Otherwise it will be very easy to crash QEMU after applying patch
3/9.
Igor Mammedov March 28, 2018, 12:29 p.m. UTC | #3
On Fri, 23 Mar 2018 18:28:37 -0300
Eduardo Habkost <ehabkost@redhat.com> wrote:

> On Mon, Mar 12, 2018 at 02:11:11PM +0100, Igor Mammedov wrote:
> > New option will be used to allow commands, which are prepared/need
> > to run run in preconfig state. Other commands that should be able
> > to run in preconfig state, should be ammeded to not expect machine
> > in initialized state or deal with it.
> > 
> > For compatibility reasons, commands, that don't use new flag
> > 'allowed-in-preconfig' explicitly, are not permited to run in
> > preconfig state but allowed in all other states like they used
> > to be.
> > 
> > Within this patch allow following commands in preconfig state:
> >    qmp_capabilities
> >    query-qmp-schema
> >    query-commands
> >    query-status
> >    cont
> > to allow qmp connection, basic introspection and moving to the next
> > state.
> > 
> > PS:
> > set-numa-node and query-hotpluggable-cpus will be enabled later in
> > a separate patch.
> > 
> > Signed-off-by: Igor Mammedov <imammedo@redhat.com>  
> 
> I didn't review the code yet, but:
> 
> Shouldn't this be applied before patch 3/9, for bisectability?
> Otherwise it will be very easy to crash QEMU after applying patch
> 3/9.
no, it isn't going to work.
This patch depends on RUN_STATE_PRECONFIG that is introduced in 3/9.

It could be fine to merge into 3/9 during merge, but then history
wise it would be difficult to read it later with 2 big and mostly
separate changes within one patch.

Considering -preconfig if off by default it shouldn't affect
bisectability in general so I'd keep current patch order.
Igor Mammedov March 28, 2018, 3:23 p.m. UTC | #4
On Fri, 23 Mar 2018 16:11:53 -0500
Eric Blake <eblake@redhat.com> wrote:

> On 03/12/2018 08:11 AM, Igor Mammedov wrote:
[...]
> 
> > preconfig state but allowed in all other states like they used
> > to be.
> > 
> > Within this patch allow following commands in preconfig state:
> >     qmp_capabilities
> >     query-qmp-schema
> >     query-commands
> >     query-status
> >     cont
> > to allow qmp connection, basic introspection and moving to the next
> > state.  
> 
> Looks like a reasonable list.  Maybe also query-command-line-options 
> should be here?
added
 
> > 
> > PS:
> > set-numa-node and query-hotpluggable-cpus will be enabled later in
> > a separate patch.
> > 
> > Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> > ---
> > v4:
> >    * replaces complex "universal" approach
> >       "[PATCH v3 5/9] QAPI: allow to specify valid runstates  per command"
> >      with a simpler new command flag "allowed-in-preconfig".
> >      (Eric Blake <eblake@redhat.com>)  
> 
> Thanks; it looks a lot more maintainable now.  However, you need to 
> rebase, now that 'allow-oob' has already landed.
rebased

[...]

All other comments are addressed as well
Eduardo Habkost March 28, 2018, 7:30 p.m. UTC | #5
On Wed, Mar 28, 2018 at 02:29:57PM +0200, Igor Mammedov wrote:
> On Fri, 23 Mar 2018 18:28:37 -0300
> Eduardo Habkost <ehabkost@redhat.com> wrote:
> 
> > On Mon, Mar 12, 2018 at 02:11:11PM +0100, Igor Mammedov wrote:
> > > New option will be used to allow commands, which are prepared/need
> > > to run run in preconfig state. Other commands that should be able
> > > to run in preconfig state, should be ammeded to not expect machine
> > > in initialized state or deal with it.
> > > 
> > > For compatibility reasons, commands, that don't use new flag
> > > 'allowed-in-preconfig' explicitly, are not permited to run in
> > > preconfig state but allowed in all other states like they used
> > > to be.
> > > 
> > > Within this patch allow following commands in preconfig state:
> > >    qmp_capabilities
> > >    query-qmp-schema
> > >    query-commands
> > >    query-status
> > >    cont
> > > to allow qmp connection, basic introspection and moving to the next
> > > state.
> > > 
> > > PS:
> > > set-numa-node and query-hotpluggable-cpus will be enabled later in
> > > a separate patch.
> > > 
> > > Signed-off-by: Igor Mammedov <imammedo@redhat.com>  
> > 
> > I didn't review the code yet, but:
> > 
> > Shouldn't this be applied before patch 3/9, for bisectability?
> > Otherwise it will be very easy to crash QEMU after applying patch
> > 3/9.
> no, it isn't going to work.
> This patch depends on RUN_STATE_PRECONFIG that is introduced in 3/9.
> 
> It could be fine to merge into 3/9 during merge, but then history
> wise it would be difficult to read it later with 2 big and mostly
> separate changes within one patch.

Yeah, I don't think squashing would be the right answer.

> 
> Considering -preconfig if off by default it shouldn't affect
> bisectability in general so I'd keep current patch order.

Well, it would affect bisectability if debugging a crash that
happens using -preconfig.

The only hunk in this patch that really depends on patch 3/9
seems to be:

  @@ -92,6 +93,13 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
           return NULL;
       }
  
  +    if (runstate_check(RUN_STATE_PRECONFIG) &&
  +        !(cmd->options & QCO_ALLOWED_IN_PRECONFIG)) {
  +        error_setg(errp, "The command '%s' isn't permitted in '%s' state",
  +                   cmd->name, RunState_str(RUN_STATE_PRECONFIG));
  +        return NULL;
  +    }
  +
       if (!qdict_haskey(dict, "arguments")) {
           args = qdict_new();
       } else {
  

What about moving it to patch 3/9?


Or, an alternative is to move the following hunk from patch 3/9 to this patch:

  diff --git a/qapi/run-state.json b/qapi/run-state.json
  index 1c9fff3aef..ce846a570e 100644
  --- a/qapi/run-state.json
  +++ b/qapi/run-state.json
  @@ -49,12 +49,15 @@
   # @colo: guest is paused to save/restore VM state under colo checkpoint,
   #        VM can not get into this state unless colo capability is enabled
   #        for migration. (since 2.8)
  +# @preconfig: QEMU is paused before board specific init callback is executed.
  +#             The state is reachable only if -preconfig CLI option is used.
  +#             (Since 2.12)
   ##
   { 'enum': 'RunState',
     'data': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused',
               'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm',
               'running', 'save-vm', 'shutdown', 'suspended', 'watchdog',
  -            'guest-panicked', 'colo' ] }
  +            'guest-panicked', 'colo', 'preconfig' ] }
  
   ##
   # @StatusInfo:

Which could be an interesting idea, because the QAPI schema
changes would be all grouped inside a single patch, and then
followed by the actual implementation of the -preconfig option.
Igor Mammedov March 29, 2018, 9:53 a.m. UTC | #6
On Wed, 28 Mar 2018 16:30:16 -0300
Eduardo Habkost <ehabkost@redhat.com> wrote:

> On Wed, Mar 28, 2018 at 02:29:57PM +0200, Igor Mammedov wrote:
> > On Fri, 23 Mar 2018 18:28:37 -0300
> > Eduardo Habkost <ehabkost@redhat.com> wrote:
> >   
> > > On Mon, Mar 12, 2018 at 02:11:11PM +0100, Igor Mammedov wrote:  
> > > > New option will be used to allow commands, which are prepared/need
> > > > to run run in preconfig state. Other commands that should be able
> > > > to run in preconfig state, should be ammeded to not expect machine
> > > > in initialized state or deal with it.
> > > > 
> > > > For compatibility reasons, commands, that don't use new flag
> > > > 'allowed-in-preconfig' explicitly, are not permited to run in
> > > > preconfig state but allowed in all other states like they used
> > > > to be.
> > > > 
> > > > Within this patch allow following commands in preconfig state:
> > > >    qmp_capabilities
> > > >    query-qmp-schema
> > > >    query-commands
> > > >    query-status
> > > >    cont
> > > > to allow qmp connection, basic introspection and moving to the next
> > > > state.
> > > > 
> > > > PS:
> > > > set-numa-node and query-hotpluggable-cpus will be enabled later in
> > > > a separate patch.
> > > > 
> > > > Signed-off-by: Igor Mammedov <imammedo@redhat.com>    
> > > 
> > > I didn't review the code yet, but:
> > > 
> > > Shouldn't this be applied before patch 3/9, for bisectability?
> > > Otherwise it will be very easy to crash QEMU after applying patch
> > > 3/9.  
> > no, it isn't going to work.
> > This patch depends on RUN_STATE_PRECONFIG that is introduced in 3/9.
> > 
> > It could be fine to merge into 3/9 during merge, but then history
> > wise it would be difficult to read it later with 2 big and mostly
> > separate changes within one patch.  
> 
> Yeah, I don't think squashing would be the right answer.
> 
> > 
> > Considering -preconfig if off by default it shouldn't affect
> > bisectability in general so I'd keep current patch order.  
> 
> Well, it would affect bisectability if debugging a crash that
> happens using -preconfig.
> 
> The only hunk in this patch that really depends on patch 3/9
> seems to be:
> 
>   @@ -92,6 +93,13 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
>            return NULL;
>        }
>   
>   +    if (runstate_check(RUN_STATE_PRECONFIG) &&
>   +        !(cmd->options & QCO_ALLOWED_IN_PRECONFIG)) {
>   +        error_setg(errp, "The command '%s' isn't permitted in '%s' state",
>   +                   cmd->name, RunState_str(RUN_STATE_PRECONFIG));
>   +        return NULL;
>   +    }
>   +
>        if (!qdict_haskey(dict, "arguments")) {
>            args = qdict_new();
>        } else {
>   
> 
> What about moving it to patch 3/9?
By itself it won't work but with moving following hunk with it

@@ -21,7 +21,8 @@ typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
 typedef enum QmpCommandOptions
 {
     QCO_NO_OPTIONS = 0x0,
-    QCO_NO_SUCCESS_RESP = 0x1,
+    QCO_NO_SUCCESS_RESP = 1U << 0,
+    QCO_ALLOWED_IN_PRECONFIG =  1U << 1,
 } QmpCommandOptions;

it should compile and do proper check in above hunk.

I'll try to do it and see if it works.

> Or, an alternative is to move the following hunk from patch 3/9 to this patch:
> 
>   diff --git a/qapi/run-state.json b/qapi/run-state.json
>   index 1c9fff3aef..ce846a570e 100644
>   --- a/qapi/run-state.json
>   +++ b/qapi/run-state.json
>   @@ -49,12 +49,15 @@
>    # @colo: guest is paused to save/restore VM state under colo checkpoint,
>    #        VM can not get into this state unless colo capability is enabled
>    #        for migration. (since 2.8)
>   +# @preconfig: QEMU is paused before board specific init callback is executed.
>   +#             The state is reachable only if -preconfig CLI option is used.
>   +#             (Since 2.12)
>    ##
>    { 'enum': 'RunState',
>      'data': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused',
>                'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm',
>                'running', 'save-vm', 'shutdown', 'suspended', 'watchdog',
>   -            'guest-panicked', 'colo' ] }
>   +            'guest-panicked', 'colo', 'preconfig' ] }
>   
>    ##
>    # @StatusInfo:
> 
> Which could be an interesting idea, because the QAPI schema
> changes would be all grouped inside a single patch, and then
> followed by the actual implementation of the -preconfig option.
it won't really work as this enum generates RUN_STATE_PRECONFIG,
which is used by 3/9
Eduardo Habkost March 29, 2018, 12:21 p.m. UTC | #7
On Thu, Mar 29, 2018 at 11:53:55AM +0200, Igor Mammedov wrote:
> On Wed, 28 Mar 2018 16:30:16 -0300
> Eduardo Habkost <ehabkost@redhat.com> wrote:
> 
> > On Wed, Mar 28, 2018 at 02:29:57PM +0200, Igor Mammedov wrote:
> > > On Fri, 23 Mar 2018 18:28:37 -0300
> > > Eduardo Habkost <ehabkost@redhat.com> wrote:
> > >   
> > > > On Mon, Mar 12, 2018 at 02:11:11PM +0100, Igor Mammedov wrote:  
> > > > > New option will be used to allow commands, which are prepared/need
> > > > > to run run in preconfig state. Other commands that should be able
> > > > > to run in preconfig state, should be ammeded to not expect machine
> > > > > in initialized state or deal with it.
> > > > > 
> > > > > For compatibility reasons, commands, that don't use new flag
> > > > > 'allowed-in-preconfig' explicitly, are not permited to run in
> > > > > preconfig state but allowed in all other states like they used
> > > > > to be.
> > > > > 
> > > > > Within this patch allow following commands in preconfig state:
> > > > >    qmp_capabilities
> > > > >    query-qmp-schema
> > > > >    query-commands
> > > > >    query-status
> > > > >    cont
> > > > > to allow qmp connection, basic introspection and moving to the next
> > > > > state.
> > > > > 
> > > > > PS:
> > > > > set-numa-node and query-hotpluggable-cpus will be enabled later in
> > > > > a separate patch.
> > > > > 
> > > > > Signed-off-by: Igor Mammedov <imammedo@redhat.com>    
> > > > 
> > > > I didn't review the code yet, but:
> > > > 
> > > > Shouldn't this be applied before patch 3/9, for bisectability?
> > > > Otherwise it will be very easy to crash QEMU after applying patch
> > > > 3/9.  
> > > no, it isn't going to work.
> > > This patch depends on RUN_STATE_PRECONFIG that is introduced in 3/9.
> > > 
> > > It could be fine to merge into 3/9 during merge, but then history
> > > wise it would be difficult to read it later with 2 big and mostly
> > > separate changes within one patch.  
> > 
> > Yeah, I don't think squashing would be the right answer.
> > 
> > > 
> > > Considering -preconfig if off by default it shouldn't affect
> > > bisectability in general so I'd keep current patch order.  
> > 
> > Well, it would affect bisectability if debugging a crash that
> > happens using -preconfig.
> > 
> > The only hunk in this patch that really depends on patch 3/9
> > seems to be:
> > 
> >   @@ -92,6 +93,13 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
> >            return NULL;
> >        }
> >   
> >   +    if (runstate_check(RUN_STATE_PRECONFIG) &&
> >   +        !(cmd->options & QCO_ALLOWED_IN_PRECONFIG)) {
> >   +        error_setg(errp, "The command '%s' isn't permitted in '%s' state",
> >   +                   cmd->name, RunState_str(RUN_STATE_PRECONFIG));
> >   +        return NULL;
> >   +    }
> >   +
> >        if (!qdict_haskey(dict, "arguments")) {
> >            args = qdict_new();
> >        } else {
> >   
> > 
> > What about moving it to patch 3/9?
> By itself it won't work but with moving following hunk with it
> 
> @@ -21,7 +21,8 @@ typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
>  typedef enum QmpCommandOptions
>  {
>      QCO_NO_OPTIONS = 0x0,
> -    QCO_NO_SUCCESS_RESP = 0x1,
> +    QCO_NO_SUCCESS_RESP = 1U << 0,
> +    QCO_ALLOWED_IN_PRECONFIG =  1U << 1,
>  } QmpCommandOptions;
> 
> it should compile and do proper check in above hunk.
> 
> I'll try to do it and see if it works.

Sounds OK to me.

> 
> > Or, an alternative is to move the following hunk from patch 3/9 to this patch:
> > 
> >   diff --git a/qapi/run-state.json b/qapi/run-state.json
> >   index 1c9fff3aef..ce846a570e 100644
> >   --- a/qapi/run-state.json
> >   +++ b/qapi/run-state.json
> >   @@ -49,12 +49,15 @@
> >    # @colo: guest is paused to save/restore VM state under colo checkpoint,
> >    #        VM can not get into this state unless colo capability is enabled
> >    #        for migration. (since 2.8)
> >   +# @preconfig: QEMU is paused before board specific init callback is executed.
> >   +#             The state is reachable only if -preconfig CLI option is used.
> >   +#             (Since 2.12)
> >    ##
> >    { 'enum': 'RunState',
> >      'data': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused',
> >                'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm',
> >                'running', 'save-vm', 'shutdown', 'suspended', 'watchdog',
> >   -            'guest-panicked', 'colo' ] }
> >   +            'guest-panicked', 'colo', 'preconfig' ] }
> >   
> >    ##
> >    # @StatusInfo:
> > 
> > Which could be an interesting idea, because the QAPI schema
> > changes would be all grouped inside a single patch, and then
> > followed by the actual implementation of the -preconfig option.
> it won't really work as this enum generates RUN_STATE_PRECONFIG,
> which is used by 3/9

My suggestion in this case would be applying this patch
(including the above run-state.json change) before 3/9.
diff mbox series

Patch

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 1e694b5..2d02b75 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -21,7 +21,8 @@  typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
 typedef enum QmpCommandOptions
 {
     QCO_NO_OPTIONS = 0x0,
-    QCO_NO_SUCCESS_RESP = 0x1,
+    QCO_NO_SUCCESS_RESP = 1U << 0,
+    QCO_ALLOWED_IN_PRECONFIG =  1U << 1,
 } QmpCommandOptions;
 
 typedef struct QmpCommand
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 25b7180..170f15f 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -556,7 +556,8 @@  following example objects:
 
 Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
          '*returns': TYPE-NAME, '*boxed': true,
-         '*gen': false, '*success-response': false }
+         '*gen': false, '*success-response': false,
+         '*allowed-in-preconfig': true }
 
 Commands are defined by using a dictionary containing several members,
 where three members are most common.  The 'command' member is a
@@ -636,6 +637,13 @@  possible, the command expression should include the optional key
 'success-response' with boolean value false.  So far, only QGA makes
 use of this member.
 
+A command may use optional 'allowed-in-preconfig' key to permit
+its execution at early runtime configuration stage (preconfig runstate).
+If not specified then a command defaults to 'allowed-in-preconfig: false'.
+
+An example of declaring preconfig enabled command:
+ { 'command': 'qmp_capabilities',
+   'allowed-in-preconfig': true }
 
 === Events ===
 
diff --git a/monitor.c b/monitor.c
index ea0ca57..0adf220 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1016,7 +1016,7 @@  void monitor_init_qmp_commands(void)
 
     qmp_register_command(&qmp_commands, "query-qmp-schema",
                          qmp_query_qmp_schema,
-                         QCO_NO_OPTIONS);
+                         QCO_ALLOWED_IN_PRECONFIG);
     qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
                          QCO_NO_OPTIONS);
     qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
@@ -1026,7 +1026,8 @@  void monitor_init_qmp_commands(void)
 
     QTAILQ_INIT(&qmp_cap_negotiation_commands);
     qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
-                         qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS);
+                         qmp_marshal_qmp_capabilities,
+                         QCO_ALLOWED_IN_PRECONFIG);
 }
 
 void qmp_qmp_capabilities(Error **errp)
diff --git a/qapi/introspect.json b/qapi/introspect.json
index 5b3e6e9..05faded 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -259,12 +259,16 @@ 
 #
 # @ret-type: the name of the command's result type.
 #
+# @allowed-in-preconfig: command could be executed  in preconfig runstate,
+#                        default: 'false' (Since 2.12)
+#
 # TODO: @success-response (currently irrelevant, because it's QGA, not QMP)
 #
 # Since: 2.5
 ##
 { 'struct': 'SchemaInfoCommand',
-  'data': { 'arg-type': 'str', 'ret-type': 'str' } }
+  'data': { 'arg-type': 'str', 'ret-type': 'str',
+            'allowed-in-preconfig': 'bool' } }
 
 ##
 # @SchemaInfoEvent:
diff --git a/qapi/misc.json b/qapi/misc.json
index bcd5d10..1f48d35 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -24,7 +24,7 @@ 
 # Since: 0.13
 #
 ##
-{ 'command': 'qmp_capabilities' }
+{ 'command': 'qmp_capabilities', 'allowed-in-preconfig': true }
 
 ##
 # @VersionTriple:
@@ -127,7 +127,8 @@ 
 # Note: This example has been shortened as the real response is too long.
 #
 ##
-{ 'command': 'query-commands', 'returns': ['CommandInfo'] }
+{ 'command': 'query-commands', 'returns': ['CommandInfo'],
+  'allowed-in-preconfig': true }
 
 ##
 # @LostTickPolicy:
@@ -1180,7 +1181,7 @@ 
 # <- { "return": {} }
 #
 ##
-{ 'command': 'cont' }
+{ 'command': 'cont', 'allowed-in-preconfig': true }
 
 ##
 # @system_wakeup:
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index e31ac4b..81dbd19 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -17,6 +17,7 @@ 
 #include "qapi/qmp/json-parser.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qjson.h"
+#include "sysemu/sysemu.h"
 
 static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
 {
@@ -92,6 +93,13 @@  static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
         return NULL;
     }
 
+    if (runstate_check(RUN_STATE_PRECONFIG) &&
+        !(cmd->options & QCO_ALLOWED_IN_PRECONFIG)) {
+        error_setg(errp, "The command '%s' isn't permitted in '%s' state",
+                   cmd->name, RunState_str(RUN_STATE_PRECONFIG));
+        return NULL;
+    }
+
     if (!qdict_haskey(dict, "arguments")) {
         args = qdict_new();
     } else {
diff --git a/qapi/run-state.json b/qapi/run-state.json
index ce846a5..174a2a3 100644
--- a/qapi/run-state.json
+++ b/qapi/run-state.json
@@ -94,7 +94,8 @@ 
 #                  "status": "running" } }
 #
 ##
-{ 'command': 'query-status', 'returns': 'StatusInfo' }
+{ 'command': 'query-status', 'returns': 'StatusInfo',
+  'allowed-in-preconfig': true }
 
 ##
 # @SHUTDOWN:
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 21a7e0d..bd8dc5e 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -193,10 +193,18 @@  out:
     return ret
 
 
-def gen_register_command(name, success_response):
-    options = 'QCO_NO_OPTIONS'
+def gen_register_command(name, success_response, allowed_in_preconfig):
+    options = []
+
     if not success_response:
-        options = 'QCO_NO_SUCCESS_RESP'
+        options += ['QCO_NO_SUCCESS_RESP']
+    if allowed_in_preconfig:
+        options += ['QCO_ALLOWED_IN_PRECONFIG']
+
+    if not options:
+        options = ['QCO_NO_OPTIONS']
+
+    options = " | ".join(options)
 
     ret = mcgen('''
     qmp_register_command(cmds, "%(name)s",
@@ -268,7 +276,7 @@  void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
         genc.add(gen_registry(self._regy, self._prefix))
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, allowed_in_preconfig):
         if not gen:
             return
         self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
@@ -277,7 +285,8 @@  void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
             self._genc.add(gen_marshal_output(ret_type))
         self._genh.add(gen_marshal_decl(name))
         self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
-        self._regy += gen_register_command(name, success_response)
+        self._regy += gen_register_command(name, success_response,
+                                           allowed_in_preconfig)
 
 
 def gen_commands(schema, output_dir, prefix):
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 97e9060..e92f514 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -921,7 +921,8 @@  def check_exprs(exprs):
         elif 'command' in expr:
             meta = 'command'
             check_keys(expr_elem, 'command', [],
-                       ['data', 'returns', 'gen', 'success-response', 'boxed'])
+                       ['data', 'returns', 'gen', 'success-response',
+                        'boxed', 'allowed-in-preconfig'])
         elif 'event' in expr:
             meta = 'event'
             check_keys(expr_elem, 'event', [], ['data', 'boxed'])
@@ -1044,7 +1045,7 @@  class QAPISchemaVisitor(object):
         pass
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, allowed_in_preconfig):
         pass
 
     def visit_event(self, name, info, arg_type, boxed):
@@ -1421,7 +1422,7 @@  class QAPISchemaAlternateType(QAPISchemaType):
 
 class QAPISchemaCommand(QAPISchemaEntity):
     def __init__(self, name, info, doc, arg_type, ret_type,
-                 gen, success_response, boxed):
+                 gen, success_response, boxed, allowed_in_preconfig):
         QAPISchemaEntity.__init__(self, name, info, doc)
         assert not arg_type or isinstance(arg_type, str)
         assert not ret_type or isinstance(ret_type, str)
@@ -1432,6 +1433,7 @@  class QAPISchemaCommand(QAPISchemaEntity):
         self.gen = gen
         self.success_response = success_response
         self.boxed = boxed
+        self.allowed_in_preconfig = allowed_in_preconfig
 
     def check(self, schema):
         if self._arg_type_name:
@@ -1455,7 +1457,8 @@  class QAPISchemaCommand(QAPISchemaEntity):
     def visit(self, visitor):
         visitor.visit_command(self.name, self.info,
                               self.arg_type, self.ret_type,
-                              self.gen, self.success_response, self.boxed)
+                              self.gen, self.success_response, self.boxed,
+                              self.allowed_in_preconfig)
 
 
 class QAPISchemaEvent(QAPISchemaEntity):
@@ -1674,6 +1677,7 @@  class QAPISchema(object):
         gen = expr.get('gen', True)
         success_response = expr.get('success-response', True)
         boxed = expr.get('boxed', False)
+        allowed_in_preconfig = expr.get('allowed-in-preconfig', False)
         if isinstance(data, OrderedDict):
             data = self._make_implicit_object_type(
                 name, info, doc, 'arg', self._make_members(data, info))
@@ -1681,7 +1685,8 @@  class QAPISchema(object):
             assert len(rets) == 1
             rets = self._make_array_type(rets[0], info)
         self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
-                                           gen, success_response, boxed))
+                                           gen, success_response, boxed,
+                                           allowed_in_preconfig))
 
     def _def_event(self, expr, info, doc):
         name = expr['event']
diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py
index 0ea68bf..464c89b 100644
--- a/scripts/qapi/doc.py
+++ b/scripts/qapi/doc.py
@@ -228,7 +228,7 @@  class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
                                body=texi_entity(doc, 'Members')))
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, allowed_in_preconfig):
         doc = self.cur_doc
         if boxed:
             body = texi_body(doc)
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index f66c397..fa7dc01 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -29,6 +29,11 @@  def to_json(obj, level=0):
                               to_json(obj[key], level + 1))
                 for key in sorted(obj.keys())]
         ret = '{' + ', '.join(elts) + '}'
+    elif isinstance(obj, bool):
+        if obj:
+            ret = 'true'
+        else:
+            ret = 'false'
     else:
         assert False                # not implemented
     if level == 1:
@@ -160,12 +165,13 @@  const char %(c_name)s[] = %(c_string)s;
                                     for m in variants.variants]})
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, allowed_in_preconfig):
         arg_type = arg_type or self._schema.the_empty_object_type
         ret_type = ret_type or self._schema.the_empty_object_type
         self._gen_json(name, 'command',
                        {'arg-type': self._use_type(arg_type),
-                        'ret-type': self._use_type(ret_type)})
+                        'ret-type': self._use_type(ret_type),
+                        'allowed-in-preconfig': allowed_in_preconfig})
 
     def visit_event(self, name, info, arg_type, boxed):
         arg_type = arg_type or self._schema.the_empty_object_type
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 67e417e..7b22c90 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -42,7 +42,7 @@  class QAPISchemaTestVisitor(QAPISchemaVisitor):
         self._print_variants(variants)
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, allowed_in_preconfig):
         print('command %s %s -> %s' % \
               (name, arg_type and arg_type.name, ret_type and ret_type.name))
         print('   gen=%s success_response=%s boxed=%s' % \