]> git.proxmox.com Git - qemu.git/blobdiff - savevm.c
tcg-sparc: Use TCG_TARGET_REG_BITS in conditional compilation.
[qemu.git] / savevm.c
index 74f2c66d298cb9c446f9c8f885a6789902cc366e..aefe052cd3b691072887b49468c78512d1c967ff 100644 (file)
--- a/savevm.c
+++ b/savevm.c
 #include <sys/select.h>
 #ifdef CONFIG_BSD
 #include <sys/stat.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 #include <libutil.h>
 #else
 #include <util.h>
 #endif
-#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
-#include <freebsd/stdlib.h>
-#else
 #ifdef __linux__
 #include <pty.h>
 #include <malloc.h>
@@ -123,24 +120,24 @@ static int announce_self_create(uint8_t *buf,
     return 60; /* len (FCS will be added by hardware) */
 }
 
-static void qemu_announce_self_once(void *opaque)
+static void qemu_announce_self_iter(NICState *nic, void *opaque)
 {
-    int i, len;
-    VLANState *vlan;
-    VLANClientState *vc;
     uint8_t buf[60];
+    int len;
+
+    len = announce_self_create(buf, nic->conf->macaddr.a);
+
+    qemu_send_packet_raw(&nic->nc, buf, len);
+}
+
+
+static void qemu_announce_self_once(void *opaque)
+{
     static int count = SELF_ANNOUNCE_ROUNDS;
     QEMUTimer *timer = *(QEMUTimer **)opaque;
 
-    for (i = 0; i < MAX_NICS; i++) {
-        if (!nd_table[i].used)
-            continue;
-        len = announce_self_create(buf, nd_table[i].macaddr);
-        vlan = nd_table[i].vlan;
-        QTAILQ_FOREACH(vc, &vlan->clients, next) {
-            qemu_send_packet_raw(vc, buf, len);
-        }
-    }
+    qemu_foreach_nic(qemu_announce_self_iter, NULL);
+
     if (--count) {
         /* delay 50ms, 150ms, 250ms, ... */
         qemu_mod_timer(timer, qemu_get_clock(rt_clock) +
@@ -169,6 +166,7 @@ struct QEMUFile {
     QEMUFileCloseFunc *close;
     QEMUFileRateLimit *rate_limit;
     QEMUFileSetRateLimit *set_rate_limit;
+    QEMUFileGetRateLimit *get_rate_limit;
     void *opaque;
     int is_write;
 
@@ -264,9 +262,11 @@ QEMUFile *qemu_popen(FILE *stdio_file, const char *mode)
     s->stdio_file = stdio_file;
 
     if(mode[0] == 'r') {
-        s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_pclose, NULL, NULL);
+        s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_pclose, 
+                                NULL, NULL, NULL);
     } else {
-        s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_pclose, NULL, NULL);
+        s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_pclose, 
+                                NULL, NULL, NULL);
     }
     return s->file;
 }
@@ -311,9 +311,11 @@ QEMUFile *qemu_fdopen(int fd, const char *mode)
         goto fail;
 
     if(mode[0] == 'r') {
-        s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose, NULL, NULL);
+        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);
+        s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose, 
+                                NULL, NULL, NULL);
     }
     return s->file;
 
@@ -327,7 +329,8 @@ QEMUFile *qemu_fopen_socket(int fd)
     QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
 
     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;
 }
 
@@ -363,11 +366,13 @@ QEMUFile *qemu_fopen(const char *filename, const char *mode)
     s->stdio_file = fopen(filename, mode);
     if (!s->stdio_file)
         goto fail;
-
+    
     if(mode[0] == 'w') {
-        s->file = qemu_fopen_ops(s, file_put_buffer, NULL, stdio_fclose, NULL, NULL);
+        s->file = qemu_fopen_ops(s, file_put_buffer, NULL, stdio_fclose, 
+                                NULL, NULL, NULL);
     } else {
-        s->file = qemu_fopen_ops(s, NULL, file_get_buffer, stdio_fclose, NULL, NULL);
+        s->file = qemu_fopen_ops(s, NULL, file_get_buffer, stdio_fclose, 
+                              NULL, NULL, NULL);
     }
     return s->file;
 fail:
@@ -395,15 +400,17 @@ static int bdrv_fclose(void *opaque)
 static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
 {
     if (is_writable)
-        return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose, NULL, NULL);
-    return qemu_fopen_ops(bs, NULL, block_get_buffer, bdrv_fclose, NULL, NULL);
+        return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose, 
+                             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,
                          QEMUFileGetBufferFunc *get_buffer,
                          QEMUFileCloseFunc *close,
                          QEMUFileRateLimit *rate_limit,
