Patchwork [v7,2/6] Introduce "save-devices-state"

login
register
mail settings
Submitter Stefano Stabellini
Date March 16, 2012, 12:13 p.m.
Message ID <1331899989-7756-2-git-send-email-stefano.stabellini@eu.citrix.com>
Download mbox | patch
Permalink /patch/147196/
State New
Headers show

Comments

Stefano Stabellini - March 16, 2012, 12:13 p.m.
- add an "is_ram" flag to SaveStateEntry;

- register_savevm_live sets is_ram for live_savevm devices;

- introduce a "save-devices-state" QAPI command that can be used to save
the state of all devices, but not the RAM or the block devices of the
VM.

Changes in v7:

- rename save_devices to save-devices-state.

Changes in v6:

- remove the is_ram parameter from register_savevm_live and sets is_ram
if the device is a live_savevm device;

- introduce save_devices as a QAPI command, write a better description
for it;

- fix CODING_STYLE;

- introduce a new doc to explain the save format used by save_devices.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
CC: Luiz Capitulino <lcapitulino@redhat.com>

---
 docs/save-devices-state.txt |   33 ++++++++++++++++++++
 qapi-schema.json            |   18 +++++++++++
 qmp-commands.hx             |   25 +++++++++++++++
 savevm.c                    |   71 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 147 insertions(+), 0 deletions(-)
 create mode 100644 docs/save-devices-state.txt
Eric Blake - March 16, 2012, 3:49 p.m.
On 03/16/2012 06:13 AM, Stefano Stabellini wrote:
> - add an "is_ram" flag to SaveStateEntry;
> 
> - register_savevm_live sets is_ram for live_savevm devices;
> 
> - introduce a "save-devices-state" QAPI command that can be used to save
> the state of all devices, but not the RAM or the block devices of the
> VM.
> 

> +QEMU has code to load/save the state of the guest that it is running.
> +These are two complementary operations.  Saving the state just does
> +that, saves the state for each device that the guest is running.
> +
> +These operations are normally used with migration (see migration.txt),
> +however it is also possible to save the state of all devices to file,
> +without saving the RAM or the block devices of the VM.
> +
> +This operation is called "save-devices-state" (see QMP/qmp-commands.txt)

Is there a complimentary load-devices-state?

Just to make sure I'm clear, there are three things to save before you
have a complete picture of a running VM:

disk state (can be saved with 'savevm' to internal qcow2 snapshots, or
with 'transaction' and 'blockdev-snapshot-sync' by creating external
snapshots, or by 'migrate' to a file)

RAM state (can be saved with 'savevm' to internal qcow2 snapshot, or
with 'migrate' to a file; it is also possible to start qemu with a
command line parameter telling which backing file tracks RAM state)

device state (can be saved with 'savevm' to internal qcow2 snapshot, or
with 'migrate' to a file, and now with 'save-devices-state')

That is, 'migrate' does all three at once to an external file, 'savevm'
does all three at once to an internal qcow2 snapshot, and you are now
making it possible to do any one of the three independently to an
external file while the VM continues to run.

Is this something that libvirt should be exposing in the near future?

> +SQMP
> +save-devices-state
> +-------
> +
> +Save the state of all devices to file. The RAM and the block devices
> +of the VM are not saved by this command.
> +
> +Arguments:
> +
> +- "filename": the file to save the state of the devices to as binary
> +data. See save-devices-state.txt for a description of the binary format.
> +
> +Example:
> +
> +-> { "execute": "save-devices-state", "arguments": { "filename": "/tmp/save" } }

