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

version 1.1.1.5, 2018/04/24 17:20:36 version 1.1.1.6, 2018/04/24 17:34:11
Line 29 Line 29
 #include <sys/time.h>  #include <sys/time.h>
 #include <zlib.h>  #include <zlib.h>
   
 /* Needed early for HOST_BSD etc. */  /* Needed early for CONFIG_BSD etc. */
 #include "config-host.h"  #include "config-host.h"
   
 #ifndef _WIN32  #ifndef _WIN32
Line 42 Line 42
 #include <sys/socket.h>  #include <sys/socket.h>
 #include <netinet/in.h>  #include <netinet/in.h>
 #include <net/if.h>  #include <net/if.h>
 #if defined(__NetBSD__)  
 #include <net/if_tap.h>  
 #endif  
 #ifdef __linux__  
 #include <linux/if_tun.h>  
 #endif  
 #include <arpa/inet.h>  #include <arpa/inet.h>
 #include <dirent.h>  #include <dirent.h>
 #include <netdb.h>  #include <netdb.h>
 #include <sys/select.h>  #include <sys/select.h>
 #ifdef HOST_BSD  #ifdef CONFIG_BSD
 #include <sys/stat.h>  #include <sys/stat.h>
 #if defined(__FreeBSD__) || defined(__DragonFly__)  #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 #include <libutil.h>  #include <libutil.h>
 #else  #else
 #include <util.h>  #include <util.h>
 #endif  #endif
 #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)  
 #include <freebsd/stdlib.h>  
 #else  
 #ifdef __linux__  #ifdef __linux__
 #include <pty.h>  #include <pty.h>
 #include <malloc.h>  #include <malloc.h>
