Diff for /qemu/savevm.c between versions 1.1.1.6 and 1.1.1.9

version 1.1.1.6, 2018/04/24 17:34:11 version 1.1.1.9, 2018/04/24 18:33:41
Line 72 Line 72
   
 #include "qemu-common.h"  #include "qemu-common.h"
 #include "hw/hw.h"  #include "hw/hw.h"
   #include "hw/qdev.h"
 #include "net.h"  #include "net.h"
 #include "monitor.h"  #include "monitor.h"
 #include "sysemu.h"  #include "sysemu.h"
 #include "qemu-timer.h"  #include "qemu-timer.h"
 #include "qemu-char.h"  #include "qemu-char.h"
 #include "block.h"  
 #include "audio/audio.h"  #include "audio/audio.h"
 #include "migration.h"  #include "migration.h"
 #include "qemu_socket.h"  #include "qemu_socket.h"
 #include "qemu-queue.h"  #include "qemu-queue.h"
   
 /* point to the block driver where the snapshots are managed */  
 static BlockDriverState *bs_snapshots;  
   
 #define SELF_ANNOUNCE_ROUNDS 5  #define SELF_ANNOUNCE_ROUNDS 5
   
 #ifndef ETH_P_RARP  #ifndef ETH_P_RARP
 #define ETH_P_RARP 0x0835  #define ETH_P_RARP 0x8035
 #endif  #endif
 #define ARP_HTYPE_ETH 0x0001  #define ARP_HTYPE_ETH 0x0001
 #define ARP_PTYPE_IP 0x0800  #define ARP_PTYPE_IP 0x0800