Can we at least reserve something for future extension to add things
like 'fd:name' to refer to a named fd received earlier via 'getfd'?  You
could do that by documenting up front that if "filename" does not start
with "/", then any pattern of letters followed by a ':' as the initial
pattern of the filename is an error (and you avoid the error by using
./foo:... or an absolute path).
Anthony Liguori - March 16, 2012, 3:58 p.m.
On 03/16/2012 10:49 AM, Eric Blake wrote:
> On 03/16/2012 06:13 AM, Stefano Stabellini wrote:
>> - add an "is_ram" flag to SaveStateEntry;
>>
>> - register_savevm_live sets is_ram for live_savevm devices;
>>
>> - introduce a "save-devices-state" QAPI command that can be used to save
>> the state of all devices, but not the RAM or the block devices of the
>> VM.
>>
>
>> +QEMU has code to load/save the state of the guest that it is running.
>> +These are two complementary operations.  Saving the state just does
>> +that, saves the state for each device that the guest is running.
>> +
>> +These operations are normally used with migration (see migration.txt),
>> +however it is also possible to save the state of all devices to file,
>> +without saving the RAM or the block devices of the VM.
>> +
>> +This operation is called "save-devices-state" (see QMP/qmp-commands.txt)
>
> Is there a complimentary load-devices-state?

Maybe we should call this xen-save-devices-state.

As far as I'm concerned, this is a Xen specific interface, not an interface for 
general consumption.

I would not expect libvirt to use this interface.  If libvirt wants an interface 
that only saves device state, I'd much rather do it properly through QMP such 
that what was returned was well structured and in JSON.

Regards,

Anthony Liguori

>
> Just to make sure I'm clear, there are three things to save before you
> have a complete picture of a running VM:
>
> disk state (can be saved with 'savevm' to internal qcow2 snapshots, or
> with 'transaction' and 'blockdev-snapshot-sync' by creating external
> snapshots, or by 'migrate' to a file)
>
> RAM state (can be saved with 'savevm' to internal qcow2 snapshot, or
> with 'migrate' to a file; it is also possible to start qemu with a
> command line parameter telling which backing file tracks RAM state)
>
> device state (can be saved with 'savevm' to internal qcow2 snapshot, or
> with 'migrate' to a file, and now with 'save-devices-state')
>
> That is, 'migrate' does all three at once to an external file, 'savevm'
> does all three at once to an internal qcow2 snapshot, and you are now
> making it possible to do any one of the three independently to an
> external file while the VM continues to run.
>
> Is this something that libvirt should be exposing in the near future?
>
>> +SQMP
>> +save-devices-state
>> +-------
>> +
>> +Save the state of all devices to file. The RAM and the block devices
>> +of the VM are not saved by this command.
>> +
>> +Arguments:
>> +
>> +- "filename": the file to save the state of the devices to as binary
>> +data. See save-devices-state.txt for a description of the binary format.
>> +
>> +Example:
>> +
>> +->  { "execute": "save-devices-state", "arguments": { "filename": "/tmp/save" } }
>
> Can we at least reserve something for future extension to add things
> like 'fd:name' to refer to a named fd received earlier via 'getfd'?  You
> could do that by documenting up front that if "filename" does not start
> with "/", then any pattern of letters followed by a ':' as the initial
> pattern of the filename is an error (and you avoid the error by using
> ./foo:... or an absolute path).
>
Eric Blake - March 16, 2012, 4:03 p.m.
On 03/16/2012 09:58 AM, Anthony Liguori wrote:

>>> +These operations are normally used with migration (see migration.txt),
>>> +however it is also possible to save the state of all devices to file,
>>> +without saving the RAM or the block devices of the VM.
>>> +
>>> +This operation is called "save-devices-state" (see
>>> QMP/qmp-commands.txt)
>>
>> Is there a complimentary load-devices-state?
> 
> Maybe we should call this xen-save-devices-state.
> 
> As far as I'm concerned, this is a Xen specific interface, not an
> interface for general consumption.

Fair enough - and renaming it would certainly help.

> 
> I would not expect libvirt to use this interface.

