qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3 14/17] migration/snpashot: Implement API for RAMBlock


From: nikita . lapshin
Subject: [PATCH v3 14/17] migration/snpashot: Implement API for RAMBlock
Date: Thu, 16 Jun 2022 13:28:08 +0300

From: Nikita Lapshin <nikita.lapshin@openvz.org>

Implemented RAMBlock is used for managing ram block from VM.
This structure is close to existing RAMBlock in migration but
has few differences.

May be it should be replaced with existing RAMBlock it can lead to
lots of reuses.

Signed-off-by: Nikita Lapshin <nikita.lapshin@openvz.org>
---
 migration/qemu-snapshot.c | 180 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 180 insertions(+)

diff --git a/migration/qemu-snapshot.c b/migration/qemu-snapshot.c
index f7695e75c7..394c6acb77 100644
--- a/migration/qemu-snapshot.c
+++ b/migration/qemu-snapshot.c
@@ -23,13 +23,193 @@
 #include "migration/ram.h"
 #include "qemu-snapshot.h"
 
+/* RAM block */
+/* TODO RAMBlock should be replace with existing struct RAMBlock in ram.c */
+typedef struct RAMBlock {
+    int64_t bdrv_offset;        /* Offset on backing storage */
+    int64_t length;             /* Length */
+    int64_t nr_pages;           /* Page count */
+    int64_t nr_slices;          /* Number of slices (for bitmap bookkeeping) */
+    int64_t discard_offset;     /* Used for postcopy dicarding of ram blocks */
+
+    unsigned long *bitmap;      /* Bitmap of RAM slices */
+
+    /* Link into ram_list */
+    QSIMPLEQ_ENTRY(RAMBlock) next;
+
+    char idstr[256];            /* RAM block id string */
+} RAMBlock;
+
 /* RAM transfer context */
 typedef struct RAMCtx {
     int64_t normal_pages;       /* Total number of normal pages */
+
+    /* RAM block list head */
+    QSIMPLEQ_HEAD(, RAMBlock) ram_block_list;
+
 } RAMCtx;
 
 static RAMCtx ram_ctx;
 
+static inline
+bool ram_offset_in_block(RAMBlock *block, int64_t offset)
+{
+    return block && offset < block->length;
+}
+
+static inline
+bool ram_bdrv_offset_in_block(RAMBlock *block, int64_t bdrv_offset)
+{
+    return block && bdrv_offset >= block->bdrv_offset &&
+            bdrv_offset < block->bdrv_offset + block->length;
+}
+
+static inline
+int64_t ram_bdrv_from_block_offset(RAMBlock *block, int64_t offset)
+{
+    if (!ram_offset_in_block(block, offset)) {
+        return INVALID_OFFSET;
+    }
+
+    return block->bdrv_offset + offset;
+}
+
+static inline
+int64_t ram_block_offset_from_bdrv(RAMBlock *block, int64_t bdrv_offset)
+{
+    int64_t offset;
+
+    if (!block) {
+        return INVALID_OFFSET;
+    }
+
+    offset = bdrv_offset - block->bdrv_offset;
+    return offset >= 0 ? offset : INVALID_OFFSET;
+}
+
+static RAMBlock *ram_block_by_idstr(const char *idstr)
+{
+    RAMBlock *block;
+
+    QSIMPLEQ_FOREACH(block, &ram_ctx.ram_block_list, next) {
+        if (!strcmp(idstr, block->idstr)) {
+            return block;
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Assume QEMUFile is migration stream and try to get ram block from it.
+ * Also check if this ram block exists.
+ */
+static RAMBlock *ram_block_from_stream(QEMUFile *f, int flags)
+{
+    static RAMBlock *block;
+    char idstr[256];
+
+    if (flags & RAM_SAVE_FLAG_CONTINUE) {
+        if (!block) {
+            error_report("RAM_SAVE_FLAG_CONTINUE outside RAM block");
+            return NULL;
+        }
+
+        return block;
+    }
+
+    if (!qemu_get_counted_string(f, idstr)) {
+        error_report("Failed to get RAM block name");
+        return NULL;
+    }
+
+    block = ram_block_by_idstr(idstr);
+    if (!block) {
+        error_report("Can't find RAM block %s", idstr);
+        return NULL;
+    }
+
+    return block;
+}
+
+static int64_t ram_block_next_bdrv_offset(void)
+{
+    RAMBlock *last_block;
+    int64_t offset;
+
+    last_block = QSIMPLEQ_LAST(&ram_ctx.ram_block_list, RAMBlock, next);
+    if (!last_block) {
+        return 0;
+    }
+
+    offset = last_block->bdrv_offset + last_block->length;
+    return ROUND_UP(offset, BDRV_CLUSTER_SIZE);
+}
+
+static void ram_block_add(const char *idstr, int64_t size)
+{
+    RAMBlock *block;
+
+    block = g_new0(RAMBlock, 1);
+    block->length = size;
+    block->bdrv_offset = ram_block_next_bdrv_offset();
+    strcpy(block->idstr, idstr);
+
+    QSIMPLEQ_INSERT_TAIL(&ram_ctx.ram_block_list, block, next);
+}
+
+/*
+ * Assume that QEMUFile is migration stream and try to get
+ * from f_src ram blocks list. mem_size is a total amount of bytes of whole
+ * ram blocks.
+ */
+static int ram_block_list_from_stream(QEMUFile *f_src, int64_t mem_size)
+{
+    int64_t total_ram_bytes;
+
+    total_ram_bytes = mem_size;
+    while (total_ram_bytes > 0) {
+        char idstr[256];
+        int64_t size;
+
+        if (!qemu_get_counted_string(f_src, idstr)) {
+            error_report("Failed to get RAM block list");
+            return -EINVAL;
+        }
+
+        size = qemu_get_be64(f_src);
+
+        ram_block_add(idstr, size);
+        total_ram_bytes -= size;
+    }
+
+    if (total_ram_bytes != 0) {
+        error_report("Corrupted RAM block list");
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+/* Send ram block list using migration rule */
+static int ram_block_list_to_stream(QEMUFile *f_dest)
+{
+    RAMBlock *block;
+    uint64_t total = 0;
+
+    QSIMPLEQ_FOREACH(block, &ram_ctx.ram_block_list, next) {
+        total += block->length;
+    }
+    qemu_put_be64(f_dest, total | RAM_SAVE_FLAG_MEM_SIZE);
+
+    QSIMPLEQ_FOREACH(block, &ram_ctx.ram_block_list, next) {
+        qemu_put_counted_string(f_dest, block->idstr);
+        qemu_put_be64(f_dest, block->length);
+    }
+
+    return qemu_file_get_error(f_dest);
+}
+
 int coroutine_fn save_state_main(StateSaveCtx *s)
 {
     /* TODO: implement */
-- 
2.31.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]