diff mbox

[v4,2/6] Introduce "save_devices"

Message ID 1327496745-31260-2-git-send-email-stefano.stabellini@eu.citrix.com
State New
Headers show

Commit Message

Stefano Stabellini Jan. 25, 2012, 1:05 p.m. UTC
- add an "is_ram" flag to SaveStateEntry;

- add an "is_ram" parameter to register_savevm_live;

- introduce a "save_devices" monitor command that can be used to save
the state of non-ram devices.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 block-migration.c |    2 +-
 hmp-commands.hx   |   14 ++++++++++
 hw/hw.h           |    1 +
 qmp-commands.hx   |   17 ++++++++++++
 savevm.c          |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 sysemu.h          |    1 +
 vl.c              |    2 +-
 7 files changed, 106 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/block-migration.c b/block-migration.c
index 2b7edbc..424a87d 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -720,6 +720,6 @@  void blk_mig_init(void)
     QSIMPLEQ_INIT(&block_mig_state.bmds_list);
     QSIMPLEQ_INIT(&block_mig_state.blk_list);
 
-    register_savevm_live(NULL, "block", 0, 1, block_set_params,
+    register_savevm_live(NULL, "block", 0, 1, 0, block_set_params,
                          block_save_live, NULL, block_load, &block_mig_state);
 }
diff --git a/hmp-commands.hx b/hmp-commands.hx
index a586498..ba4c9d5 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -241,6 +241,20 @@  a snapshot with the same tag or ID, it is replaced. More info at
 ETEXI
 
     {
+        .name       = "save_devices",
+        .args_type  = "filename:F",
+        .params     = "filename",
+        .help       = "save the state of non-ram devices.",
+        .mhandler.cmd_new = do_save_device_state,
+    },
+
+STEXI
+@item save_devices @var{filename}
+@findex save_devices
+Save the state of non-ram devices.
+ETEXI
+
+    {
         .name       = "loadvm",
         .args_type  = "name:s",
         .params     = "tag|id",
diff --git a/hw/hw.h b/hw/hw.h
index 932014a..9d3d76d 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -263,6 +263,7 @@  int register_savevm_live(DeviceState *dev,
                          const char *idstr,
                          int instance_id,
                          int version_id,
+                         int is_ram,
                          SaveSetParamsHandler *set_params,
 			 SaveLiveStateHandler *save_live_state,
                          SaveStateHandler *save_state,
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 7e3f4b9..51f4436 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -429,6 +429,23 @@  Note: inject-nmi is only supported for x86 guest currently, it will
 EQMP
 
     {
+        .name       = "save_devices",
+        .args_type  = "filename:F",
+        .params     = "filename",
+        .help       = "save the state of non-ram devices.",
+        .user_print = monitor_user_noop,	
+    .mhandler.cmd_new = do_save_device_state,
+    },
+
+SQMP
+save_devices
+-------
+
+Save the state of non-ram devices.
+
+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..d0e62bb 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1177,6 +1177,7 @@  typedef struct SaveStateEntry {
     void *opaque;
     CompatEntry *compat;
     int no_migrate;
+    int is_ram;
 } SaveStateEntry;
 
 
@@ -1223,6 +1224,7 @@  int register_savevm_live(DeviceState *dev,
                          const char *idstr,
                          int instance_id,
                          int version_id,
+                         int is_ram,
                          SaveSetParamsHandler *set_params,
                          SaveLiveStateHandler *save_live_state,
                          SaveStateHandler *save_state,
@@ -1241,6 +1243,7 @@  int register_savevm_live(DeviceState *dev,
     se->opaque = opaque;
     se->vmsd = NULL;
     se->no_migrate = 0;
+    se->is_ram = is_ram;
 
     if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
         char *id = dev->parent_bus->info->get_dev_path(dev);
@@ -1277,7 +1280,7 @@  int register_savevm(DeviceState *dev,
                     LoadStateHandler *load_state,
                     void *opaque)
 {
-    return register_savevm_live(dev, idstr, instance_id, version_id,
+    return register_savevm_live(dev, idstr, instance_id, version_id, 0,
                                 NULL, NULL, save_state, load_state, opaque);
 }
 
@@ -1728,6 +1731,43 @@  out:
     return ret;
 }
 
+static int qemu_save_device_state(Monitor *mon, 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 +2149,36 @@  void do_savevm(Monitor *mon, const QDict *qdict)
         vm_start();
 }
 
+int do_save_device_state(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    int ret;
+    QEMUFile *f;
+    int saved_vm_running;
+    const char *filename = qdict_get_try_str(qdict, "filename");
+
+    saved_vm_running = runstate_is_running();
+    vm_stop(RUN_STATE_SAVE_VM);
+
+    f = qemu_fopen(filename, "wb");
+    if (!f) {
+        monitor_printf(mon, "Could not open VM state file\n");
+        ret = -1;
+        goto the_end;
+    }
+    ret = qemu_save_device_state(mon, f);
+    qemu_fclose(f);
+    if (ret < 0) {
+        monitor_printf(mon, "Error %d while writing VM\n", ret);
+        goto the_end;
+    }
+    ret = 0;
+
+ the_end:
+    if (saved_vm_running)
+        vm_start();
+    return ret;
+}
+
 int load_vmstate(const char *name)
 {
     BlockDriverState *bs, *bs_vm_state;
diff --git a/sysemu.h b/sysemu.h
index ddef2bb..4103b08 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -59,6 +59,7 @@  void qemu_remove_exit_notifier(Notifier *notify);
 void qemu_add_machine_init_done_notifier(Notifier *notify);
 
 void do_savevm(Monitor *mon, const QDict *qdict);
+int do_save_device_state(Monitor *mon, const QDict *qdict, QObject **ret_data);
 int load_vmstate(const char *name);
 void do_delvm(Monitor *mon, const QDict *qdict);
 void do_info_snapshots(Monitor *mon);
diff --git a/vl.c b/vl.c
index ba55b35..c3a155f 100644
--- a/vl.c
+++ b/vl.c
@@ -3270,7 +3270,7 @@  int main(int argc, char **argv, char **envp)
     default_drive(default_sdcard, snapshot, machine->use_scsi,
                   IF_SD, 0, SD_OPTS);
 
-    register_savevm_live(NULL, "ram", 0, 4, NULL, ram_save_live, NULL,
+    register_savevm_live(NULL, "ram", 0, 4, 1, NULL, ram_save_live, NULL,
                          ram_load, NULL);
 
     if (nb_numa_nodes > 0) {