Good to know.  In that case, adding an fd: interface isn't a priority,
after all.
Stefano Stabellini - March 16, 2012, 4:13 p.m.
On Fri, 16 Mar 2012, Eric Blake wrote:
> On 03/16/2012 06:13 AM, Stefano Stabellini wrote:
> > - add an "is_ram" flag to SaveStateEntry;
> > 
> > - register_savevm_live sets is_ram for live_savevm devices;
> > 
> > - introduce a "save-devices-state" QAPI command that can be used to save
> > the state of all devices, but not the RAM or the block devices of the
> > VM.
> > 
> 
> > +QEMU has code to load/save the state of the guest that it is running.
> > +These are two complementary operations.  Saving the state just does
> > +that, saves the state for each device that the guest is running.
> > +
> > +These operations are normally used with migration (see migration.txt),
> > +however it is also possible to save the state of all devices to file,
> > +without saving the RAM or the block devices of the VM.
> > +
> > +This operation is called "save-devices-state" (see QMP/qmp-commands.txt)
> 
> Is there a complimentary load-devices-state?

The generic loadvm function can be used with the device state on Xen,
see below.


> Just to make sure I'm clear, there are three things to save before you
> have a complete picture of a running VM:
> 
> disk state (can be saved with 'savevm' to internal qcow2 snapshots, or
> with 'transaction' and 'blockdev-snapshot-sync' by creating external
> snapshots, or by 'migrate' to a file)
> 
> RAM state (can be saved with 'savevm' to internal qcow2 snapshot, or
> with 'migrate' to a file; it is also possible to start qemu with a
> command line parameter telling which backing file tracks RAM state)
> 
> device state (can be saved with 'savevm' to internal qcow2 snapshot, or
> with 'migrate' to a file, and now with 'save-devices-state')
> 
> That is, 'migrate' does all three at once to an external file, 'savevm'
> does all three at once to an internal qcow2 snapshot, and you are now
> making it possible to do any one of the three independently to an
> external file while the VM continues to run.
> 
> Is this something that libvirt should be exposing in the near future?

I don't think so. It is useful under Xen where the RAM state and the
disk state are saved elsewhere. Libvirt is going to be a consumer of
this interface but only through libxenlight.


> Can we at least reserve something for future extension to add things
> like 'fd:name' to refer to a named fd received earlier via 'getfd'?  You
> could do that by documenting up front that if "filename" does not start
> with "/", then any pattern of letters followed by a ':' as the initial
> pattern of the filename is an error (and you avoid the error by using
> ./foo:... or an absolute path).
 
Yes, that can be done.
Luiz Capitulino - March 16, 2012, 5:28 p.m.
On Fri, 16 Mar 2012 09:49:55 -0600
Eric Blake <eblake@redhat.com> wrote:

> On 03/16/2012 06:13 AM, Stefano Stabellini wrote:
> > - add an "is_ram" flag to SaveStateEntry;
> > 
> > - register_savevm_live sets is_ram for live_savevm devices;
> > 
> > - introduce a "save-devices-state" QAPI command that can be used to save
> > the state of all devices, but not the RAM or the block devices of the
> > VM.
> > 
> 
> > +QEMU has code to load/save the state of the guest that it is running.
> > +These are two complementary operations.  Saving the state just does
> > +that, saves the state for each device that the guest is running.
> > +
> > +These operations are normally used with migration (see migration.txt),
> > +however it is also possible to save the state of all devices to file,
> > +without saving the RAM or the block devices of the VM.
> > +
> > +This operation is called "save-devices-state" (see QMP/qmp-commands.txt)
> 
> Is there a complimentary load-devices-state?
> 
> Just to make sure I'm clear, there are three things to save before you
> have a complete picture of a running VM:
> 
> disk state (can be saved with 'savevm' to internal qcow2 snapshots, or
> with 'transaction' and 'blockdev-snapshot-sync' by creating external
> snapshots, or by 'migrate' to a file)
> 
> RAM state (can be saved with 'savevm' to internal qcow2 snapshot, or
> with 'migrate' to a file; it is also possible to start qemu with a
> command line parameter telling which backing file tracks RAM state)

The maybe-to-be-added 'dump' command also saves RAM state, but to elf file
format.