Line 90 Line 81
 #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"
   
 /* point to the block driver where the snapshots are managed */  /* point to the block driver where the snapshots are managed */
 static BlockDriverState *bs_snapshots;  static BlockDriverState *bs_snapshots;
   
 #define SELF_ANNOUNCE_ROUNDS 5  #define SELF_ANNOUNCE_ROUNDS 5
 #define ETH_P_EXPERIMENTAL 0x01F1 /* just a number */  
 //#define ETH_P_EXPERIMENTAL 0x0012 /* make it the size of the packet */  
 #define EXPERIMENTAL_MAGIC 0xf1f23f4f  
   
 static int announce_self_create(uint8_t *buf,   #ifndef ETH_P_RARP
   #define ETH_P_RARP 0x0835
   #endif
   #define ARP_HTYPE_ETH 0x0001
   #define ARP_PTYPE_IP 0x0800
   #define ARP_OP_REQUEST_REV 0x3
   
   static int announce_self_create(uint8_t *buf,
                                 uint8_t *mac_addr)                                  uint8_t *mac_addr)
 {  {
     uint32_t magic = EXPERIMENTAL_MAGIC;      /* Ethernet header. */
     uint16_t proto = htons(ETH_P_EXPERIMENTAL);      memset(buf, 0xff, 6);         /* destination MAC addr */
       memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
       *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
   
       /* RARP header. */
       *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
       *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
       *(buf + 18) = 6; /* hardware addr length (ethernet) */
       *(buf + 19) = 4; /* protocol addr length (IPv4) */
       *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
       memcpy(buf + 22, mac_addr, 6); /* source hw addr */
       memset(buf + 28, 0x00, 4);     /* source protocol addr */
       memcpy(buf + 32, mac_addr, 6); /* target hw addr */
       memset(buf + 38, 0x00, 4);     /* target protocol addr */
   
       /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
       memset(buf + 42, 0x00, 18);
   
     /* FIXME: should we send a different packet (arp/rarp/ping)? */      return 60; /* len (FCS will be added by hardware) */
   }
   
     memset(buf, 0, 64);  static void qemu_announce_self_iter(NICState *nic, void *opaque)
     memset(buf, 0xff, 6);         /* h_dst */  {
     memcpy(buf + 6, mac_addr, 6); /* h_src */      uint8_t buf[60];
     memcpy(buf + 12, &proto, 2);  /* h_proto */      int len;
     memcpy(buf + 14, &magic, 4);  /* magic */  
       len = announce_self_create(buf, nic->conf->macaddr.a);
   
     return 64; /* len */      qemu_send_packet_raw(&nic->nc, buf, len);
 }  }
   
   
 static void qemu_announce_self_once(void *opaque)  static void qemu_announce_self_once(void *opaque)
 {  {
     int i, len;  
     VLANState *vlan;  
     VLANClientState *vc;  
     uint8_t buf[256];  
     static int count = SELF_ANNOUNCE_ROUNDS;      static int count = SELF_ANNOUNCE_ROUNDS;
     QEMUTimer *timer = *(QEMUTimer **)opaque;      QEMUTimer *timer = *(QEMUTimer **)opaque;
   
     for (i = 0; i < MAX_NICS; i++) {      qemu_foreach_nic(qemu_announce_self_iter, NULL);
         if (!nd_table[i].used)  
             continue;      if (--count) {
         len = announce_self_create(buf, nd_table[i].macaddr);          /* delay 50ms, 150ms, 250ms, ... */
         vlan = nd_table[i].vlan;          qemu_mod_timer(timer, qemu_get_clock(rt_clock) +
         for(vc = vlan->first_client; vc != NULL; vc = vc->next) {                         50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100);
             vc->receive(vc, buf, len);  
         }  
     }  
     if (count--) {  
             qemu_mod_timer(timer, qemu_get_clock(rt_clock) + 100);  
     } else {      } else {
             qemu_del_timer(timer);              qemu_del_timer(timer);
             qemu_free_timer(timer);              qemu_free_timer(timer);
Line 160  struct QEMUFile { Line 166  struct QEMUFile {
     QEMUFileCloseFunc *close;      QEMUFileCloseFunc *close;
     QEMUFileRateLimit *rate_limit;      QEMUFileRateLimit *rate_limit;
     QEMUFileSetRateLimit *set_rate_limit;      QEMUFileSetRateLimit *set_rate_limit;
       QEMUFileGetRateLimit *get_rate_limit;
     void *opaque;      void *opaque;
     int is_write;      int is_write;
   
Line 172  struct QEMUFile { Line 179  struct QEMUFile {
     int has_error;      int has_error;
 };  };
   
 typedef struct QEMUFilePopen  typedef struct QEMUFileStdio
 {  {
     FILE *popen_file;      FILE *stdio_file;
     QEMUFile *file;      QEMUFile *file;
 } QEMUFilePopen;  } QEMUFileStdio;
   
 typedef struct QEMUFileSocket  typedef struct QEMUFileSocket
 {  {
Line 206  static int socket_close(void *opaque) Line 213  static int socket_close(void *opaque)
     return 0;      return 0;
 }  }
   
 static int popen_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)  static int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
 {  {
     QEMUFilePopen *s = opaque;      QEMUFileStdio *s = opaque;
     return fwrite(buf, 1, size, s->popen_file);      return fwrite(buf, 1, size, s->stdio_file);
 }  }
   
 static int popen_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)  static int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
 {  {
     QEMUFilePopen *s = opaque;      QEMUFileStdio *s = opaque;
     FILE *fp = s->popen_file;      FILE *fp = s->stdio_file;
     int bytes;      int bytes;
   
     do {      do {
Line 225  static int popen_get_buffer(void *opaque Line 232  static int popen_get_buffer(void *opaque
     return bytes;      return bytes;
 }  }
   
 static int popen_close(void *opaque)  static int stdio_pclose(void *opaque)
 {  {
     QEMUFilePopen *s = opaque;      QEMUFileStdio *s = opaque;
     pclose(s->popen_file);      pclose(s->stdio_file);
     qemu_free(s);      qemu_free(s);
     return 0;      return 0;
 }  }
   
 QEMUFile *qemu_popen(FILE *popen_file, const char *mode)  static int stdio_fclose(void *opaque)
 {  {
     QEMUFilePopen *s;      QEMUFileStdio *s = opaque;
       fclose(s->stdio_file);
       qemu_free(s);
       return 0;
   }
   
     if (popen_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {  QEMUFile *qemu_popen(FILE *stdio_file, const char *mode)
   {
       QEMUFileStdio *s;
   
       if (stdio_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
         fprintf(stderr, "qemu_popen: Argument validity check failed\n");          fprintf(stderr, "qemu_popen: Argument validity check failed\n");
         return NULL;          return NULL;
     }      }
   
     s = qemu_mallocz(sizeof(QEMUFilePopen));      s = qemu_mallocz(sizeof(QEMUFileStdio));
   
     s->popen_file = popen_file;      s->stdio_file = stdio_file;
   
     if(mode[0] == 'r') {      if(mode[0] == 'r') {
         s->file = qemu_fopen_ops(s, NULL, popen_get_buffer, popen_close, NULL, NULL);          s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_pclose, 
                                    NULL, NULL, NULL);
     } else {      } else {
         s->file = qemu_fopen_ops(s, popen_put_buffer, NULL, popen_close, NULL, NULL);          s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_pclose, 
                                    NULL, NULL, NULL);
     }      }
     return s->file;      return s->file;
 }  }
Line 266  QEMUFile *qemu_popen_cmd(const char *com Line 283  QEMUFile *qemu_popen_cmd(const char *com
     return qemu_popen(popen_file, mode);      return qemu_popen(popen_file, mode);
 }  }
   
 int qemu_popen_fd(QEMUFile *f)  int qemu_stdio_fd(QEMUFile *f)
 {  {
     QEMUFilePopen *p;      QEMUFileStdio *p;
     int fd;      int fd;
   
     p = (QEMUFilePopen *)f->opaque;      p = (QEMUFileStdio *)f->opaque;
     fd = fileno(p->popen_file);      fd = fileno(p->stdio_file);
   
     return fd;      return fd;
 }  }
   
   QEMUFile *qemu_fdopen(int fd, const char *mode)
   {
       QEMUFileStdio *s;
   
       if (mode == NULL ||
           (mode[0] != 'r' && mode[0] != 'w') ||
           mode[1] != 'b' || mode[2] != 0) {
           fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
           return NULL;
       }
   
       s = qemu_mallocz(sizeof(QEMUFileStdio));
       s->stdio_file = fdopen(fd, mode);
       if (!s->stdio_file)
           goto fail;
   
       if(mode[0] == 'r') {
           s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose, 
                                    NULL, NULL, NULL);
       } else {
           s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose, 
                                    NULL, NULL, NULL);
       }
       return s->file;
   
   fail:
       qemu_free(s);
       return NULL;
   }
   
 QEMUFile *qemu_fopen_socket(int fd)  QEMUFile *qemu_fopen_socket(int fd)
 {  {
     QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));      QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
   
     s->fd = fd;      s->fd = fd;
     s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, socket_close, NULL, NULL);      s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, socket_close, 
                                NULL, NULL, NULL);
     return s->file;      return s->file;
 }  }
   
 typedef struct QEMUFileStdio  
 {  
     FILE *outfile;  
 } QEMUFileStdio;  
   
 static int file_put_buffer(void *opaque, const uint8_t *buf,  static int file_put_buffer(void *opaque, const uint8_t *buf,
                             int64_t pos, int size)                              int64_t pos, int size)
 {  {
     QEMUFileStdio *s = opaque;      QEMUFileStdio *s = opaque;
     fseek(s->outfile, pos, SEEK_SET);      fseek(s->stdio_file, pos, SEEK_SET);
     fwrite(buf, 1, size, s->outfile);      fwrite(buf, 1, size, s->stdio_file);
     return size;      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)
 {  {
     QEMUFileStdio *s = opaque;      QEMUFileStdio *s = opaque;
     fseek(s->outfile, pos, SEEK_SET);      fseek(s->stdio_file, pos, SEEK_SET);
     return fread(buf, 1, size, s->outfile);      return fread(buf, 1, size, s->stdio_file);
 }  
   
 static int file_close(void *opaque)  
 {  
     QEMUFileStdio *s = opaque;  
     fclose(s->outfile);  
     qemu_free(s);  
     return 0;  
 }  }
   
 QEMUFile *qemu_fopen(const char *filename, const char *mode)  QEMUFile *qemu_fopen(const char *filename, const char *mode)
 {  {
     QEMUFileStdio *s;      QEMUFileStdio *s;
   
       if (mode == NULL ||
           (mode[0] != 'r' && mode[0] != 'w') ||
           mode[1] != 'b' || mode[2] != 0) {
           fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
           return NULL;
       }
   
     s = qemu_mallocz(sizeof(QEMUFileStdio));      s = qemu_mallocz(sizeof(QEMUFileStdio));
   
     s->outfile = fopen(filename, mode);      s->stdio_file = fopen(filename, mode);
     if (!s->outfile)      if (!s->stdio_file)
         goto fail;          goto fail;
       
     if (!strcmp(mode, "wb"))      if(mode[0] == 'w') {
         return qemu_fopen_ops(s, file_put_buffer, NULL, file_close, NULL, NULL);          s->file = qemu_fopen_ops(s, file_put_buffer, NULL, stdio_fclose, 
     else if (!strcmp(mode, "rb"))                                   NULL, NULL, NULL);
         return qemu_fopen_ops(s, NULL, file_get_buffer, file_close, NULL, NULL);      } else {
           s->file = qemu_fopen_ops(s, NULL, file_get_buffer, stdio_fclose, 
                                  NULL, NULL, NULL);
       }
       return s->file;
 fail:  fail:
     if (s->outfile)  
         fclose(s->outfile);  
     qemu_free(s);      qemu_free(s);
     return NULL;      return NULL;
 }  }
Line 357  static int bdrv_fclose(void *opaque) Line 400  static int bdrv_fclose(void *opaque)
 static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)  static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
 {  {
     if (is_writable)      if (is_writable)
         return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose, NULL, NULL);          return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose, 
     return qemu_fopen_ops(bs, NULL, block_get_buffer, bdrv_fclose, NULL, NULL);                                NULL, NULL, NULL);
       return qemu_fopen_ops(bs, NULL, block_get_buffer, bdrv_fclose, NULL, NULL, NULL);
 }  }
   
 QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,  QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
                          QEMUFileGetBufferFunc *get_buffer,                           QEMUFileGetBufferFunc *get_buffer,
                          QEMUFileCloseFunc *close,                           QEMUFileCloseFunc *close,
                          QEMUFileRateLimit *rate_limit,                           QEMUFileRateLimit *rate_limit,
                          QEMUFileSetRateLimit *set_rate_limit)                           QEMUFileSetRateLimit *set_rate_limit,
                            QEMUFileGetRateLimit *get_rate_limit)
 {  {
     QEMUFile *f;      QEMUFile *f;
   
Line 377  QEMUFile *qemu_fopen_ops(void *opaque, Q Line 422  QEMUFile *qemu_fopen_ops(void *opaque, Q
     f->close = close;      f->close = close;
     f->rate_limit = rate_limit;      f->rate_limit = rate_limit;
     f->set_rate_limit = set_rate_limit;      f->set_rate_limit = set_rate_limit;
       f->get_rate_limit = get_rate_limit;
     f->is_write = 0;      f->is_write = 0;
   
     return f;      return f;
Line 554  int qemu_file_rate_limit(QEMUFile *f) Line 600  int qemu_file_rate_limit(QEMUFile *f)
     return 0;      return 0;
 }  }
   
   size_t qemu_file_get_rate_limit(QEMUFile *f)
   {
       if (f->get_rate_limit)
           return f->get_rate_limit(f->opaque);
   
       return 0;
   }
   
 size_t qemu_file_set_rate_limit(QEMUFile *f, size_t new_rate)  size_t qemu_file_set_rate_limit(QEMUFile *f, size_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
Line 610  uint64_t qemu_get_be64(QEMUFile *f) Line 664  uint64_t qemu_get_be64(QEMUFile *f)
     return v;      return v;
 }  }
   
   /* 8 bit int */
   
   static int get_int8(QEMUFile *f, void *pv, size_t size)
   {
       int8_t *v = pv;
       qemu_get_s8s(f, v);
       return 0;
   }
   
   static void put_int8(QEMUFile *f, void *pv, size_t size)
   {
       int8_t *v = pv;
       qemu_put_s8s(f, v);
   }
   
   const VMStateInfo vmstate_info_int8 = {
       .name = "int8",
       .get  = get_int8,
       .put  = put_int8,
   };
   
   /* 16 bit int */
   
   static int get_int16(QEMUFile *f, void *pv, size_t size)
   {
       int16_t *v = pv;
       qemu_get_sbe16s(f, v);
       return 0;
   }
   
   static void put_int16(QEMUFile *f, void *pv, size_t size)
   {
       int16_t *v = pv;
       qemu_put_sbe16s(f, v);
   }
   
   const VMStateInfo vmstate_info_int16 = {
       .name = "int16",
       .get  = get_int16,
       .put  = put_int16,
   };
   
   /* 32 bit int */
   
   static int get_int32(QEMUFile *f, void *pv, size_t size)
   {
       int32_t *v = pv;
       qemu_get_sbe32s(f, v);
       return 0;
   }
   
   static void put_int32(QEMUFile *f, void *pv, size_t size)
   {
       int32_t *v = pv;
       qemu_put_sbe32s(f, v);
   }
   
   const VMStateInfo vmstate_info_int32 = {
       .name = "int32",
       .get  = get_int32,
       .put  = put_int32,
   };
   
   /* 32 bit int. See that the received value is the same than the one
      in the field */
   
   static int get_int32_equal(QEMUFile *f, void *pv, size_t size)
   {
       int32_t *v = pv;
       int32_t v2;
       qemu_get_sbe32s(f, &v2);
   
       if (*v == v2)
           return 0;
       return -EINVAL;
   }
   
   const VMStateInfo vmstate_info_int32_equal = {
       .name = "int32 equal",
       .get  = get_int32_equal,
       .put  = put_int32,
   };
   
   /* 32 bit int. See that the received value is the less or the same
      than the one in the field */
   
   static int get_int32_le(QEMUFile *f, void *pv, size_t size)
   {
       int32_t *old = pv;
       int32_t new;
       qemu_get_sbe32s(f, &new);
   
       if (*old <= new)
           return 0;
       return -EINVAL;
   }
   
   const VMStateInfo vmstate_info_int32_le = {
       .name = "int32 equal",
       .get  = get_int32_le,
       .put  = put_int32,
   };
   
   /* 64 bit int */
   
   static int get_int64(QEMUFile *f, void *pv, size_t size)
   {
       int64_t *v = pv;
       qemu_get_sbe64s(f, v);
       return 0;
   }
   
   static void put_int64(QEMUFile *f, void *pv, size_t size)
   {
       int64_t *v = pv;
       qemu_put_sbe64s(f, v);
   }
   
   const VMStateInfo vmstate_info_int64 = {
       .name = "int64",
       .get  = get_int64,
       .put  = put_int64,
   };
   
   /* 8 bit unsigned int */
   
   static int get_uint8(QEMUFile *f, void *pv, size_t size)
   {
       uint8_t *v = pv;
       qemu_get_8s(f, v);
       return 0;
   }
   
   static void put_uint8(QEMUFile *f, void *pv, size_t size)
   {
       uint8_t *v = pv;
       qemu_put_8s(f, v);
   }
   
   const VMStateInfo vmstate_info_uint8 = {
       .name = "uint8",
       .get  = get_uint8,
       .put  = put_uint8,
   };
   
   /* 16 bit unsigned int */
   
   static int get_uint16(QEMUFile *f, void *pv, size_t size)
   {
       uint16_t *v = pv;
       qemu_get_be16s(f, v);
       return 0;
   }
   
   static void put_uint16(QEMUFile *f, void *pv, size_t size)
   {
       uint16_t *v = pv;
       qemu_put_be16s(f, v);
   }
   
   const VMStateInfo vmstate_info_uint16 = {
       .name = "uint16",
       .get  = get_uint16,
       .put  = put_uint16,
   };
   
   /* 32 bit unsigned int */
   
   static int get_uint32(QEMUFile *f, void *pv, size_t size)
   {
       uint32_t *v = pv;
       qemu_get_be32s(f, v);
       return 0;
   }
   
   static void put_uint32(QEMUFile *f, void *pv, size_t size)
   {
       uint32_t *v = pv;
       qemu_put_be32s(f, v);
   }
   
   const VMStateInfo vmstate_info_uint32 = {
       .name = "uint32",
       .get  = get_uint32,
       .put  = put_uint32,
   };
   
   /* 64 bit unsigned int */
   
   static int get_uint64(QEMUFile *f, void *pv, size_t size)
   {
       uint64_t *v = pv;
       qemu_get_be64s(f, v);
       return 0;
   }
   
   static void put_uint64(QEMUFile *f, void *pv, size_t size)
   {
       uint64_t *v = pv;
       qemu_put_be64s(f, v);
   }
   
   const VMStateInfo vmstate_info_uint64 = {
       .name = "uint64",
       .get  = get_uint64,
       .put  = put_uint64,
   };
   
   /* 8 bit int. See that the received value is the same than the one
      in the field */
   
   static int get_uint8_equal(QEMUFile *f, void *pv, size_t size)
   {
       uint8_t *v = pv;
       uint8_t v2;
       qemu_get_8s(f, &v2);
   
       if (*v == v2)
           return 0;
       return -EINVAL;
   }
   
   const VMStateInfo vmstate_info_uint8_equal = {
       .name = "uint8 equal",
       .get  = get_uint8_equal,
       .put  = put_uint8,
   };
   
   /* 16 bit unsigned int int. See that the received value is the same than the one
      in the field */
   
   static int get_uint16_equal(QEMUFile *f, void *pv, size_t size)
   {
       uint16_t *v = pv;
       uint16_t v2;
       qemu_get_be16s(f, &v2);
   
       if (*v == v2)
           return 0;
       return -EINVAL;
   }
   
   const VMStateInfo vmstate_info_uint16_equal = {
       .name = "uint16 equal",
       .get  = get_uint16_equal,
       .put  = put_uint16,
   };
   
   /* timers  */
   
   static int get_timer(QEMUFile *f, void *pv, size_t size)
   {
       QEMUTimer *v = pv;
       qemu_get_timer(f, v);
       return 0;
   }
   
   static void put_timer(QEMUFile *f, void *pv, size_t size)
   {
       QEMUTimer *v = pv;
       qemu_put_timer(f, v);
   }
   
   const VMStateInfo vmstate_info_timer = {
       .name = "timer",
       .get  = get_timer,
       .put  = put_timer,
   };
   
   /* uint8_t buffers */
   
   static int get_buffer(QEMUFile *f, void *pv, size_t size)
   {
       uint8_t *v = pv;
       qemu_get_buffer(f, v, size);
       return 0;
   }
   
   static void put_buffer(QEMUFile *f, void *pv, size_t size)
   {
       uint8_t *v = pv;
       qemu_put_buffer(f, v, size);
   }
   
   const VMStateInfo vmstate_info_buffer = {
       .name = "buffer",
       .get  = get_buffer,
       .put  = put_buffer,
   };
   
   /* unused buffers: space that was used for some fields that are
      not usefull anymore */
   
   static int get_unused_buffer(QEMUFile *f, void *pv, size_t size)
   {
       uint8_t buf[1024];
       int block_len;
   
       while (size > 0) {
           block_len = MIN(sizeof(buf), size);
           size -= block_len;
           qemu_get_buffer(f, buf, block_len);
       }
      return 0;
   }
   
   static void put_unused_buffer(QEMUFile *f, void *pv, size_t size)
   {
       static const uint8_t buf[1024];
       int block_len;
   
       while (size > 0) {
           block_len = MIN(sizeof(buf), size);
           size -= block_len;
           qemu_put_buffer(f, buf, block_len);
       }
   }
   
   const VMStateInfo vmstate_info_unused_buffer = {
       .name = "unused_buffer",
       .get  = get_unused_buffer,
       .put  = put_unused_buffer,
   };
   
 typedef struct SaveStateEntry {  typedef struct SaveStateEntry {
       QTAILQ_ENTRY(SaveStateEntry) entry;
     char idstr[256];      char idstr[256];
     int instance_id;      int instance_id;
     int version_id;      int version_id;
     int section_id;      int section_id;
       SaveSetParamsHandler *set_params;
     SaveLiveStateHandler *save_live_state;      SaveLiveStateHandler *save_live_state;
     SaveStateHandler *save_state;      SaveStateHandler *save_state;
     LoadStateHandler *load_state;      LoadStateHandler *load_state;
       const VMStateDescription *vmsd;
     void *opaque;      void *opaque;
     struct SaveStateEntry *next;  
 } SaveStateEntry;  } SaveStateEntry;
   
 static SaveStateEntry *first_se;  
   static QTAILQ_HEAD(savevm_handlers, SaveStateEntry) savevm_handlers =
       QTAILQ_HEAD_INITIALIZER(savevm_handlers);
   static int global_section_id;
   
   static int calculate_new_instance_id(const char *idstr)
   {
       SaveStateEntry *se;
       int instance_id = 0;
   
       QTAILQ_FOREACH(se, &savevm_handlers, entry) {
           if (strcmp(idstr, se->idstr) == 0
               && instance_id <= se->instance_id) {
               instance_id = se->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.
Line 631  static SaveStateEntry *first_se; Line 1028  static SaveStateEntry *first_se;
 int register_savevm_live(const char *idstr,  int register_savevm_live(const char *idstr,
                          int instance_id,                           int instance_id,
                          int version_id,                           int version_id,
                            SaveSetParamsHandler *set_params,
                          SaveLiveStateHandler *save_live_state,                           SaveLiveStateHandler *save_live_state,
                          SaveStateHandler *save_state,                           SaveStateHandler *save_state,
                          LoadStateHandler *load_state,                           LoadStateHandler *load_state,
                          void *opaque)                           void *opaque)
 {  {
     SaveStateEntry *se, **pse;      SaveStateEntry *se;
     static int global_section_id;  
   
     se = qemu_malloc(sizeof(SaveStateEntry));      se = qemu_mallocz(sizeof(SaveStateEntry));
     pstrcpy(se->idstr, sizeof(se->idstr), idstr);      pstrcpy(se->idstr, sizeof(se->idstr), idstr);
     se->instance_id = (instance_id == -1) ? 0 : instance_id;  
     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->save_live_state = save_live_state;      se->save_live_state = save_live_state;
     se->save_state = save_state;      se->save_state = save_state;
     se->load_state = load_state;      se->load_state = load_state;
     se->opaque = opaque;      se->opaque = opaque;
     se->next = NULL;      se->vmsd = NULL;
   
     /* add at the end of list */      if (instance_id == -1) {
     pse = &first_se;          se->instance_id = calculate_new_instance_id(idstr);
     while (*pse != NULL) {      } else {
         if (instance_id == -1          se->instance_id = instance_id;
                 && strcmp(se->idstr, (*pse)->idstr) == 0  
                 && se->instance_id <= (*pse)->instance_id)  
             se->instance_id = (*pse)->instance_id + 1;  
         pse = &(*pse)->next;  
     }      }
     *pse = se;      /* add at the end of list */
       QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
     return 0;      return 0;
 }  }
   
Line 671  int register_savevm(const char *idstr, Line 1065  int register_savevm(const char *idstr,
                     void *opaque)                      void *opaque)
 {  {
     return register_savevm_live(idstr, instance_id, version_id,      return register_savevm_live(idstr, instance_id, version_id,
                                 NULL, save_state, load_state, opaque);                                  NULL, NULL, save_state, load_state, opaque);
 }  }
   
 void unregister_savevm(const char *idstr, void *opaque)  void unregister_savevm(const char *idstr, void *opaque)
 {  {
     SaveStateEntry **pse;      SaveStateEntry *se, *new_se;
   
     pse = &first_se;      QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
     while (*pse != NULL) {          if (strcmp(se->idstr, idstr) == 0 && se->opaque == opaque) {
         if (strcmp((*pse)->idstr, idstr) == 0 && (*pse)->opaque == opaque) {              QTAILQ_REMOVE(&savevm_handlers, se, entry);
             SaveStateEntry *next = (*pse)->next;              qemu_free(se);
             qemu_free(*pse);  
             *pse = next;  
             continue;  
         }          }
         pse = &(*pse)->next;  
     }      }
 }  }
   
   int vmstate_register(int instance_id, const VMStateDescription *vmsd,
                        void *opaque)
   {
       SaveStateEntry *se;
   
       se = qemu_mallocz(sizeof(SaveStateEntry));
       pstrcpy(se->idstr, sizeof(se->idstr), vmsd->name);
       se->version_id = vmsd->version_id;
       se->section_id = global_section_id++;
       se->save_live_state = NULL;
       se->save_state = NULL;
       se->load_state = NULL;
       se->opaque = opaque;
       se->vmsd = vmsd;
   
       if (instance_id == -1) {
           se->instance_id = calculate_new_instance_id(vmsd->name);
       } else {
           se->instance_id = instance_id;
       }
       /* add at the end of list */
       QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
       return 0;
   }
   
   void vmstate_unregister(const VMStateDescription *vmsd, void *opaque)
   {
       SaveStateEntry *se, *new_se;
   
       QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
           if (se->vmsd == vmsd && se->opaque == opaque) {
               QTAILQ_REMOVE(&savevm_handlers, se, entry);
               qemu_free(se);
           }
       }
   }
   
   int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                          void *opaque, int version_id)
   {
       VMStateField *field = vmsd->fields;
   
       if (version_id > vmsd->version_id) {
           return -EINVAL;
       }
       if (version_id < vmsd->minimum_version_id_old) {
           return -EINVAL;
       }
       if  (version_id < vmsd->minimum_version_id) {
           return vmsd->load_state_old(f, opaque, version_id);
       }
       if (vmsd->pre_load) {
           int ret = vmsd->pre_load(opaque);
           if (ret)
               return ret;
       }
       while(field->name) {
           if ((field->field_exists &&
                field->field_exists(opaque, version_id)) ||
               (!field->field_exists &&
                field->version_id <= version_id)) {
               void *base_addr = opaque + field->offset;
               int ret, i, n_elems = 1;
               int size = field->size;
   
               if (field->flags & VMS_VBUFFER) {
                   size = *(int32_t *)(opaque+field->size_offset);
                   if (field->flags & VMS_MULTIPLY) {
                       size *= field->size;
                   }
               }
               if (field->flags & VMS_ARRAY) {
                   n_elems = field->num;
               } else if (field->flags & VMS_VARRAY_INT32) {
                   n_elems = *(int32_t *)(opaque+field->num_offset);
               } else if (field->flags & VMS_VARRAY_UINT16) {
                   n_elems = *(uint16_t *)(opaque+field->num_offset);
               }
               if (field->flags & VMS_POINTER) {
                   base_addr = *(void **)base_addr + field->start;
               }
               for (i = 0; i < n_elems; i++) {
                   void *addr = base_addr + size * i;
   
                   if (field->flags & VMS_ARRAY_OF_POINTER) {
                       addr = *(void **)addr;
                   }
                   if (field->flags & VMS_STRUCT) {
                       ret = vmstate_load_state(f, field->vmsd, addr, field->vmsd->version_id);
                   } else {
                       ret = field->info->get(f, addr, size);
   
                   }
                   if (ret < 0) {
                       return ret;
                   }
               }
           }
           field++;
       }
       if (vmsd->post_load) {
           return vmsd->post_load(opaque, version_id);
       }
       return 0;
   }
   
   void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
                           void *opaque)
   {
       VMStateField *field = vmsd->fields;
   
       if (vmsd->pre_save) {
           vmsd->pre_save(opaque);
       }
       while(field->name) {
           if (!field->field_exists ||
               field->field_exists(opaque, vmsd->version_id)) {
               void *base_addr = opaque + field->offset;
               int i, n_elems = 1;
               int size = field->size;
   
               if (field->flags & VMS_VBUFFER) {
                   size = *(int32_t *)(opaque+field->size_offset);
                   if (field->flags & VMS_MULTIPLY) {
                       size *= field->size;
                   }
               }
               if (field->flags & VMS_ARRAY) {
                   n_elems = field->num;
               } else if (field->flags & VMS_VARRAY_INT32) {
                   n_elems = *(int32_t *)(opaque+field->num_offset);
               } else if (field->flags & VMS_VARRAY_UINT16) {
                   n_elems = *(uint16_t *)(opaque+field->num_offset);
               }
               if (field->flags & VMS_POINTER) {
                   base_addr = *(void **)base_addr + field->start;
               }
               for (i = 0; i < n_elems; i++) {
                   void *addr = base_addr + size * i;
   
                   if (field->flags & VMS_ARRAY_OF_POINTER) {
                       addr = *(void **)addr;
                   }
                   if (field->flags & VMS_STRUCT) {
                       vmstate_save_state(f, field->vmsd, addr);
                   } else {
                       field->info->put(f, addr, size);
                   }
               }
           }
           field++;
       }
       if (vmsd->post_save) {
           vmsd->post_save(opaque);
       }
   }
   
   static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
   {
       if (!se->vmsd) {         /* Old style */
           return se->load_state(f, se->opaque, version_id);
       }
       return vmstate_load_state(f, se->vmsd, se->opaque, version_id);
   }
   
   static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
   {
       if (!se->vmsd) {         /* Old style */
           se->save_state(f, se->opaque);
           return;
       }
       vmstate_save_state(f,se->vmsd, se->opaque);
   }
   
 #define QEMU_VM_FILE_MAGIC           0x5145564d  #define QEMU_VM_FILE_MAGIC           0x5145564d
 #define QEMU_VM_FILE_VERSION_COMPAT  0x00000002  #define QEMU_VM_FILE_VERSION_COMPAT  0x00000002
 #define QEMU_VM_FILE_VERSION         0x00000003  #define QEMU_VM_FILE_VERSION         0x00000003