-                         QEMUFileSetRateLimit *set_rate_limit)
+                         QEMUFileSetRateLimit *set_rate_limit,
+                         QEMUFileGetRateLimit *get_rate_limit)
 {
     QEMUFile *f;
 
@@ -415,6 +422,7 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
     f->close = close;
     f->rate_limit = rate_limit;
     f->set_rate_limit = set_rate_limit;
+    f->get_rate_limit = get_rate_limit;
     f->is_write = 0;
 
     return f;
@@ -592,6 +600,14 @@ int qemu_file_rate_limit(QEMUFile *f)
     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)
 {
     /* any failed or completed migration keeps its state to allow probing of
@@ -943,13 +959,27 @@ const VMStateInfo vmstate_info_buffer = {
 
 static int get_unused_buffer(QEMUFile *f, void *pv, size_t size)
 {
-    qemu_fseek(f, size, SEEK_CUR);
-    return 0;
+    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)
 {
-    qemu_fseek(f, size, SEEK_CUR);
+    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 = {
@@ -964,6 +994,7 @@ typedef struct SaveStateEntry {
     int instance_id;
     int version_id;
     int section_id;
+    SaveSetParamsHandler *set_params;
     SaveLiveStateHandler *save_live_state;
     SaveStateHandler *save_state;
     LoadStateHandler *load_state;
@@ -971,6 +1002,7 @@ typedef struct SaveStateEntry {
     void *opaque;
 } SaveStateEntry;
 
+
 static QTAILQ_HEAD(savevm_handlers, SaveStateEntry) savevm_handlers =
     QTAILQ_HEAD_INITIALIZER(savevm_handlers);
 static int global_section_id;
@@ -996,6 +1028,7 @@ static int calculate_new_instance_id(const char *idstr)
 int register_savevm_live(const char *idstr,
                          int instance_id,
                          int version_id,
+                         SaveSetParamsHandler *set_params,
                          SaveLiveStateHandler *save_live_state,
                          SaveStateHandler *save_state,
                          LoadStateHandler *load_state,
@@ -1003,10 +1036,11 @@ int register_savevm_live(const char *idstr,
 {
     SaveStateEntry *se;
 
-    se = qemu_malloc(sizeof(SaveStateEntry));
+    se = qemu_mallocz(sizeof(SaveStateEntry));
     pstrcpy(se->idstr, sizeof(se->idstr), idstr);
     se->version_id = version_id;
     se->section_id = global_section_id++;
+    se->set_params = set_params;
     se->save_live_state = save_live_state;
     se->save_state = save_state;
     se->load_state = load_state;
@@ -1031,7 +1065,7 @@ int register_savevm(const char *idstr,
                     void *opaque)
 {
     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)
@@ -1051,7 +1085,7 @@ int vmstate_register(int instance_id, const VMStateDescription *vmsd,
 {
     SaveStateEntry *se;
 
-    se = qemu_malloc(sizeof(SaveStateEntry));
+    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++;
@@ -1109,7 +1143,14 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
              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) {
@@ -1118,10 +1159,10 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                 n_elems = *(uint16_t *)(opaque+field->num_offset);
             }
             if (field->flags & VMS_POINTER) {
-                base_addr = *(void **)base_addr;
+                base_addr = *(void **)base_addr + field->start;
             }
             for (i = 0; i < n_elems; i++) {
-                void *addr = base_addr + field->size * i;
+                void *addr = base_addr + size * i;
 
                 if (field->flags & VMS_ARRAY_OF_POINTER) {
                     addr = *(void **)addr;
@@ -1129,7 +1170,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                 if (field->flags & VMS_STRUCT) {
                     ret = vmstate_load_state(f, field->vmsd, addr, field->vmsd->version_id);
                 } else {
-                    ret = field->info->get(f, addr, field->size);
+                    ret = field->info->get(f, addr, size);
 
                 }
                 if (ret < 0) {
@@ -1158,7 +1199,14 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
             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) {
@@ -1167,15 +1215,18 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
                 n_elems = *(uint16_t *)(opaque+field->num_offset);
             }
             if (field->flags & VMS_POINTER) {
-                base_addr = *(void **)base_addr;
+                base_addr = *(void **)base_addr + field->start;
             }
             for (i = 0; i < n_elems; i++) {
-                void *addr = base_addr + field->size * 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, field->size);
+                    field->info->put(f, addr, size);
                 }
             }
         }
@@ -1213,10 +1264,18 @@ static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
 #define QEMU_VM_SECTION_END          0x03
 #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;
 
+    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_VERSION);
 
@@ -1238,16 +1297,18 @@ int qemu_savevm_state_begin(QEMUFile *f)
         qemu_put_be32(f, se->instance_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 0;
 }
 
-int qemu_savevm_state_iterate(QEMUFile *f)
+int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
 {
     SaveStateEntry *se;
     int ret = 1;
@@ -1260,19 +1321,28 @@ int qemu_savevm_state_iterate(QEMUFile *f)
         qemu_put_byte(f, QEMU_VM_SECTION_PART);
         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)
         return 1;
 
-    if (qemu_file_has_error(f))
+    if (qemu_file_has_error(f)) {
+        qemu_savevm_state_cancel(mon, f);
         return -EIO;
+    }
 
     return 0;
 }
 
-int qemu_savevm_state_complete(QEMUFile *f)
+int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
 {
     SaveStateEntry *se;
 
@@ -1284,7 +1354,7 @@ int qemu_savevm_state_complete(QEMUFile *f)
         qemu_put_byte(f, QEMU_VM_SECTION_END);
         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);
     }
 
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
@@ -1316,7 +1386,18 @@ int qemu_savevm_state_complete(QEMUFile *f)
     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 ret;
@@ -1326,17 +1407,17 @@ int qemu_savevm_state(QEMUFile *f)
 
     bdrv_flush_all();
 
-    ret = qemu_savevm_state_begin(f);
+    ret = qemu_savevm_state_begin(mon, f, 0, 0);
     if (ret < 0)
         goto out;
 
     do {
-        ret = qemu_savevm_state_iterate(f);
+        ret = qemu_savevm_state_iterate(mon, f);
         if (ret < 0)
             goto out;
     } while (ret == 0);
 
-    ret = qemu_savevm_state_complete(f);
+    ret = qemu_savevm_state_complete(mon, f);
 
 out:
     if (qemu_file_has_error(f))
@@ -1625,7 +1706,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
         monitor_printf(mon, "Could not open VM state file\n");
         goto the_end;
     }
-    ret = qemu_savevm_state(f);
+    ret = qemu_savevm_state(mon, f);
     vm_state_size = qemu_ftell(f);
     qemu_fclose(f);
     if (ret < 0) {