> 
> device state (can be saved with 'savevm' to internal qcow2 snapshot, or
> with 'migrate' to a file, and now with 'save-devices-state')
> 
> That is, 'migrate' does all three at once to an external file, 'savevm'
> does all three at once to an internal qcow2 snapshot, and you are now
> making it possible to do any one of the three independently to an
> external file while the VM continues to run.
> 
> Is this something that libvirt should be exposing in the near future?
> 
> > +SQMP
> > +save-devices-state
> > +-------
> > +
> > +Save the state of all devices to file. The RAM and the block devices
> > +of the VM are not saved by this command.
> > +
> > +Arguments:
> > +
> > +- "filename": the file to save the state of the devices to as binary
> > +data. See save-devices-state.txt for a description of the binary format.
> > +
> > +Example:
> > +
> > +-> { "execute": "save-devices-state", "arguments": { "filename": "/tmp/save" } }
> 
> Can we at least reserve something for future extension to add things
> like 'fd:name' to refer to a named fd received earlier via 'getfd'?  You
> could do that by documenting up front that if "filename" does not start
> with "/", then any pattern of letters followed by a ':' as the initial
> pattern of the filename is an error (and you avoid the error by using
> ./foo:... or an absolute path).
>
Stefano Stabellini - March 19, 2012, 11:48 a.m.
On Fri, 16 Mar 2012, Eric Blake wrote:
> On 03/16/2012 09:58 AM, Anthony Liguori wrote:
> 
> >>> +These operations are normally used with migration (see migration.txt),
> >>> +however it is also possible to save the state of all devices to file,
> >>> +without saving the RAM or the block devices of the VM.
> >>> +
> >>> +This operation is called "save-devices-state" (see
> >>> QMP/qmp-commands.txt)
> >>
> >> Is there a complimentary load-devices-state?
> > 
> > Maybe we should call this xen-save-devices-state.
> > 
> > As far as I'm concerned, this is a Xen specific interface, not an
> > interface for general consumption.
> 
> Fair enough - and renaming it would certainly help.
 
OK, I have renamed the command to xen-save-devices-state and reposted
the series.
Thanks for the feedback.

Patch

diff --git a/docs/save-devices-state.txt b/docs/save-devices-state.txt
new file mode 100644
index 0000000..c6b726c
--- /dev/null
+++ b/docs/save-devices-state.txt
@@ -0,0 +1,33 @@ 
+= Save Devices =
+
+QEMU has code to load/save the state of the guest that it is running.
+These are two complementary operations.  Saving the state just does
+that, saves the state for each device that the guest is running.
+
+These operations are normally used with migration (see migration.txt),
+however it is also possible to save the state of all devices to file,
+without saving the RAM or the block devices of the VM.
+
+This operation is called "save-devices-state" (see QMP/qmp-commands.txt)
+
+
+The binary format used in the file is the following:
+
+
+-------------------------------------------
+
+32 bit big endian: QEMU_VM_FILE_MAGIC
+32 bit big endian: QEMU_VM_FILE_VERSION
+
+for_each_device
+{
+    8 bit:              QEMU_VM_SECTION_FULL
+    32 bit big endian:  section_id
+    8 bit:              idstr (ID string) length
+    string:             idstr (ID string)
+    32 bit big endian:  instance_id
+    32 bit big endian:  version_id
+    buffer:             device specific data
+}
+
+8 bit: QEMU_VM_EOF
diff --git a/qapi-schema.json b/qapi-schema.json
index d0b6792..7dd0b74 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1593,3 +1593,21 @@ 
 { 'command': 'qom-list-types',
   'data': { '*implements': 'str', '*abstract': 'bool' },
   'returns': [ 'ObjectTypeInfo' ] }