Line 700  void unregister_savevm(const char *idstr Line 1264  void unregister_savevm(const char *idstr
 #define QEMU_VM_SECTION_END          0x03  #define QEMU_VM_SECTION_END          0x03
 #define QEMU_VM_SECTION_FULL         0x04  #define QEMU_VM_SECTION_FULL         0x04
   
 int qemu_savevm_state_begin(QEMUFile *f)  int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
                               int shared)
 {  {
     SaveStateEntry *se;      SaveStateEntry *se;
   
       QTAILQ_FOREACH(se, &savevm_handlers, entry) {
           if(se->set_params == NULL) {
               continue;
           }
           se->set_params(blk_enable, shared, se->opaque);
       }
       
     qemu_put_be32(f, QEMU_VM_FILE_MAGIC);      qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
     qemu_put_be32(f, QEMU_VM_FILE_VERSION);      qemu_put_be32(f, QEMU_VM_FILE_VERSION);
   
     for (se = first_se; se != NULL; se = se->next) {      QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         int len;          int len;
   
         if (se->save_live_state == NULL)          if (se->save_live_state == NULL)
Line 725  int qemu_savevm_state_begin(QEMUFile *f) Line 1297  int qemu_savevm_state_begin(QEMUFile *f)
         qemu_put_be32(f, se->instance_id);          qemu_put_be32(f, se->instance_id);
         qemu_put_be32(f, se->version_id);          qemu_put_be32(f, se->version_id);
   
         se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);          se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
     }      }
   
     if (qemu_file_has_error(f))      if (qemu_file_has_error(f)) {
           qemu_savevm_state_cancel(mon, f);
         return -EIO;          return -EIO;
       }
   
     return 0;      return 0;
 }  }
   
 int qemu_savevm_state_iterate(QEMUFile *f)  int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
 {  {
     SaveStateEntry *se;      SaveStateEntry *se;
     int ret = 1;      int ret = 1;
   
     for (se = first_se; se != NULL; se = se->next) {      QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         if (se->save_live_state == NULL)          if (se->save_live_state == NULL)
             continue;              continue;
   
Line 747  int qemu_savevm_state_iterate(QEMUFile * Line 1321  int qemu_savevm_state_iterate(QEMUFile *
         qemu_put_byte(f, QEMU_VM_SECTION_PART);          qemu_put_byte(f, QEMU_VM_SECTION_PART);
         qemu_put_be32(f, se->section_id);          qemu_put_be32(f, se->section_id);
   
         ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque);          ret = se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque);
           if (!ret) {
               /* Do not proceed to the next vmstate before this one reported
                  completion of the current stage. This serializes the migration
                  and reduces the probability that a faster changing state is
                  synchronized over and over again. */
               break;
           }
     }      }
   
     if (ret)      if (ret)
         return 1;          return 1;
   
     if (qemu_file_has_error(f))      if (qemu_file_has_error(f)) {
           qemu_savevm_state_cancel(mon, f);
         return -EIO;          return -EIO;
       }
   
     return 0;      return 0;
 }  }
   
 int qemu_savevm_state_complete(QEMUFile *f)  int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
 {  {
     SaveStateEntry *se;      SaveStateEntry *se;
   
     for (se = first_se; se != NULL; se = se->next) {      QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         if (se->save_live_state == NULL)          if (se->save_live_state == NULL)
             continue;              continue;
   
Line 771  int qemu_savevm_state_complete(QEMUFile  Line 1354  int qemu_savevm_state_complete(QEMUFile 
         qemu_put_byte(f, QEMU_VM_SECTION_END);          qemu_put_byte(f, QEMU_VM_SECTION_END);
         qemu_put_be32(f, se->section_id);          qemu_put_be32(f, se->section_id);
   
         se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);          se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
     }      }
   
     for(se = first_se; se != NULL; se = se->next) {      QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         int len;          int len;
   
         if (se->save_state == NULL)          if (se->save_state == NULL && se->vmsd == NULL)
             continue;              continue;
   
         /* Section type */          /* Section type */
Line 792  int qemu_savevm_state_complete(QEMUFile  Line 1375  int qemu_savevm_state_complete(QEMUFile 
         qemu_put_be32(f, se->instance_id);          qemu_put_be32(f, se->instance_id);
         qemu_put_be32(f, se->version_id);          qemu_put_be32(f, se->version_id);
   
         se->save_state(f, se->opaque);          vmstate_save(f, se);
     }      }
   
     qemu_put_byte(f, QEMU_VM_EOF);      qemu_put_byte(f, QEMU_VM_EOF);
Line 803  int qemu_savevm_state_complete(QEMUFile  Line 1386  int qemu_savevm_state_complete(QEMUFile 
     return 0;      return 0;
 }  }
   
 int qemu_savevm_state(QEMUFile *f)  void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f)
   {
       SaveStateEntry *se;
   
       QTAILQ_FOREACH(se, &savevm_handlers, entry) {
           if (se->save_live_state) {
               se->save_live_state(mon, f, -1, se->opaque);
           }
       }
   }
   
   static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
 {  {
     int saved_vm_running;      int saved_vm_running;
     int ret;      int ret;
Line 813  int qemu_savevm_state(QEMUFile *f) Line 1407  int qemu_savevm_state(QEMUFile *f)
   
     bdrv_flush_all();      bdrv_flush_all();
   
     ret = qemu_savevm_state_begin(f);      ret = qemu_savevm_state_begin(mon, f, 0, 0);
     if (ret < 0)      if (ret < 0)
         goto out;          goto out;
   
     do {      do {
         ret = qemu_savevm_state_iterate(f);          ret = qemu_savevm_state_iterate(mon, f);
         if (ret < 0)          if (ret < 0)
             goto out;              goto out;
     } while (ret == 0);      } while (ret == 0);
   
     ret = qemu_savevm_state_complete(f);      ret = qemu_savevm_state_complete(mon, f);
   
 out:  out:
     if (qemu_file_has_error(f))      if (qemu_file_has_error(f))
Line 839  static SaveStateEntry *find_se(const cha Line 1433  static SaveStateEntry *find_se(const cha
 {  {
     SaveStateEntry *se;      SaveStateEntry *se;
   
     for(se = first_se; se != NULL; se = se->next) {      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)
             return se;              return se;
Line 848  static SaveStateEntry *find_se(const cha Line 1442  static SaveStateEntry *find_se(const cha
 }  }
   
 typedef struct LoadStateEntry {  typedef struct LoadStateEntry {
       QLIST_ENTRY(LoadStateEntry) entry;
     SaveStateEntry *se;      SaveStateEntry *se;
     int section_id;      int section_id;
     int version_id;      int version_id;
     struct LoadStateEntry *next;  
 } LoadStateEntry;  } LoadStateEntry;
   
 static int qemu_loadvm_state_v2(QEMUFile *f)  
 {  
     SaveStateEntry *se;  
     int len, ret, instance_id, record_len, version_id;  
     int64_t total_len, end_pos, cur_pos;  
     char idstr[256];  
   
     total_len = qemu_get_be64(f);  
     end_pos = total_len + qemu_ftell(f);  
     for(;;) {  
         if (qemu_ftell(f) >= end_pos)  
             break;  
         len = qemu_get_byte(f);  
         qemu_get_buffer(f, (uint8_t *)idstr, len);  
         idstr[len] = '\0';  
         instance_id = qemu_get_be32(f);  
         version_id = qemu_get_be32(f);  
         record_len = qemu_get_be32(f);  
         cur_pos = qemu_ftell(f);  
         se = find_se(idstr, instance_id);  
         if (!se) {  
             fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",  
                     instance_id, idstr);  
         } else {  
             ret = se->load_state(f, se->opaque, version_id);  
             if (ret < 0) {  
                 fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",  
                         instance_id, idstr);  
                 return ret;  
             }  
         }  
         /* always seek to exact end of record */  
         qemu_fseek(f, cur_pos + record_len, SEEK_SET);  
     }  
   
     if (qemu_file_has_error(f))  
         return -EIO;  
   
     return 0;  
 }  
   
 int qemu_loadvm_state(QEMUFile *f)  int qemu_loadvm_state(QEMUFile *f)
 {  {
     LoadStateEntry *first_le = NULL;      QLIST_HEAD(, LoadStateEntry) loadvm_handlers =
           QLIST_HEAD_INITIALIZER(loadvm_handlers);
       LoadStateEntry *le, *new_le;
     uint8_t section_type;      uint8_t section_type;
     unsigned int v;      unsigned int v;
     int ret;      int ret;
Line 907  int qemu_loadvm_state(QEMUFile *f) Line 1462  int qemu_loadvm_state(QEMUFile *f)
         return -EINVAL;          return -EINVAL;
   
     v = qemu_get_be32(f);      v = qemu_get_be32(f);
     if (v == QEMU_VM_FILE_VERSION_COMPAT)      if (v == QEMU_VM_FILE_VERSION_COMPAT) {
         return qemu_loadvm_state_v2(f);          fprintf(stderr, "SaveVM v2 format is obsolete and don't work anymore\n");
           return -ENOTSUP;
       }
     if (v != QEMU_VM_FILE_VERSION)      if (v != QEMU_VM_FILE_VERSION)
         return -ENOTSUP;          return -ENOTSUP;
   
     while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {      while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
         uint32_t instance_id, version_id, section_id;          uint32_t instance_id, version_id, section_id;
         LoadStateEntry *le;  
         SaveStateEntry *se;          SaveStateEntry *se;
         char idstr[257];          char idstr[257];
         int len;          int len;
Line 952  int qemu_loadvm_state(QEMUFile *f) Line 1508  int qemu_loadvm_state(QEMUFile *f)
             le->se = se;              le->se = se;
             le->section_id = section_id;              le->section_id = section_id;
             le->version_id = version_id;              le->version_id = version_id;
             le->next = first_le;              QLIST_INSERT_HEAD(&loadvm_handlers, le, entry);
             first_le = le;  
   
             le->se->load_state(f, le->se->opaque, le->version_id);              ret = vmstate_load(f, le->se, le->version_id);
               if (ret < 0) {
                   fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
                           instance_id, idstr);
                   goto out;
               }
             break;              break;
         case QEMU_VM_SECTION_PART:          case QEMU_VM_SECTION_PART:
         case QEMU_VM_SECTION_END:          case QEMU_VM_SECTION_END:
             section_id = qemu_get_be32(f);              section_id = qemu_get_be32(f);
   
             for (le = first_le; le && le->section_id != section_id; le = le->next);              QLIST_FOREACH(le, &loadvm_handlers, entry) {
                   if (le->section_id == section_id) {
                       break;
                   }
               }
             if (le == NULL) {              if (le == NULL) {
                 fprintf(stderr, "Unknown savevm section %d\n", section_id);                  fprintf(stderr, "Unknown savevm section %d\n", section_id);
                 ret = -EINVAL;                  ret = -EINVAL;
                 goto out;                  goto out;
             }              }
   
             le->se->load_state(f, le->se->opaque, le->version_id);              ret = vmstate_load(f, le->se, le->version_id);
               if (ret < 0) {
                   fprintf(stderr, "qemu: warning: error while loading state section id %d\n",
                           section_id);
                   goto out;
               }
             break;              break;
         default:          default:
             fprintf(stderr, "Unknown savevm section type %d\n", section_type);              fprintf(stderr, "Unknown savevm section type %d\n", section_type);
Line 980  int qemu_loadvm_state(QEMUFile *f) Line 1549  int qemu_loadvm_state(QEMUFile *f)
     ret = 0;      ret = 0;
   
 out:  out:
     while (first_le) {      QLIST_FOREACH_SAFE(le, &loadvm_handlers, entry, new_le) {
         LoadStateEntry *le = first_le;          QLIST_REMOVE(le, entry);
         first_le = first_le->next;  
         qemu_free(le);          qemu_free(le);
     }      }
   
Line 1011  static int bdrv_has_snapshot(BlockDriver Line 1579  static int bdrv_has_snapshot(BlockDriver
 static BlockDriverState *get_bs_snapshots(void)  static BlockDriverState *get_bs_snapshots(void)
 {  {
     BlockDriverState *bs;      BlockDriverState *bs;
     int i;      DriveInfo *dinfo;
   
     if (bs_snapshots)      if (bs_snapshots)
         return bs_snapshots;          return bs_snapshots;
     for(i = 0; i <= nb_drives; i++) {      QTAILQ_FOREACH(dinfo, &drives, next) {
         bs = drives_table[i].bdrv;          bs = dinfo->bdrv;
         if (bdrv_can_snapshot(bs))          if (bdrv_can_snapshot(bs))
             goto ok;              goto ok;
     }      }
Line 1048  static int bdrv_snapshot_find(BlockDrive Line 1616  static int bdrv_snapshot_find(BlockDrive
     return ret;      return ret;
 }  }
   
 void do_savevm(Monitor *mon, const char *name)  /*
    * Deletes snapshots of a given name in all opened images.
    */
   static int del_existing_snapshots(Monitor *mon, const char *name)
   {
       BlockDriverState *bs;
       DriveInfo *dinfo;
       QEMUSnapshotInfo sn1, *snapshot = &sn1;
       int ret;
   
       QTAILQ_FOREACH(dinfo, &drives, next) {
           bs = dinfo->bdrv;
           if (bdrv_can_snapshot(bs) &&
               bdrv_snapshot_find(bs, snapshot, name) >= 0)
           {
               ret = bdrv_snapshot_delete(bs, name);
               if (ret < 0) {
                   monitor_printf(mon,
                                  "Error while deleting snapshot on '%s'\n",
                                  bdrv_get_device_name(bs));
                   return -1;
               }
           }
       }
   
       return 0;
   }
   
   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 must_delete, ret, i;      int ret;
     QEMUFile *f;      QEMUFile *f;
     int saved_vm_running;      int saved_vm_running;
     uint32_t vm_state_size;      uint32_t vm_state_size;
Line 1061  void do_savevm(Monitor *mon, const char  Line 1658  void do_savevm(Monitor *mon, const char 
 #else  #else
     struct timeval tv;      struct timeval tv;
 #endif  #endif
       const char *name = qdict_get_try_str(qdict, "name");
   
     bs = get_bs_snapshots();      bs = get_bs_snapshots();
     if (!bs) {      if (!bs) {
Line 1074  void do_savevm(Monitor *mon, const char  Line 1672  void do_savevm(Monitor *mon, const char 
     saved_vm_running = vm_running;      saved_vm_running = vm_running;
     vm_stop(0);      vm_stop(0);
   
     must_delete = 0;      memset(sn, 0, sizeof(*sn));
     if (name) {      if (name) {
         ret = bdrv_snapshot_find(bs, old_sn, name);          ret = bdrv_snapshot_find(bs, old_sn, name);
         if (ret >= 0) {          if (ret >= 0) {
             must_delete = 1;              pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
         }              pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
     }          } else {
     memset(sn, 0, sizeof(*sn));  
     if (must_delete) {  
         pstrcpy(sn->name, sizeof(sn->name), old_sn->name);  
         pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);  
     } else {  
         if (name)  
             pstrcpy(sn->name, sizeof(sn->name), name);              pstrcpy(sn->name, sizeof(sn->name), name);
           }
     }      }
   
     /* fill auxiliary fields */      /* fill auxiliary fields */
Line 1102  void do_savevm(Monitor *mon, const char  Line 1695  void do_savevm(Monitor *mon, const char 
 #endif  #endif
     sn->vm_clock_nsec = qemu_get_clock(vm_clock);      sn->vm_clock_nsec = qemu_get_clock(vm_clock);
   
       /* Delete old snapshots of the same name */
       if (del_existing_snapshots(mon, name) < 0) {
           goto the_end;
       }
   
     /* save the VM state */      /* save the VM state */
     f = qemu_fopen_bdrv(bs, 1);      f = qemu_fopen_bdrv(bs, 1);
     if (!f) {      if (!f) {
         monitor_printf(mon, "Could not open VM state file\n");          monitor_printf(mon, "Could not open VM state file\n");
         goto the_end;          goto the_end;
     }      }
     ret = qemu_savevm_state(f);      ret = qemu_savevm_state(mon, f);
     vm_state_size = qemu_ftell(f);      vm_state_size = qemu_ftell(f);
     qemu_fclose(f);      qemu_fclose(f);
     if (ret < 0) {      if (ret < 0) {
Line 1118  void do_savevm(Monitor *mon, const char  Line 1716  void do_savevm(Monitor *mon, const char 
   
     /* create the snapshots */      /* create the snapshots */
   
     for(i = 0; i < nb_drives; i++) {      QTAILQ_FOREACH(dinfo, &drives, next) {
         bs1 = drives_table[i].bdrv;          bs1 = dinfo->bdrv;
         if (bdrv_has_snapshot(bs1)) {          if (bdrv_has_snapshot(bs1)) {
             if (must_delete) {  
                 ret = bdrv_snapshot_delete(bs1, old_sn->id_str);  
                 if (ret < 0) {  
                     monitor_printf(mon,  
                                    "Error while deleting snapshot on '%s'\n",  
                                    bdrv_get_device_name(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 1144  void do_savevm(Monitor *mon, const char  Line 1734  void do_savevm(Monitor *mon, const char 
         vm_start();          vm_start();
 }  }
   
 void do_loadvm(Monitor *mon, const char *name)  int load_vmstate(Monitor *mon, const char *name)
 {  {
       DriveInfo *dinfo;
     BlockDriverState *bs, *bs1;      BlockDriverState *bs, *bs1;
     QEMUSnapshotInfo sn;      QEMUSnapshotInfo sn;
     QEMUFile *f;      QEMUFile *f;
     int i, ret;      int ret;
     int saved_vm_running;  
   
     bs = get_bs_snapshots();      bs = get_bs_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 -EINVAL;
     }      }
   
     /* 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();
   
     saved_vm_running = vm_running;      QTAILQ_FOREACH(dinfo, &drives, next) {
     vm_stop(0);          bs1 = dinfo->bdrv;
   
     for(i = 0; i <= nb_drives; i++) {  
         bs1 = drives_table[i].bdrv;  
         if (bdrv_has_snapshot(bs1)) {          if (bdrv_has_snapshot(bs1)) {
             ret = bdrv_snapshot_goto(bs1, name);              ret = bdrv_snapshot_goto(bs1, name);
             if (ret < 0) {              if (ret < 0) {
Line 1189  void do_loadvm(Monitor *mon, const char  Line 1776  void do_loadvm(Monitor *mon, const char 
                 }                  }
                 /* fatal on snapshot block device */                  /* fatal on snapshot block device */
                 if (bs == bs1)                  if (bs == bs1)
                     goto the_end;                      return 0;
             }              }
         }          }
     }      }
Line 1197  void do_loadvm(Monitor *mon, const char  Line 1784  void do_loadvm(Monitor *mon, const char 
     /* Don't even try to load empty VM states */      /* Don't even try to load empty VM states */
     ret = bdrv_snapshot_find(bs, &sn, name);      ret = bdrv_snapshot_find(bs, &sn, name);
     if ((ret >= 0) && (sn.vm_state_size == 0))      if ((ret >= 0) && (sn.vm_state_size == 0))
         goto the_end;          return -EINVAL;
   
     /* restore the VM state */      /* restore the VM state */
     f = qemu_fopen_bdrv(bs, 0);      f = qemu_fopen_bdrv(bs, 0);
     if (!f) {      if (!f) {
         monitor_printf(mon, "Could not open VM state file\n");          monitor_printf(mon, "Could not open VM state file\n");
         goto the_end;          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);          monitor_printf(mon, "Error %d while loading VM state\n", ret);
           return ret;
     }      }
  the_end:      return 0;
     if (saved_vm_running)  
         vm_start();  
 }  }
   
 void do_delvm(Monitor *mon, const char *name)  void do_delvm(Monitor *mon, const QDict *qdict)
 {  {
       DriveInfo *dinfo;
     BlockDriverState *bs, *bs1;      BlockDriverState *bs, *bs1;
     int i, ret;      int ret;
       const char *name = qdict_get_str(qdict, "name");
   
     bs = get_bs_snapshots();      bs = get_bs_snapshots();
     if (!bs) {      if (!bs) {
Line 1226  void do_delvm(Monitor *mon, const char * Line 1814  void do_delvm(Monitor *mon, const char *
         return;          return;
     }      }
   
     for(i = 0; i <= nb_drives; i++) {      QTAILQ_FOREACH(dinfo, &drives, next) {
         bs1 = drives_table[i].bdrv;          bs1 = dinfo->bdrv;
         if (bdrv_has_snapshot(bs1)) {          if (bdrv_has_snapshot(bs1)) {
             ret = bdrv_snapshot_delete(bs1, name);              ret = bdrv_snapshot_delete(bs1, name);
             if (ret < 0) {              if (ret < 0) {
Line 1245  void do_delvm(Monitor *mon, const char * Line 1833  void do_delvm(Monitor *mon, const char *
   
 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;
     int nb_sns, i;      int nb_sns, i;
Line 1256  void do_info_snapshots(Monitor *mon) Line 1845  void do_info_snapshots(Monitor *mon)
         return;          return;
     }      }
     monitor_printf(mon, "Snapshot devices:");      monitor_printf(mon, "Snapshot devices:");
     for(i = 0; i <= nb_drives; i++) {      QTAILQ_FOREACH(dinfo, &drives, next) {
         bs1 = drives_table[i].bdrv;          bs1 = dinfo->bdrv;
         if (bdrv_has_snapshot(bs1)) {          if (bdrv_has_snapshot(bs1)) {
             if (bs == bs1)              if (bs == bs1)
                 monitor_printf(mon, " %s", bdrv_get_device_name(bs1));                  monitor_printf(mon, " %s", bdrv_get_device_name(bs1));

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


unix.superglobalmegacorp.com