Line 235  static int stdio_get_buffer(void *opaque Line 232  static int stdio_get_buffer(void *opaque
 static int stdio_pclose(void *opaque)  static int stdio_pclose(void *opaque)
 {  {
     QEMUFileStdio *s = opaque;      QEMUFileStdio *s = opaque;
     pclose(s->stdio_file);      int ret;
       ret = pclose(s->stdio_file);
     qemu_free(s);      qemu_free(s);
     return 0;      return ret;
 }  }
   
 static int stdio_fclose(void *opaque)  static int stdio_fclose(void *opaque)
Line 339  static int file_put_buffer(void *opaque, Line 337  static int file_put_buffer(void *opaque,
 {  {
     QEMUFileStdio *s = opaque;      QEMUFileStdio *s = opaque;
     fseek(s->stdio_file, pos, SEEK_SET);      fseek(s->stdio_file, pos, SEEK_SET);
     fwrite(buf, 1, size, s->stdio_file);      return fwrite(buf, 1, size, s->stdio_file);
     return size;  
 }  }
   
 static int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)  static int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
Line 357  QEMUFile *qemu_fopen(const char *filenam Line 354  QEMUFile *qemu_fopen(const char *filenam
     if (mode == NULL ||      if (mode == NULL ||
         (mode[0] != 'r' && mode[0] != 'w') ||          (mode[0] != 'r' && mode[0] != 'w') ||
         mode[1] != 'b' || mode[2] != 0) {          mode[1] != 'b' || mode[2] != 0) {
         fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");          fprintf(stderr, "qemu_fopen: Argument validity check failed\n");
         return NULL;          return NULL;
     }      }
   
Line 553  int qemu_get_buffer(QEMUFile *f, uint8_t Line 550  int qemu_get_buffer(QEMUFile *f, uint8_t
     return size1 - size;      return size1 - size;
 }  }
   
   static int qemu_peek_byte(QEMUFile *f)
   {
       if (f->is_write)
           abort();
   
       if (f->buf_index >= f->buf_size) {
           qemu_fill_buffer(f);
           if (f->buf_index >= f->buf_size)
               return 0;
       }
       return f->buf[f->buf_index];
   }
   
 int qemu_get_byte(QEMUFile *f)  int qemu_get_byte(QEMUFile *f)
 {  {
     if (f->is_write)      if (f->is_write)
Line 600  int qemu_file_rate_limit(QEMUFile *f) Line 610  int qemu_file_rate_limit(QEMUFile *f)
     return 0;      return 0;
 }  }
   
 size_t qemu_file_get_rate_limit(QEMUFile *f)  int64_t qemu_file_get_rate_limit(QEMUFile *f)
 {  {
     if (f->get_rate_limit)      if (f->get_rate_limit)
         return f->get_rate_limit(f->opaque);          return f->get_rate_limit(f->opaque);
Line 608  size_t qemu_file_get_rate_limit(QEMUFile Line 618  size_t qemu_file_get_rate_limit(QEMUFile
     return 0;      return 0;
 }  }
   
 size_t qemu_file_set_rate_limit(QEMUFile *f, size_t new_rate)  int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate)
 {  {
     /* any failed or completed migration keeps its state to allow probing of      /* any failed or completed migration keeps its state to allow probing of
      * migration data, but has no associated file anymore */       * migration data, but has no associated file anymore */
Line 664  uint64_t qemu_get_be64(QEMUFile *f) Line 674  uint64_t qemu_get_be64(QEMUFile *f)
     return v;      return v;
 }  }
   
   /* bool */
   
   static int get_bool(QEMUFile *f, void *pv, size_t size)
   {
       bool *v = pv;
       *v = qemu_get_byte(f);
       return 0;
   }
   
   static void put_bool(QEMUFile *f, void *pv, size_t size)
   {
       bool *v = pv;
       qemu_put_byte(f, *v);
   }
   
   const VMStateInfo vmstate_info_bool = {
       .name = "bool",
       .get  = get_bool,
       .put  = put_bool,
   };
   
 /* 8 bit int */  /* 8 bit int */
   
 static int get_int8(QEMUFile *f, void *pv, size_t size)  static int get_int8(QEMUFile *f, void *pv, size_t size)
Line 988  const VMStateInfo vmstate_info_unused_bu Line 1019  const VMStateInfo vmstate_info_unused_bu
     .put  = put_unused_buffer,      .put  = put_unused_buffer,
 };  };
   
   typedef struct CompatEntry {
       char idstr[256];
       int instance_id;
   } CompatEntry;
   
 typedef struct SaveStateEntry {  typedef struct SaveStateEntry {
     QTAILQ_ENTRY(SaveStateEntry) entry;      QTAILQ_ENTRY(SaveStateEntry) entry;
     char idstr[256];      char idstr[256];
     int instance_id;      int instance_id;
       int alias_id;
     int version_id;      int version_id;
     int section_id;      int section_id;
     SaveSetParamsHandler *set_params;      SaveSetParamsHandler *set_params;
Line 1000  typedef struct SaveStateEntry { Line 1037  typedef struct SaveStateEntry {
     LoadStateHandler *load_state;      LoadStateHandler *load_state;
     const VMStateDescription *vmsd;      const VMStateDescription *vmsd;
     void *opaque;      void *opaque;
       CompatEntry *compat;
       int no_migrate;
 } SaveStateEntry;  } SaveStateEntry;
   
   
Line 1021  static int calculate_new_instance_id(con Line 1060  static int calculate_new_instance_id(con
     return instance_id;      return instance_id;
 }  }
   
   static int calculate_compat_instance_id(const char *idstr)
   {
       SaveStateEntry *se;
       int instance_id = 0;
   
       QTAILQ_FOREACH(se, &savevm_handlers, entry) {
           if (!se->compat)
               continue;
   
           if (strcmp(idstr, se->compat->idstr) == 0
               && instance_id <= se->compat->instance_id) {
               instance_id = se->compat->instance_id + 1;
           }
       }
       return instance_id;
   }
   
 /* TODO: Individual devices generally have very little idea about the rest  /* TODO: Individual devices generally have very little idea about the rest
    of the system, so instance_id should be removed/replaced.     of the system, so instance_id should be removed/replaced.
    Meanwhile pass -1 as instance_id if you do not already have a clearly     Meanwhile pass -1 as instance_id if you do not already have a clearly
    distinguishing id for all instances of your device class. */     distinguishing id for all instances of your device class. */
 int register_savevm_live(const char *idstr,  int register_savevm_live(DeviceState *dev,
                            const char *idstr,
                          int instance_id,                           int instance_id,
                          int version_id,                           int version_id,
                          SaveSetParamsHandler *set_params,                           SaveSetParamsHandler *set_params,
Line 1037  int register_savevm_live(const char *ids Line 1094  int register_savevm_live(const char *ids
     SaveStateEntry *se;      SaveStateEntry *se;
   
     se = qemu_mallocz(sizeof(SaveStateEntry));      se = qemu_mallocz(sizeof(SaveStateEntry));
     pstrcpy(se->idstr, sizeof(se->idstr), idstr);  
     se->version_id = version_id;      se->version_id = version_id;
     se->section_id = global_section_id++;      se->section_id = global_section_id++;
     se->set_params = set_params;      se->set_params = set_params;
Line 1046  int register_savevm_live(const char *ids Line 1102  int register_savevm_live(const char *ids
     se->load_state = load_state;      se->load_state = load_state;
     se->opaque = opaque;      se->opaque = opaque;
     se->vmsd = NULL;      se->vmsd = NULL;
       se->no_migrate = 0;
   
       if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
           char *id = dev->parent_bus->info->get_dev_path(dev);
           if (id) {
               pstrcpy(se->idstr, sizeof(se->idstr), id);
               pstrcat(se->idstr, sizeof(se->idstr), "/");
               qemu_free(id);
   
               se->compat = qemu_mallocz(sizeof(CompatEntry));
               pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), idstr);
               se->compat->instance_id = instance_id == -1 ?
                            calculate_compat_instance_id(idstr) : instance_id;
               instance_id = -1;
           }
       }
       pstrcat(se->idstr, sizeof(se->idstr), idstr);
   
     if (instance_id == -1) {      if (instance_id == -1) {
         se->instance_id = calculate_new_instance_id(idstr);          se->instance_id = calculate_new_instance_id(se->idstr);
     } else {      } else {
         se->instance_id = instance_id;          se->instance_id = instance_id;
     }      }
       assert(!se->compat || se->instance_id == 0);
     /* add at the end of list */      /* add at the end of list */
     QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);      QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
     return 0;      return 0;
 }  }
   
 int register_savevm(const char *idstr,  int register_savevm(DeviceState *dev,
                       const char *idstr,
                     int instance_id,                      int instance_id,
                     int version_id,                      int version_id,
                     SaveStateHandler *save_state,                      SaveStateHandler *save_state,
                     LoadStateHandler *load_state,                      LoadStateHandler *load_state,
                     void *opaque)                      void *opaque)
 {  {
     return register_savevm_live(idstr, instance_id, version_id,      return register_savevm_live(dev, idstr, instance_id, version_id,
                                 NULL, NULL, save_state, load_state, opaque);                                  NULL, NULL, save_state, load_state, opaque);
 }  }
   
 void unregister_savevm(const char *idstr, void *opaque)  void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
 {  {
     SaveStateEntry *se, *new_se;      SaveStateEntry *se, *new_se;
       char id[256] = "";
   
       if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
           char *path = dev->parent_bus->info->get_dev_path(dev);
           if (path) {
               pstrcpy(id, sizeof(id), path);
               pstrcat(id, sizeof(id), "/");
               qemu_free(path);
           }
       }
       pstrcat(id, sizeof(id), idstr);
   
     QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {      QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
         if (strcmp(se->idstr, idstr) == 0 && se->opaque == opaque) {          if (strcmp(se->idstr, id) == 0 && se->opaque == opaque) {
             QTAILQ_REMOVE(&savevm_handlers, se, entry);              QTAILQ_REMOVE(&savevm_handlers, se, entry);
               if (se->compat) {
                   qemu_free(se->compat);
               }
             qemu_free(se);              qemu_free(se);
         }          }
     }      }
 }  }
   
 int vmstate_register(int instance_id, const VMStateDescription *vmsd,  /* mark a device as not to be migrated, that is the device should be
                      void *opaque)     unplugged before migration */
   void register_device_unmigratable(DeviceState *dev, const char *idstr,
                                                               void *opaque)
 {  {
     SaveStateEntry *se;      SaveStateEntry *se;
       char id[256] = "";
   
       if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
           char *path = dev->parent_bus->info->get_dev_path(dev);
           if (path) {
               pstrcpy(id, sizeof(id), path);
               pstrcat(id, sizeof(id), "/");
               qemu_free(path);
           }
       }
       pstrcat(id, sizeof(id), idstr);
   
       QTAILQ_FOREACH(se, &savevm_handlers, entry) {
           if (strcmp(se->idstr, id) == 0 && se->opaque == opaque) {
               se->no_migrate = 1;
           }
       }
   }
   
   int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
                                      const VMStateDescription *vmsd,
                                      void *opaque, int alias_id,
                                      int required_for_version)
   {
       SaveStateEntry *se;
   
       /* If this triggers, alias support can be dropped for the vmsd. */
       assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id);
   
     se = qemu_mallocz(sizeof(SaveStateEntry));      se = qemu_mallocz(sizeof(SaveStateEntry));
     pstrcpy(se->idstr, sizeof(se->idstr), vmsd->name);  
     se->version_id = vmsd->version_id;      se->version_id = vmsd->version_id;
     se->section_id = global_section_id++;      se->section_id = global_section_id++;
     se->save_live_state = NULL;      se->save_live_state = NULL;
Line 1094  int vmstate_register(int instance_id, co Line 1212  int vmstate_register(int instance_id, co
     se->load_state = NULL;      se->load_state = NULL;
     se->opaque = opaque;      se->opaque = opaque;
     se->vmsd = vmsd;      se->vmsd = vmsd;
       se->alias_id = alias_id;
   
       if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
           char *id = dev->parent_bus->info->get_dev_path(dev);
           if (id) {
               pstrcpy(se->idstr, sizeof(se->idstr), id);
               pstrcat(se->idstr, sizeof(se->idstr), "/");
               qemu_free(id);
   
               se->compat = qemu_mallocz(sizeof(CompatEntry));
               pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), vmsd->name);
               se->compat->instance_id = instance_id == -1 ?
                            calculate_compat_instance_id(vmsd->name) : instance_id;
               instance_id = -1;
           }
       }
       pstrcat(se->idstr, sizeof(se->idstr), vmsd->name);
   
     if (instance_id == -1) {      if (instance_id == -1) {
         se->instance_id = calculate_new_instance_id(vmsd->name);          se->instance_id = calculate_new_instance_id(se->idstr);
     } else {      } else {
         se->instance_id = instance_id;          se->instance_id = instance_id;
     }      }
       assert(!se->compat || se->instance_id == 0);
     /* add at the end of list */      /* add at the end of list */
     QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);      QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
     return 0;      return 0;
 }  }
   
 void vmstate_unregister(const VMStateDescription *vmsd, void *opaque)  int vmstate_register(DeviceState *dev, int instance_id,
                        const VMStateDescription *vmsd, void *opaque)
   {
       return vmstate_register_with_alias_id(dev, instance_id, vmsd,
                                             opaque, -1, 0);
   }
   
   void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
                           void *opaque)
 {  {
     SaveStateEntry *se, *new_se;      SaveStateEntry *se, *new_se;
   
     QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {      QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
         if (se->vmsd == vmsd && se->opaque == opaque) {          if (se->vmsd == vmsd && se->opaque == opaque) {
             QTAILQ_REMOVE(&savevm_handlers, se, entry);              QTAILQ_REMOVE(&savevm_handlers, se, entry);
               if (se->compat) {
                   qemu_free(se->compat);
               }
             qemu_free(se);              qemu_free(se);
         }          }
     }      }
 }  }
   
   static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
                                       void *opaque);
   static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
                                      void *opaque);
   
 int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,  int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                        void *opaque, int version_id)                         void *opaque, int version_id)
 {  {
     VMStateField *field = vmsd->fields;      VMStateField *field = vmsd->fields;
       int ret;
   
     if (version_id > vmsd->version_id) {      if (version_id > vmsd->version_id) {
         return -EINVAL;          return -EINVAL;
Line 1142  int vmstate_load_state(QEMUFile *f, cons Line 1295  int vmstate_load_state(QEMUFile *f, cons
             (!field->field_exists &&              (!field->field_exists &&
              field->version_id <= version_id)) {               field->version_id <= version_id)) {
             void *base_addr = opaque + field->offset;              void *base_addr = opaque + field->offset;
             int ret, i, n_elems = 1;              int i, n_elems = 1;
             int size = field->size;              int size = field->size;
   
             if (field->flags & VMS_VBUFFER) {              if (field->flags & VMS_VBUFFER) {
Line 1180  int vmstate_load_state(QEMUFile *f, cons Line 1333  int vmstate_load_state(QEMUFile *f, cons
         }          }
         field++;          field++;
     }      }
       ret = vmstate_subsection_load(f, vmsd, opaque);
       if (ret != 0) {
           return ret;
       }
     if (vmsd->post_load) {      if (vmsd->post_load) {
         return vmsd->post_load(opaque, version_id);          return vmsd->post_load(opaque, version_id);
     }      }
Line 1232  void vmstate_save_state(QEMUFile *f, con Line 1389  void vmstate_save_state(QEMUFile *f, con
         }          }
         field++;          field++;
     }      }
     if (vmsd->post_save) {      vmstate_subsection_save(f, vmsd, opaque);
         vmsd->post_save(opaque);  
     }  
 }  }
   
 static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)  static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
Line 1263  static void vmstate_save(QEMUFile *f, Sa Line 1418  static void vmstate_save(QEMUFile *f, Sa
 #define QEMU_VM_SECTION_PART         0x02  #define QEMU_VM_SECTION_PART         0x02
 #define QEMU_VM_SECTION_END          0x03  #define QEMU_VM_SECTION_END          0x03
 #define QEMU_VM_SECTION_FULL         0x04  #define QEMU_VM_SECTION_FULL         0x04
   #define QEMU_VM_SUBSECTION           0x05
   
   bool qemu_savevm_state_blocked(Monitor *mon)
   {
       SaveStateEntry *se;
   
       QTAILQ_FOREACH(se, &savevm_handlers, entry) {
           if (se->no_migrate) {
               monitor_printf(mon, "state blocked by non-migratable device '%s'\n",
                              se->idstr);
               return true;
           }
       }
       return false;
   }
   
 int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,  int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
                             int shared)                              int shared)
Line 1346  int qemu_savevm_state_complete(Monitor * Line 1516  int qemu_savevm_state_complete(Monitor *
 {  {
     SaveStateEntry *se;      SaveStateEntry *se;
   
       cpu_synchronize_all_states();
   
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {      QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         if (se->save_live_state == NULL)          if (se->save_live_state == NULL)
             continue;              continue;
Line 1405  static int qemu_savevm_state(Monitor *mo Line 1577  static int qemu_savevm_state(Monitor *mo
     saved_vm_running = vm_running;      saved_vm_running = vm_running;
     vm_stop(0);      vm_stop(0);
   
     bdrv_flush_all();      if (qemu_savevm_state_blocked(mon)) {
           ret = -EINVAL;
           goto out;
       }
   
     ret = qemu_savevm_state_begin(mon, f, 0, 0);      ret = qemu_savevm_state_begin(mon, f, 0, 0);
     if (ret < 0)      if (ret < 0)
Line 1435  static SaveStateEntry *find_se(const cha Line 1610  static SaveStateEntry *find_se(const cha
   
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {      QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         if (!strcmp(se->idstr, idstr) &&          if (!strcmp(se->idstr, idstr) &&
             instance_id == se->instance_id)              (instance_id == se->instance_id ||
                instance_id == se->alias_id))
             return se;              return se;
           /* Migrating from an older version? */
           if (strstr(se->idstr, idstr) && se->compat) {
               if (!strcmp(se->compat->idstr, idstr) &&
                   (instance_id == se->compat->instance_id ||
                    instance_id == se->alias_id))
                   return se;
           }
       }
       return NULL;
   }
   
   static const VMStateDescription *vmstate_get_subsection(const VMStateSubsection *sub, char *idstr)
   {
       while(sub && sub->needed) {
           if (strcmp(idstr, sub->vmsd->name) == 0) {
               return sub->vmsd;
           }
           sub++;
     }      }
     return NULL;      return NULL;
 }  }
   
   static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
                                      void *opaque)
   {
       const VMStateSubsection *sub = vmsd->subsections;
   
       if (!sub || !sub->needed) {
           return 0;
       }
   
       while (qemu_peek_byte(f) == QEMU_VM_SUBSECTION) {
           char idstr[256];
           int ret;
           uint8_t version_id, len;
           const VMStateDescription *sub_vmsd;
   
           qemu_get_byte(f); /* subsection */
           len = qemu_get_byte(f);
           qemu_get_buffer(f, (uint8_t *)idstr, len);
           idstr[len] = 0;
           version_id = qemu_get_be32(f);
   
           sub_vmsd = vmstate_get_subsection(sub, idstr);
           if (sub_vmsd == NULL) {
               return -ENOENT;
           }
           assert(!sub_vmsd->subsections);
           ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
           if (ret) {
               return ret;
           }
       }
       return 0;
   }
   
   static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
                                       void *opaque)
   {
       const VMStateSubsection *sub = vmsd->subsections;
   
       while (sub && sub->needed) {
           if (sub->needed(opaque)) {
               const VMStateDescription *vmsd = sub->vmsd;
               uint8_t len;
   
               qemu_put_byte(f, QEMU_VM_SUBSECTION);
               len = strlen(vmsd->name);
               qemu_put_byte(f, len);
               qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
               qemu_put_be32(f, vmsd->version_id);
               assert(!vmsd->subsections);
               vmstate_save_state(f, vmsd, opaque);
           }
           sub++;
       }
   }
   
 typedef struct LoadStateEntry {  typedef struct LoadStateEntry {
     QLIST_ENTRY(LoadStateEntry) entry;      QLIST_ENTRY(LoadStateEntry) entry;
     SaveStateEntry *se;      SaveStateEntry *se;
Line 1457  int qemu_loadvm_state(QEMUFile *f) Line 1707  int qemu_loadvm_state(QEMUFile *f)
     unsigned int v;      unsigned int v;
     int ret;      int ret;
   
       if (qemu_savevm_state_blocked(default_mon)) {
           return -EINVAL;
       }
   
     v = qemu_get_be32(f);      v = qemu_get_be32(f);
     if (v != QEMU_VM_FILE_MAGIC)      if (v != QEMU_VM_FILE_MAGIC)
         return -EINVAL;          return -EINVAL;
Line 1546  int qemu_loadvm_state(QEMUFile *f) Line 1800  int qemu_loadvm_state(QEMUFile *f)
         }          }
     }      }
   
       cpu_synchronize_all_post_init();
   
     ret = 0;      ret = 0;
   
 out:  out:
Line 1560  out: Line 1816  out:
     return ret;      return ret;
 }  }
   
 /* device can contain snapshots */  
 static int bdrv_can_snapshot(BlockDriverState *bs)  
 {  
     return (bs &&  
             !bdrv_is_removable(bs) &&  
             !bdrv_is_read_only(bs));  
 }  
   
 /* device must be snapshots in order to have a reliable snapshot */  
 static int bdrv_has_snapshot(BlockDriverState *bs)  
 {  
     return (bs &&  
             !bdrv_is_removable(bs) &&  
             !bdrv_is_read_only(bs));  
 }  
   
 static BlockDriverState *get_bs_snapshots(void)  
 {  
     BlockDriverState *bs;  
     DriveInfo *dinfo;  
   
     if (bs_snapshots)  
         return bs_snapshots;  
     QTAILQ_FOREACH(dinfo, &drives, next) {  
         bs = dinfo->bdrv;  
         if (bdrv_can_snapshot(bs))  
             goto ok;  
     }  
     return NULL;  
  ok:  
     bs_snapshots = bs;  
     return bs;  
 }  
   
 static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,  static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
                               const char *name)                                const char *name)
 {  {
Line 1622  static int bdrv_snapshot_find(BlockDrive Line 1844  static int bdrv_snapshot_find(BlockDrive
 static int del_existing_snapshots(Monitor *mon, const char *name)  static int del_existing_snapshots(Monitor *mon, const char *name)
 {  {
     BlockDriverState *bs;      BlockDriverState *bs;
     DriveInfo *dinfo;  
     QEMUSnapshotInfo sn1, *snapshot = &sn1;      QEMUSnapshotInfo sn1, *snapshot = &sn1;
     int ret;      int ret;
   
     QTAILQ_FOREACH(dinfo, &drives, next) {      bs = NULL;
         bs = dinfo->bdrv;      while ((bs = bdrv_next(bs))) {
         if (bdrv_can_snapshot(bs) &&          if (bdrv_can_snapshot(bs) &&
             bdrv_snapshot_find(bs, snapshot, name) >= 0)              bdrv_snapshot_find(bs, snapshot, name) >= 0)
         {          {
Line 1646  static int del_existing_snapshots(Monito Line 1867  static int del_existing_snapshots(Monito
   
 void do_savevm(Monitor *mon, const QDict *qdict)  void do_savevm(Monitor *mon, const QDict *qdict)
 {  {
     DriveInfo *dinfo;  
     BlockDriverState *bs, *bs1;      BlockDriverState *bs, *bs1;
     QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;      QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
     int ret;      int ret;
Line 1655  void do_savevm(Monitor *mon, const QDict Line 1875  void do_savevm(Monitor *mon, const QDict
     uint32_t vm_state_size;      uint32_t vm_state_size;
 #ifdef _WIN32  #ifdef _WIN32
     struct _timeb tb;      struct _timeb tb;
       struct tm *ptm;
 #else  #else
     struct timeval tv;      struct timeval tv;
       struct tm tm;
 #endif  #endif
     const char *name = qdict_get_try_str(qdict, "name");      const char *name = qdict_get_try_str(qdict, "name");
   
     bs = get_bs_snapshots();      /* Verify if there is a device that doesn't support snapshots and is writable */
       bs = NULL;
       while ((bs = bdrv_next(bs))) {
   
           if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
               continue;
           }
   
           if (!bdrv_can_snapshot(bs)) {
               monitor_printf(mon, "Device '%s' is writable but does not support snapshots.\n",
                                  bdrv_get_device_name(bs));
               return;
           }
       }
   
       bs = bdrv_snapshots();
     if (!bs) {      if (!bs) {
         monitor_printf(mon, "No block device can accept snapshots\n");          monitor_printf(mon, "No block device can accept snapshots\n");
         return;          return;
     }      }
   
     /* ??? Should this occur after vm_stop?  */  
     qemu_aio_flush();  
   
     saved_vm_running = vm_running;      saved_vm_running = vm_running;
     vm_stop(0);      vm_stop(0);
   
     memset(sn, 0, sizeof(*sn));      memset(sn, 0, sizeof(*sn));
     if (name) {  
         ret = bdrv_snapshot_find(bs, old_sn, name);  
         if (ret >= 0) {  
             pstrcpy(sn->name, sizeof(sn->name), old_sn->name);  
             pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);  
         } else {  
             pstrcpy(sn->name, sizeof(sn->name), name);  
         }  
     }  
   
     /* fill auxiliary fields */      /* fill auxiliary fields */
 #ifdef _WIN32  #ifdef _WIN32
Line 1695  void do_savevm(Monitor *mon, const QDict Line 1920  void do_savevm(Monitor *mon, const QDict
 #endif  #endif
     sn->vm_clock_nsec = qemu_get_clock(vm_clock);      sn->vm_clock_nsec = qemu_get_clock(vm_clock);
   
       if (name) {
           ret = bdrv_snapshot_find(bs, old_sn, name);
           if (ret >= 0) {
               pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
               pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
           } else {
               pstrcpy(sn->name, sizeof(sn->name), name);
           }
       } else {
   #ifdef _WIN32
           ptm = localtime(&tb.time);
           strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", ptm);
   #else
           /* cast below needed for OpenBSD where tv_sec is still 'long' */
           localtime_r((const time_t *)&tv.tv_sec, &tm);
           strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", &tm);
   #endif
       }
   
     /* Delete old snapshots of the same name */      /* Delete old snapshots of the same name */
     if (del_existing_snapshots(mon, name) < 0) {      if (name && del_existing_snapshots(mon, name) < 0) {
         goto the_end;          goto the_end;
     }      }
   
Line 1716  void do_savevm(Monitor *mon, const QDict Line 1960  void do_savevm(Monitor *mon, const QDict
   
     /* create the snapshots */      /* create the snapshots */
   
     QTAILQ_FOREACH(dinfo, &drives, next) {      bs1 = NULL;
         bs1 = dinfo->bdrv;      while ((bs1 = bdrv_next(bs1))) {
         if (bdrv_has_snapshot(bs1)) {          if (bdrv_can_snapshot(bs1)) {
             /* Write VM state size only to the image that contains the state */              /* Write VM state size only to the image that contains the state */
             sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);              sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
             ret = bdrv_snapshot_create(bs1, sn);              ret = bdrv_snapshot_create(bs1, sn);
Line 1734  void do_savevm(Monitor *mon, const QDict Line 1978  void do_savevm(Monitor *mon, const QDict
         vm_start();          vm_start();
 }  }
   
 int load_vmstate(Monitor *mon, const char *name)  int load_vmstate(const char *name)
 {  {
     DriveInfo *dinfo;      BlockDriverState *bs, *bs_vm_state;
     BlockDriverState *bs, *bs1;  
     QEMUSnapshotInfo sn;      QEMUSnapshotInfo sn;
     QEMUFile *f;      QEMUFile *f;
     int ret;      int ret;
   
     bs = get_bs_snapshots();      bs_vm_state = bdrv_snapshots();
     if (!bs) {      if (!bs_vm_state) {
         monitor_printf(mon, "No block device supports snapshots\n");          error_report("No block device supports snapshots");
           return -ENOTSUP;
       }
   
       /* Don't even try to load empty VM states */
       ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
       if (ret < 0) {
           return ret;
       } else if (sn.vm_state_size == 0) {
         return -EINVAL;          return -EINVAL;
     }      }
   
       /* Verify if there is any device that doesn't support snapshots and is
       writable and check if the requested snapshot is available too. */
       bs = NULL;
       while ((bs = bdrv_next(bs))) {
   
           if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
               continue;
           }
   
           if (!bdrv_can_snapshot(bs)) {
               error_report("Device '%s' is writable but does not support snapshots.",
                                  bdrv_get_device_name(bs));
               return -ENOTSUP;
           }
   
           ret = bdrv_snapshot_find(bs, &sn, name);
           if (ret < 0) {
               error_report("Device '%s' does not have the requested snapshot '%s'",
                              bdrv_get_device_name(bs), name);
               return ret;
           }
       }
   
     /* Flush all IO requests so they don't interfere with the new state.  */      /* Flush all IO requests so they don't interfere with the new state.  */
     qemu_aio_flush();      qemu_aio_flush();
   
     QTAILQ_FOREACH(dinfo, &drives, next) {      bs = NULL;
         bs1 = dinfo->bdrv;      while ((bs = bdrv_next(bs))) {
         if (bdrv_has_snapshot(bs1)) {          if (bdrv_can_snapshot(bs)) {
             ret = bdrv_snapshot_goto(bs1, name);              ret = bdrv_snapshot_goto(bs, name);
             if (ret < 0) {              if (ret < 0) {
                 if (bs != bs1)                  error_report("Error %d while activating snapshot '%s' on '%s'",
                     monitor_printf(mon, "Warning: ");                               ret, name, bdrv_get_device_name(bs));
                 switch(ret) {                  return ret;
                 case -ENOTSUP:  
                     monitor_printf(mon,  
                                    "Snapshots not supported on device '%s'\n",  
                                    bdrv_get_device_name(bs1));  
                     break;  
                 case -ENOENT:  
                     monitor_printf(mon, "Could not find snapshot '%s' on "  
                                    "device '%s'\n",  
                                    name, bdrv_get_device_name(bs1));  
                     break;  
                 default:  
                     monitor_printf(mon, "Error %d while activating snapshot on"  
                                    " '%s'\n", ret, bdrv_get_device_name(bs1));  
                     break;  
                 }  
                 /* fatal on snapshot block device */  
                 if (bs == bs1)  
                     return 0;  
             }              }
         }          }
     }      }
   
     /* Don't even try to load empty VM states */  
     ret = bdrv_snapshot_find(bs, &sn, name);  
     if ((ret >= 0) && (sn.vm_state_size == 0))  
         return -EINVAL;  
   
     /* restore the VM state */      /* restore the VM state */
     f = qemu_fopen_bdrv(bs, 0);      f = qemu_fopen_bdrv(bs_vm_state, 0);
     if (!f) {      if (!f) {
         monitor_printf(mon, "Could not open VM state file\n");          error_report("Could not open VM state file");
         return -EINVAL;          return -EINVAL;
     }      }
   
     ret = qemu_loadvm_state(f);      ret = qemu_loadvm_state(f);
   
     qemu_fclose(f);      qemu_fclose(f);
     if (ret < 0) {      if (ret < 0) {
         monitor_printf(mon, "Error %d while loading VM state\n", ret);          error_report("Error %d while loading VM state", ret);
         return ret;          return ret;
     }      }
   
     return 0;      return 0;
 }  }
   
 void do_delvm(Monitor *mon, const QDict *qdict)  void do_delvm(Monitor *mon, const QDict *qdict)
 {  {
     DriveInfo *dinfo;  
     BlockDriverState *bs, *bs1;      BlockDriverState *bs, *bs1;
     int ret;      int ret;
     const char *name = qdict_get_str(qdict, "name");      const char *name = qdict_get_str(qdict, "name");
   
     bs = get_bs_snapshots();      bs = bdrv_snapshots();
     if (!bs) {      if (!bs) {
         monitor_printf(mon, "No block device supports snapshots\n");          monitor_printf(mon, "No block device supports snapshots\n");
         return;          return;
     }      }
   
     QTAILQ_FOREACH(dinfo, &drives, next) {      bs1 = NULL;
         bs1 = dinfo->bdrv;      while ((bs1 = bdrv_next(bs1))) {
         if (bdrv_has_snapshot(bs1)) {          if (bdrv_can_snapshot(bs1)) {
             ret = bdrv_snapshot_delete(bs1, name);              ret = bdrv_snapshot_delete(bs1, name);
             if (ret < 0) {              if (ret < 0) {
                 if (ret == -ENOTSUP)                  if (ret == -ENOTSUP)
Line 1833  void do_delvm(Monitor *mon, const QDict  Line 2086  void do_delvm(Monitor *mon, const QDict 
   
 void do_info_snapshots(Monitor *mon)  void do_info_snapshots(Monitor *mon)
 {  {
     DriveInfo *dinfo;  
     BlockDriverState *bs, *bs1;      BlockDriverState *bs, *bs1;
     QEMUSnapshotInfo *sn_tab, *sn;      QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s;
     int nb_sns, i;      int nb_sns, i, ret, available;
       int total;
       int *available_snapshots;
     char buf[256];      char buf[256];
   
     bs = get_bs_snapshots();      bs = bdrv_snapshots();
     if (!bs) {      if (!bs) {
         monitor_printf(mon, "No available block device supports snapshots\n");          monitor_printf(mon, "No available block device supports snapshots\n");
         return;          return;
     }      }
     monitor_printf(mon, "Snapshot devices:");  
     QTAILQ_FOREACH(dinfo, &drives, next) {  
         bs1 = dinfo->bdrv;  
         if (bdrv_has_snapshot(bs1)) {  
             if (bs == bs1)  
                 monitor_printf(mon, " %s", bdrv_get_device_name(bs1));  
         }  
     }  
     monitor_printf(mon, "\n");  
   
     nb_sns = bdrv_snapshot_list(bs, &sn_tab);      nb_sns = bdrv_snapshot_list(bs, &sn_tab);
     if (nb_sns < 0) {      if (nb_sns < 0) {
         monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);          monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
         return;          return;
     }      }
     monitor_printf(mon, "Snapshot list (from %s):\n",  
                    bdrv_get_device_name(bs));      if (nb_sns == 0) {
     monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));          monitor_printf(mon, "There is no snapshot available.\n");
     for(i = 0; i < nb_sns; i++) {          return;
       }
   
       available_snapshots = qemu_mallocz(sizeof(int) * nb_sns);
       total = 0;
       for (i = 0; i < nb_sns; i++) {
         sn = &sn_tab[i];          sn = &sn_tab[i];
         monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));          available = 1;
           bs1 = NULL;
   
           while ((bs1 = bdrv_next(bs1))) {
               if (bdrv_can_snapshot(bs1) && bs1 != bs) {
                   ret = bdrv_snapshot_find(bs1, sn_info, sn->id_str);
                   if (ret < 0) {
                       available = 0;
                       break;
                   }
               }
           }
   
           if (available) {
               available_snapshots[total] = i;
               total++;
           }
     }      }
   
       if (total > 0) {
           monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
           for (i = 0; i < total; i++) {
               sn = &sn_tab[available_snapshots[i]];
               monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
           }
       } else {
           monitor_printf(mon, "There is no suitable snapshot available\n");
       }
   
     qemu_free(sn_tab);      qemu_free(sn_tab);
       qemu_free(available_snapshots);
   
 }  }

Removed from v.1.1.1.6  
changed lines
  Added in v.1.1.1.9


unix.superglobalmegacorp.com