+
+##
+# @save-devices-state:
+#
+# Save the state of all devices to file. The RAM and the block devices
+# of the VM are not saved by this command.
+#
+# @filename: the file to save the state of the devices to as binary
+# data. See save-devices-state.txt for a description of the binary format.
+#
+# Returns: Nothing on success
+#          If @filename cannot be opened, OpenFileFailed
+#          If an I/O error occurs while writing the file, IOError
+#
+# Since: 1.1
+##
+{ 'command': 'save-devices-state', 'data': {'filename': 'str'} }
+
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 705f704..8409d3f 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -444,6 +444,31 @@  Note: inject-nmi is only supported for x86 guest currently, it will
 EQMP
 
     {
+        .name       = "save-devices-state",
+        .args_type  = "filename:F",
+    .mhandler.cmd_new = qmp_marshal_input_save_devices_state,
+    },
+
+SQMP
+save-devices-state
+-------
+
+Save the state of all devices to file. The RAM and the block devices
+of the VM are not saved by this command.
+
+Arguments:
+
+- "filename": the file to save the state of the devices to as binary
+data. See save-devices-state.txt for a description of the binary format.
+
+Example:
+
+-> { "execute": "save-devices-state", "arguments": { "filename": "/tmp/save" } }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "migrate",
         .args_type  = "detach:-d,blk:-b,inc:-i,uri:s",
         .params     = "[-d] [-b] [-i] uri",
diff --git a/savevm.c b/savevm.c
index 80be1ff..07ded39 100644
--- a/savevm.c
+++ b/savevm.c
@@ -84,6 +84,7 @@ 
 #include "qemu-timer.h"
 #include "cpus.h"
 #include "memory.h"
+#include "qmp-commands.h"
 
 #define SELF_ANNOUNCE_ROUNDS 5
 
@@ -1177,6 +1178,7 @@  typedef struct SaveStateEntry {
     void *opaque;
     CompatEntry *compat;
     int no_migrate;
+    int is_ram;
 } SaveStateEntry;
 
 
@@ -1241,6 +1243,10 @@  int register_savevm_live(DeviceState *dev,
     se->opaque = opaque;
     se->vmsd = NULL;
     se->no_migrate = 0;
+    /* if this is a live_savem then set is_ram */
+    if (save_live_state != NULL) {
+        se->is_ram = 1;
+    }
 
     if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
         char *id = dev->parent_bus->info->get_dev_path(dev);
@@ -1728,6 +1734,45 @@  out:
     return ret;
 }
 
+static int qemu_save_device_state(QEMUFile *f)
+{
+    SaveStateEntry *se;
+
+    qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
+    qemu_put_be32(f, QEMU_VM_FILE_VERSION);
+
+    cpu_synchronize_all_states();
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        int len;
+
+        if (se->is_ram) {
+            continue;
+        }
+        if (se->save_state == NULL && se->vmsd == NULL) {
+            continue;
+        }
+
+        /* Section type */
+        qemu_put_byte(f, QEMU_VM_SECTION_FULL);
+        qemu_put_be32(f, se->section_id);
+
+        /* ID string */
+        len = strlen(se->idstr);
+        qemu_put_byte(f, len);
+        qemu_put_buffer(f, (uint8_t *)se->idstr, len);
+
+        qemu_put_be32(f, se->instance_id);
+        qemu_put_be32(f, se->version_id);
+
+        vmstate_save(f, se);
+    }
+
+    qemu_put_byte(f, QEMU_VM_EOF);
+
+    return qemu_file_get_error(f);
+}
+
 static SaveStateEntry *find_se(const char *idstr, int instance_id)
 {
     SaveStateEntry *se;
@@ -2109,6 +2154,32 @@  void do_savevm(Monitor *mon, const QDict *qdict)
         vm_start();
 }
 
+void qmp_save_devices_state(const char *filename, Error **errp)
+{
+    QEMUFile *f;
+    int saved_vm_running;
+    int ret;
+
+    saved_vm_running = runstate_is_running();
+    vm_stop(RUN_STATE_SAVE_VM);
+
+    f = qemu_fopen(filename, "wb");
+    if (!f) {
+        error_set(errp, QERR_OPEN_FILE_FAILED, filename);
+        goto the_end;
+    }
+    ret = qemu_save_device_state(f);
+    qemu_fclose(f);
+    if (ret < 0) {
+        error_set(errp, QERR_IO_ERROR);
+    }
+
+ the_end:
+    if (saved_vm_running)
+        vm_start();
+    return;
+}
+
 int load_vmstate(const char *name)
 {
     BlockDriverState *bs, *bs_vm_state;