[PATCH V3 4/9] vl: helper to request exec

Steve Sistare posted 9 patches 3 months ago
Maintainers: Steve Sistare <steven.sistare@oracle.com>, Peter Xu <peterx@redhat.com>, Fabiano Rosas <farosas@suse.de>, "Dr. David Alan Gilbert" <dave@treblig.org>, Alex Williamson <alex.williamson@redhat.com>, "Cédric Le Goater" <clg@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, Eric Blake <eblake@redhat.com>, Markus Armbruster <armbru@redhat.com>, Stefan Weil <sw@weilnetz.de>
There is a newer version of this series
[PATCH V3 4/9] vl: helper to request exec
Posted by Steve Sistare 3 months ago
Add a qemu_system_exec_request() hook that causes the main loop to exit and
exec a command using the specified arguments.  This will be used during CPR
to exec a new version of QEMU.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 include/system/runstate.h |  3 +++
 system/runstate.c         | 29 +++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/include/system/runstate.h b/include/system/runstate.h
index 929379a..c005f49 100644
--- a/include/system/runstate.h
+++ b/include/system/runstate.h
@@ -128,6 +128,8 @@ typedef enum WakeupReason {
     QEMU_WAKEUP_REASON_OTHER,
 } WakeupReason;
 
+typedef void (*qemu_exec_func)(char **exec_argv);
+
 void qemu_system_reset_request(ShutdownCause reason);
 void qemu_system_suspend_request(void);
 void qemu_register_suspend_notifier(Notifier *notifier);
@@ -139,6 +141,7 @@ void qemu_register_wakeup_support(void);
 void qemu_system_shutdown_request_with_code(ShutdownCause reason,
                                             int exit_code);
 void qemu_system_shutdown_request(ShutdownCause reason);
+void qemu_system_exec_request(qemu_exec_func func, const strList *args);
 void qemu_system_powerdown_request(void);
 void qemu_register_powerdown_notifier(Notifier *notifier);
 void qemu_register_shutdown_notifier(Notifier *notifier);
diff --git a/system/runstate.c b/system/runstate.c
index 6178b00..b4980ff 100644
--- a/system/runstate.c
+++ b/system/runstate.c
@@ -41,6 +41,7 @@
 #include "qapi/error.h"
 #include "qapi/qapi-commands-run-state.h"
 #include "qapi/qapi-events-run-state.h"
+#include "qapi/type-helpers.h"
 #include "qemu/accel.h"
 #include "qemu/error-report.h"
 #include "qemu/job.h"
@@ -422,6 +423,8 @@ static NotifierList wakeup_notifiers =
 static NotifierList shutdown_notifiers =
     NOTIFIER_LIST_INITIALIZER(shutdown_notifiers);
 static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE);
+qemu_exec_func exec_func;
+static char **exec_argv;
 
 ShutdownCause qemu_shutdown_requested_get(void)
 {
@@ -443,6 +446,11 @@ static int qemu_shutdown_requested(void)
     return qatomic_xchg(&shutdown_requested, SHUTDOWN_CAUSE_NONE);
 }
 
