qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: nikita.lapshin@openvz.org
To: qemu-devel@nongnu.org
Cc: den@virtuozzo.com, andrey.drobyshev@virtuozzo.com,
	quintela@redhat.com, dgilbert@redhat.com,
	nikita.lapshin@openvz.org
Subject: [PATCH v3 14/17] migration/snpashot: Implement API for RAMBlock
Date: Thu, 16 Jun 2022 13:28:08 +0300	[thread overview]
Message-ID: <20220616102811.219007-15-nikita.lapshin@openvz.org> (raw)
In-Reply-To: <20220616102811.219007-1-nikita.lapshin@openvz.org>

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



  parent reply	other threads:[~2022-06-16 10:49 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-16 10:27 [PATCH v3 00/17] migration/snapshot: External snapshot utility nikita.lapshin
2022-06-16 10:27 ` [PATCH v3 01/17] migration: Implemented new parameter stream_content nikita.lapshin
2022-06-16 10:27 ` [PATCH v3 02/17] migration: should_skip() implemented nikita.lapshin
2022-06-16 10:27 ` [PATCH v3 03/17] migration: Add vmstate part of migration stream nikita.lapshin
2022-06-16 10:27 ` [PATCH v3 04/17] migration: Add dirty-bitmaps " nikita.lapshin
2022-06-16 10:27 ` [PATCH v3 05/17] migration: Add block " nikita.lapshin
2022-06-16 10:28 ` [PATCH v3 06/17] migration: Add RAM " nikita.lapshin
2022-06-16 10:28 ` [PATCH v3 07/17] migration: analyze-migration script changed nikita.lapshin
2022-06-16 10:28 ` [PATCH v3 08/17] migration: Test for RAM and vmstate parts nikita.lapshin
2022-06-16 10:28 ` [PATCH v3 09/17] migration/snapshot: Introduce qemu-snapshot tool nikita.lapshin
2022-06-16 10:28 ` [PATCH v3 10/17] migration/snapshot: Build changes for qemu-snapshot-tool nikita.lapshin
2022-06-16 10:28 ` [PATCH v3 11/17] migration/qemu-file: Fix qemu_ftell() for non-writable file nikita.lapshin
2022-06-16 11:20   ` Daniel P. Berrangé
2022-06-16 12:54     ` Nikita
2022-06-16 10:28 ` [PATCH v3 12/17] migration/snapshot: Move RAM_SAVE_FLAG_xxx defines to migration/ram.h nikita.lapshin
2022-06-16 10:28 ` [PATCH v3 13/17] migration/snapshot: Block layer support in qemu-snapshot nikita.lapshin
2022-06-16 10:28 ` nikita.lapshin [this message]
2022-06-16 10:28 ` [PATCH v3 15/17] migration/snapshot: Save part implement nikita.lapshin
2022-06-16 10:28 ` [PATCH v3 16/17] migration/snapshot: Precopy load implemented nikita.lapshin
2022-06-16 10:28 ` [PATCH v3 17/17] migration/snapshot: Postcopy " nikita.lapshin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220616102811.219007-15-nikita.lapshin@openvz.org \
    --to=nikita.lapshin@openvz.org \
    --cc=andrey.drobyshev@virtuozzo.com \
    --cc=den@virtuozzo.com \
    --cc=dgilbert@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=quintela@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).