+static int qemu_exec_requested(void)
+{
+    return exec_argv != NULL;
+}
+
 static void qemu_kill_report(void)
 {
     if (!qtest_driver() && shutdown_signal) {
@@ -803,6 +811,23 @@ void qemu_system_shutdown_request(ShutdownCause reason)
     qemu_notify_event();
 }
 
+static void qemu_system_exec(void)
+{
+    exec_func(exec_argv);
+
+    /* exec failed */
+    g_strfreev(exec_argv);
+    exec_argv = NULL;
+    exec_func = NULL;
+}
+
+void qemu_system_exec_request(qemu_exec_func func, const strList *args)
+{
+    exec_func = func;
+    exec_argv = strv_from_str_list(args);
+    qemu_notify_event();
+}
+
 static void qemu_system_powerdown(void)
 {
     qapi_event_send_powerdown();
@@ -849,6 +874,10 @@ static bool main_loop_should_exit(int *status)
     if (qemu_suspend_requested()) {
         qemu_system_suspend();
     }
+    if (qemu_exec_requested()) {
+        qemu_system_exec();
+        return false;
+    }
     request = qemu_shutdown_requested();
     if (request) {
         qemu_kill_report();
-- 
1.8.3.1
Re: [PATCH V3 4/9] vl: helper to request exec
Posted by Peter Xu 2 months ago
On Thu, Aug 14, 2025 at 10:17:18AM -0700, Steve Sistare wrote:
> Add a qemu_system_exec_request() hook that causes the main loop to exit and
> exec a command using the specified arguments.  This will be used during CPR
> to exec a new version of QEMU.
> 
> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
> ---
>  include/system/runstate.h |  3 +++
>  system/runstate.c         | 29 +++++++++++++++++++++++++++++
>  2 files changed, 32 insertions(+)
> 
> diff --git a/include/system/runstate.h b/include/system/runstate.h
> index 929379a..c005f49 100644
> --- a/include/system/runstate.h
> +++ b/include/system/runstate.h
> @@ -128,6 +128,8 @@ typedef enum WakeupReason {
>      QEMU_WAKEUP_REASON_OTHER,
>  } WakeupReason;
>  
> +typedef void (*qemu_exec_func)(char **exec_argv);
> +
>  void qemu_system_reset_request(ShutdownCause reason);
>  void qemu_system_suspend_request(void);
>  void qemu_register_suspend_notifier(Notifier *notifier);
> @@ -139,6 +141,7 @@ void qemu_register_wakeup_support(void);
>  void qemu_system_shutdown_request_with_code(ShutdownCause reason,
>                                              int exit_code);
>  void qemu_system_shutdown_request(ShutdownCause reason);
> +void qemu_system_exec_request(qemu_exec_func func, const strList *args);
>  void qemu_system_powerdown_request(void);
>  void qemu_register_powerdown_notifier(Notifier *notifier);
>  void qemu_register_shutdown_notifier(Notifier *notifier);
> diff --git a/system/runstate.c b/system/runstate.c
> index 6178b00..b4980ff 100644
> --- a/system/runstate.c
> +++ b/system/runstate.c
> @@ -41,6 +41,7 @@
>  #include "qapi/error.h"
>  #include "qapi/qapi-commands-run-state.h"
>  #include "qapi/qapi-events-run-state.h"
> +#include "qapi/type-helpers.h"
>  #include "qemu/accel.h"
>  #include "qemu/error-report.h"
>  #include "qemu/job.h"
> @@ -422,6 +423,8 @@ static NotifierList wakeup_notifiers =
>  static NotifierList shutdown_notifiers =
>      NOTIFIER_LIST_INITIALIZER(shutdown_notifiers);
>  static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE);
> +qemu_exec_func exec_func;
> +static char **exec_argv;
>  
>  ShutdownCause qemu_shutdown_requested_get(void)
>  {
> @@ -443,6 +446,11 @@ static int qemu_shutdown_requested(void)
>      return qatomic_xchg(&shutdown_requested, SHUTDOWN_CAUSE_NONE);
>  }
>  
> +static int qemu_exec_requested(void)
> +{
> +    return exec_argv != NULL;
> +}
> +
>  static void qemu_kill_report(void)
>  {
>      if (!qtest_driver() && shutdown_signal) {
> @@ -803,6 +811,23 @@ void qemu_system_shutdown_request(ShutdownCause reason)
>      qemu_notify_event();
>  }
>  
> +static void qemu_system_exec(void)
> +{
> +    exec_func(exec_argv);
> +
> +    /* exec failed */
> +    g_strfreev(exec_argv);
> +    exec_argv = NULL;
> +    exec_func = NULL;

Would this really happen?

If so, do we at least want to dump something?

> +}
> +
> +void qemu_system_exec_request(qemu_exec_func func, const strList *args)
> +{
> +    exec_func = func;
> +    exec_argv = strv_from_str_list(args);
> +    qemu_notify_event();
> +}
> +
>  static void qemu_system_powerdown(void)
>  {
>      qapi_event_send_powerdown();
> @@ -849,6 +874,10 @@ static bool main_loop_should_exit(int *status)
>      if (qemu_suspend_requested()) {
>          qemu_system_suspend();
>      }
> +    if (qemu_exec_requested()) {
> +        qemu_system_exec();
> +        return false;
> +    }

Some explanation of why it needs to be done explicitly here would be
helpful.  E.g., can we do exec inside a BH scheduled for the main thread?
What if we exec() directly in another thread (rather than the main loop
thread)?

>      request = qemu_shutdown_requested();
>      if (request) {
>          qemu_kill_report();
> -- 
> 1.8.3.1
> 

-- 
Peter Xu
Re: [PATCH V3 4/9] vl: helper to request exec
Posted by Steven Sistare 2 months ago
On 9/9/2025 11:51 AM, Peter Xu wrote:
> On Thu, Aug 14, 2025 at 10:17:18AM -0700, Steve Sistare wrote:
>> Add a qemu_system_exec_request() hook that causes the main loop to exit and
>> exec a command using the specified arguments.  This will be used during CPR
>> to exec a new version of QEMU.
>>
>> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
>> ---
>>   include/system/runstate.h |  3 +++
>>   system/runstate.c         | 29 +++++++++++++++++++++++++++++
>>   2 files changed, 32 insertions(+)
>>
>> diff --git a/include/system/runstate.h b/include/system/runstate.h
>> index 929379a..c005f49 100644
>> --- a/include/system/runstate.h
>> +++ b/include/system/runstate.h
>> @@ -128,6 +128,8 @@ typedef enum WakeupReason {
>>       QEMU_WAKEUP_REASON_OTHER,
>>   } WakeupReason;
>>   
>> +typedef void (*qemu_exec_func)(char **exec_argv);
>> +
>>   void qemu_system_reset_request(ShutdownCause reason);
>>   void qemu_system_suspend_request(void);
>>   void qemu_register_suspend_notifier(Notifier *notifier);
>> @@ -139,6 +141,7 @@ void qemu_register_wakeup_support(void);
>>   void qemu_system_shutdown_request_with_code(ShutdownCause reason,
>>                                               int exit_code);
>>   void qemu_system_shutdown_request(ShutdownCause reason);
>> +void qemu_system_exec_request(qemu_exec_func func, const strList *args);
>>   void qemu_system_powerdown_request(void);
>>   void qemu_register_powerdown_notifier(Notifier *notifier);
>>   void qemu_register_shutdown_notifier(Notifier *notifier);
>> diff --git a/system/runstate.c b/system/runstate.c
>> index 6178b00..b4980ff 100644
>> --- a/system/runstate.c
>> +++ b/system/runstate.c
>> @@ -41,6 +41,7 @@
>>   #include "qapi/error.h"
>>   #include "qapi/qapi-commands-run-state.h"
>>   #include "qapi/qapi-events-run-state.h"
>> +#include "qapi/type-helpers.h"
>>   #include "qemu/accel.h"
>>   #include "qemu/error-report.h"
>>   #include "qemu/job.h"
>> @@ -422,6 +423,8 @@ static NotifierList wakeup_notifiers =
>>   static NotifierList shutdown_notifiers =
>>       NOTIFIER_LIST_INITIALIZER(shutdown_notifiers);
>>   static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE);
>> +qemu_exec_func exec_func;
>> +static char **exec_argv;
>>   
>>   ShutdownCause qemu_shutdown_requested_get(void)
>>   {
>> @@ -443,6 +446,11 @@ static int qemu_shutdown_requested(void)
>>       return qatomic_xchg(&shutdown_requested, SHUTDOWN_CAUSE_NONE);
>>   }
>>   
>> +static int qemu_exec_requested(void)
>> +{
>> +    return exec_argv != NULL;
>> +}
>> +
>>   static void qemu_kill_report(void)
>>   {
>>       if (!qtest_driver() && shutdown_signal) {
>> @@ -803,6 +811,23 @@ void qemu_system_shutdown_request(ShutdownCause reason)
>>       qemu_notify_event();
>>   }
>>   
>> +static void qemu_system_exec(void)
>> +{
>> +    exec_func(exec_argv);
>> +
>> +    /* exec failed */
>> +    g_strfreev(exec_argv);
>> +    exec_argv = NULL;
>> +    exec_func = NULL;
> 
> Would this really happen?
> 
> If so, do we at least want to dump something?
> 
>> +}
>> +
>> +void qemu_system_exec_request(qemu_exec_func func, const strList *args)
>> +{
>> +    exec_func = func;
>> +    exec_argv = strv_from_str_list(args);
>> +    qemu_notify_event();
>> +}
>> +
>>   static void qemu_system_powerdown(void)
>>   {
>>       qapi_event_send_powerdown();
>> @@ -849,6 +874,10 @@ static bool main_loop_should_exit(int *status)
>>       if (qemu_suspend_requested()) {
>>           qemu_system_suspend();
>>       }
>> +    if (qemu_exec_requested()) {
>> +        qemu_system_exec();
>> +        return false;
>> +    }
> 
> Some explanation of why it needs to be done explicitly here would be
> helpful.  E.g., can we do exec inside a BH scheduled for the main thread?
> What if we exec() directly in another thread (rather than the main loop
> thread)?

A BH is a good idea, thanks.
It only requires a few lines of code, and no globals.
I will drop this patch and add a BH to patch "migration: cpr-exec mode".

- Steve
Re: [PATCH V3 4/9] vl: helper to request exec
Posted by Peter Xu 2 months ago
On Fri, Sep 12, 2025 at 10:49:23AM -0400, Steven Sistare wrote:
> On 9/9/2025 11:51 AM, Peter Xu wrote:
> > On Thu, Aug 14, 2025 at 10:17:18AM -0700, Steve Sistare wrote:
> > > Add a qemu_system_exec_request() hook that causes the main loop to exit and
> > > exec a command using the specified arguments.  This will be used during CPR
> > > to exec a new version of QEMU.
> > > 
> > > Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
> > > ---
> > >   include/system/runstate.h |  3 +++
> > >   system/runstate.c         | 29 +++++++++++++++++++++++++++++
> > >   2 files changed, 32 insertions(+)
> > > 
> > > diff --git a/include/system/runstate.h b/include/system/runstate.h
> > > index 929379a..c005f49 100644
> > > --- a/include/system/runstate.h
> > > +++ b/include/system/runstate.h
> > > @@ -128,6 +128,8 @@ typedef enum WakeupReason {
> > >       QEMU_WAKEUP_REASON_OTHER,
> > >   } WakeupReason;
> > > +typedef void (*qemu_exec_func)(char **exec_argv);
> > > +
> > >   void qemu_system_reset_request(ShutdownCause reason);
> > >   void qemu_system_suspend_request(void);
> > >   void qemu_register_suspend_notifier(Notifier *notifier);
> > > @@ -139,6 +141,7 @@ void qemu_register_wakeup_support(void);
> > >   void qemu_system_shutdown_request_with_code(ShutdownCause reason,
> > >                                               int exit_code);
> > >   void qemu_system_shutdown_request(ShutdownCause reason);
> > > +void qemu_system_exec_request(qemu_exec_func func, const strList *args);
> > >   void qemu_system_powerdown_request(void);
> > >   void qemu_register_powerdown_notifier(Notifier *notifier);
> > >   void qemu_register_shutdown_notifier(Notifier *notifier);
> > > diff --git a/system/runstate.c b/system/runstate.c
> > > index 6178b00..b4980ff 100644
> > > --- a/system/runstate.c
> > > +++ b/system/runstate.c
> > > @@ -41,6 +41,7 @@
> > >   #include "qapi/error.h"
> > >   #include "qapi/qapi-commands-run-state.h"
> > >   #include "qapi/qapi-events-run-state.h"
> > > +#include "qapi/type-helpers.h"
> > >   #include "qemu/accel.h"
> > >   #include "qemu/error-report.h"
> > >   #include "qemu/job.h"
> > > @@ -422,6 +423,8 @@ static NotifierList wakeup_notifiers =
> > >   static NotifierList shutdown_notifiers =
> > >       NOTIFIER_LIST_INITIALIZER(shutdown_notifiers);
> > >   static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE);
> > > +qemu_exec_func exec_func;
> > > +static char **exec_argv;
> > >   ShutdownCause qemu_shutdown_requested_get(void)
> > >   {
> > > @@ -443,6 +446,11 @@ static int qemu_shutdown_requested(void)
> > >       return qatomic_xchg(&shutdown_requested, SHUTDOWN_CAUSE_NONE);
> > >   }
> > > +static int qemu_exec_requested(void)
> > > +{
> > > +    return exec_argv != NULL;
> > > +}
> > > +
> > >   static void qemu_kill_report(void)
> > >   {
> > >       if (!qtest_driver() && shutdown_signal) {
> > > @@ -803,6 +811,23 @@ void qemu_system_shutdown_request(ShutdownCause reason)
> > >       qemu_notify_event();
> > >   }
> > > +static void qemu_system_exec(void)
> > > +{
> > > +    exec_func(exec_argv);
> > > +
> > > +    /* exec failed */
> > > +    g_strfreev(exec_argv);
> > > +    exec_argv = NULL;
> > > +    exec_func = NULL;
> > 
> > Would this really happen?
> > 
> > If so, do we at least want to dump something?
> > 
> > > +}
> > > +
> > > +void qemu_system_exec_request(qemu_exec_func func, const strList *args)
> > > +{
> > > +    exec_func = func;
> > > +    exec_argv = strv_from_str_list(args);
> > > +    qemu_notify_event();
> > > +}
> > > +
> > >   static void qemu_system_powerdown(void)
> > >   {
> > >       qapi_event_send_powerdown();
> > > @@ -849,6 +874,10 @@ static bool main_loop_should_exit(int *status)
> > >       if (qemu_suspend_requested()) {
> > >           qemu_system_suspend();
> > >       }
> > > +    if (qemu_exec_requested()) {
> > > +        qemu_system_exec();
> > > +        return false;
> > > +    }
> > 
> > Some explanation of why it needs to be done explicitly here would be
> > helpful.  E.g., can we do exec inside a BH scheduled for the main thread?
> > What if we exec() directly in another thread (rather than the main loop
> > thread)?
> 
> A BH is a good idea, thanks.
> It only requires a few lines of code, and no globals.
> I will drop this patch and add a BH to patch "migration: cpr-exec mode".

That would be better, thanks.

Then, what happens if we exec() in the migration thread directly?  IOW, is
BH required (to serialize with something happening in the main thread), or
just looks slightly more clean when exec happens in the main thread?

These info would be great to be put into commit message, but if there's no
obvious reason, IMHO we _could_ exec() directly in the migration thread, as
I don't see whatever to be synchronized in the main thread..  Anyway, if we
want to exec(), IMHO it would be best as straightforward as possible.

Thanks,

-- 
Peter Xu
Re: [PATCH V3 4/9] vl: helper to request exec
Posted by Steven Sistare 1 month, 3 weeks ago
On 9/15/2025 12:35 PM, Peter Xu wrote:
> On Fri, Sep 12, 2025 at 10:49:23AM -0400, Steven Sistare wrote:
>> On 9/9/2025 11:51 AM, Peter Xu wrote:
>>> On Thu, Aug 14, 2025 at 10:17:18AM -0700, Steve Sistare wrote:
>>>> Add a qemu_system_exec_request() hook that causes the main loop to exit and
>>>> exec a command using the specified arguments.  This will be used during CPR
>>>> to exec a new version of QEMU.
>>>>
>>>> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
>>>> ---
>>>>    include/system/runstate.h |  3 +++
>>>>    system/runstate.c         | 29 +++++++++++++++++++++++++++++
>>>>    2 files changed, 32 insertions(+)
>>>>
>>>> diff --git a/include/system/runstate.h b/include/system/runstate.h
>>>> index 929379a..c005f49 100644
>>>> --- a/include/system/runstate.h
>>>> +++ b/include/system/runstate.h
>>>> @@ -128,6 +128,8 @@ typedef enum WakeupReason {
>>>>        QEMU_WAKEUP_REASON_OTHER,
>>>>    } WakeupReason;
>>>> +typedef void (*qemu_exec_func)(char **exec_argv);
>>>> +
>>>>    void qemu_system_reset_request(ShutdownCause reason);
>>>>    void qemu_system_suspend_request(void);
>>>>    void qemu_register_suspend_notifier(Notifier *notifier);
>>>> @@ -139,6 +141,7 @@ void qemu_register_wakeup_support(void);
>>>>    void qemu_system_shutdown_request_with_code(ShutdownCause reason,
>>>>                                                int exit_code);
>>>>    void qemu_system_shutdown_request(ShutdownCause reason);
>>>> +void qemu_system_exec_request(qemu_exec_func func, const strList *args);
>>>>    void qemu_system_powerdown_request(void);
>>>>    void qemu_register_powerdown_notifier(Notifier *notifier);
>>>>    void qemu_register_shutdown_notifier(Notifier *notifier);
>>>> diff --git a/system/runstate.c b/system/runstate.c
>>>> index 6178b00..b4980ff 100644
>>>> --- a/system/runstate.c
>>>> +++ b/system/runstate.c
>>>> @@ -41,6 +41,7 @@
>>>>    #include "qapi/error.h"
>>>>    #include "qapi/qapi-commands-run-state.h"
>>>>    #include "qapi/qapi-events-run-state.h"
>>>> +#include "qapi/type-helpers.h"
>>>>    #include "qemu/accel.h"
>>>>    #include "qemu/error-report.h"
>>>>    #include "qemu/job.h"
>>>> @@ -422,6 +423,8 @@ static NotifierList wakeup_notifiers =
>>>>    static NotifierList shutdown_notifiers =
>>>>        NOTIFIER_LIST_INITIALIZER(shutdown_notifiers);
>>>>    static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE);
>>>> +qemu_exec_func exec_func;
>>>> +static char **exec_argv;
>>>>    ShutdownCause qemu_shutdown_requested_get(void)
>>>>    {
>>>> @@ -443,6 +446,11 @@ static int qemu_shutdown_requested(void)
>>>>        return qatomic_xchg(&shutdown_requested, SHUTDOWN_CAUSE_NONE);
>>>>    }
>>>> +static int qemu_exec_requested(void)
>>>> +{
>>>> +    return exec_argv != NULL;
>>>> +}
>>>> +
>>>>    static void qemu_kill_report(void)
>>>>    {
>>>>        if (!qtest_driver() && shutdown_signal) {
>>>> @@ -803,6 +811,23 @@ void qemu_system_shutdown_request(ShutdownCause reason)
>>>>        qemu_notify_event();
>>>>    }
>>>> +static void qemu_system_exec(void)
>>>> +{
>>>> +    exec_func(exec_argv);
>>>> +
>>>> +    /* exec failed */
>>>> +    g_strfreev(exec_argv);
>>>> +    exec_argv = NULL;
>>>> +    exec_func = NULL;
>>>
>>> Would this really happen?
>>>
>>> If so, do we at least want to dump something?
>>>
>>>> +}
>>>> +
>>>> +void qemu_system_exec_request(qemu_exec_func func, const strList *args)
>>>> +{
>>>> +    exec_func = func;
>>>> +    exec_argv = strv_from_str_list(args);
>>>> +    qemu_notify_event();
>>>> +}
>>>> +
>>>>    static void qemu_system_powerdown(void)
>>>>    {
>>>>        qapi_event_send_powerdown();
>>>> @@ -849,6 +874,10 @@ static bool main_loop_should_exit(int *status)
>>>>        if (qemu_suspend_requested()) {
>>>>            qemu_system_suspend();
>>>>        }
>>>> +    if (qemu_exec_requested()) {
>>>> +        qemu_system_exec();
>>>> +        return false;
>>>> +    }
>>>
>>> Some explanation of why it needs to be done explicitly here would be
>>> helpful.  E.g., can we do exec inside a BH scheduled for the main thread?
>>> What if we exec() directly in another thread (rather than the main loop
>>> thread)?
>>
>> A BH is a good idea, thanks.
>> It only requires a few lines of code, and no globals.
>> I will drop this patch and add a BH to patch "migration: cpr-exec mode".
> 
> That would be better, thanks.
> 
> Then, what happens if we exec() in the migration thread directly?  IOW, is
> BH required (to serialize with something happening in the main thread), or
> just looks slightly more clean when exec happens in the main thread?
> 
> These info would be great to be put into commit message, but if there's no
> obvious reason, IMHO we _could_ exec() directly in the migration thread, as
> I don't see whatever to be synchronized in the main thread..  Anyway, if we
> want to exec(), IMHO it would be best as straightforward as possible.

A direct exec is not desirable for 2 reasons.

One is that cpr_exec_notifier is called in the middle of processing MIG_EVENT_PRECOPY_DONE
notifiers, and some notifiers may fall in the list after cpr_exec_notifier, and would never
be called.

Two is that cpr_exec_notifier is not called in migration_thread, it is called from a bh:
   migration_bh_dispatch_bh -> migration_cleanup -> migration_call_notifiers -> cpr_exec_notifier
so it is cleanest to post another bh to do the actual exec.

I will add those notes to the commit message.

- Steve