[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v3 3/7][RESEND PATCH] bitmap dump code via QAPI fram
From: |
Sanidhya Kashyap |
Subject: |
[Qemu-devel] [PATCH v3 3/7][RESEND PATCH] bitmap dump code via QAPI framework with runstates |
Date: |
Thu, 12 Jun 2014 17:17:12 +0530 |
Reformatted the code and added the functionality of dumping the blocks' info
which can be read by the user when required. I have also made the block name
length global.
Signed-off-by: Sanidhya Kashyap <address@hidden>
---
include/exec/cpu-all.h | 3 +-
migration.c | 7 ++
qapi-schema.json | 18 +++
qmp-commands.hx | 33 +++++
savevm.c | 325 +++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 385 insertions(+), 1 deletion(-)
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index e8363d7..9e6d903 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -301,6 +301,7 @@ extern ram_addr_t ram_size;
/* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */
#define RAM_PREALLOC_MASK (1 << 0)
+#define RAMBLOCK_NAME_LENGTH (1<<8)
typedef struct RAMBlock {
struct MemoryRegion *mr;
@@ -308,7 +309,7 @@ typedef struct RAMBlock {
ram_addr_t offset;
ram_addr_t length;
uint32_t flags;
- char idstr[256];
+ char idstr[RAMBLOCK_NAME_LENGTH];
/* Reads can take either the iothread or the ramlist lock.
* Writes must take both locks.
*/
diff --git a/migration.c b/migration.c
index 3fc03d6..d91dd4c 100644
--- a/migration.c
+++ b/migration.c
@@ -436,6 +436,13 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
return;
}
+ if (runstate_check(RUN_STATE_DUMP_BITMAP)) {
+ error_setg(errp, "bitmap dump in progress");
+ return;
+ }
+
+ runstate_set(RUN_STATE_MIGRATE);
+
s = migrate_init(¶ms);
if (strstart(uri, "tcp:", &p)) {
diff --git a/qapi-schema.json b/qapi-schema.json
index f9c75f9..aa78540 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3082,3 +3082,21 @@
'btn' : 'InputBtnEvent',
'rel' : 'InputMoveEvent',
'abs' : 'InputMoveEvent' } }
+
+##
+# @log-dirty-bitmap
+#
+# dumps the dirty bitmap to a file by logging the
+# memory for a specified number of times with a
+# a defined time differnce
+#
+# @filename: name of the file in which the bitmap will be saved.
+# @epochs: number of times the memory will be logged.
+# @frequency: time difference in milliseconds between each epoch.
+#
+# Since 2.1
+##
+{ 'command' : 'log-dirty-bitmap',
+ 'data' : { 'filename' : 'str',
+ '*epochs' : 'int',
+ '*frequency' : 'int' } }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index d8aa4ed..183a636 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3572,3 +3572,36 @@ Example:
} } ] }
EQMP
+
+ {
+ .name = "log-dirty-bitmap",
+ .args_type = "filename:s,epochs:i?,frequency:i?,readable:-r?",
+ .mhandler.cmd_new = qmp_marshal_input_log_dirty_bitmap,
+ },
+
+SQMP
+log-dirty-bitmap
+--------------------
+
+start logging the memory of the VM for writable working set
+
+Arguments:
+
+- "filename": name of the file, in which the bitmap will be saved
+- "epochs": number of times, the memory will be logged
+- "frequency": time difference in milliseconds between each epoch
+
+Examples:
+-> { "execute" : "log-dirty-bitmap",
+ "arguments" : {
+ "filename" : "/tmp/fileXXX",
+ "epochs" : 3,
+ "frequency" : 10 } }
+
+<- { "return": {} }
+
+Note: The epochs, frequency and readable are optional. epochs default
+value is 3 while that of frequency is 10.
+
+EQMP
+
diff --git a/savevm.c b/savevm.c
index da8aa24..23ba44f 100644
--- a/savevm.c
+++ b/savevm.c
@@ -41,6 +41,9 @@
#include "qemu/iov.h"
#include "block/snapshot.h"
#include "block/qapi.h"
+#include "exec/address-spaces.h"
+#include "exec/ram_addr.h"
+#include "qemu/bitmap.h"
#define SELF_ANNOUNCE_ROUNDS 5
@@ -1002,6 +1005,328 @@ void do_savevm(Monitor *mon, const QDict *qdict)
}
}
+/*
+ * Adding the functionality of continuous logging of the
+ * dirty bitmap which is almost similar to the migration
+ * thread
+ */
+
+enum {
+ LOG_BITMAP_STATE_ERROR = -1,
+ LOG_BITMAP_STATE_NONE,
+ LOG_BITMAP_STATE_SETUP,
+ LOG_BITMAP_STATE_ACTIVE,
+ LOG_BITMAP_STATE_CANCELING,
+ LOG_BITMAP_STATE_COMPLETED
+};
+
+typedef struct BitmapLogState BitmapLogState;
+static unsigned long *logging_bitmap;
+static int64_t MIN_EPOCH_VALUE = 3;
+static int64_t MIN_FREQUENCY_VALUE = 10;
+static int64_t MAX_EPOCH_VALUE = 100000;
+static int64_t MAX_FREQUENCY_VALUE = 100000;
+
+struct BitmapLogState {
+ int state;
+ int fd;
+ int64_t current_frequency;
+ int64_t total_epochs;
+ QemuThread thread;
+};
+
+/*
+ * helper functions
+ */
+
+static inline void logging_lock(void)
+{
+ qemu_mutex_lock_iothread();
+ qemu_mutex_lock_ramlist();
+}
+
+static inline void logging_unlock(void)
+{
+ qemu_mutex_unlock_ramlist();
+ qemu_mutex_unlock_iothread();
+}
+
+static inline void logging_bitmap_set_dirty(ram_addr_t addr)
+{
+ int nr = addr >> TARGET_PAGE_BITS;
+ set_bit(nr, logging_bitmap);
+}
+
+static bool logging_state_set_status(BitmapLogState *b,
+ int old_state,
+ int new_state)
+{
+ return atomic_cmpxchg(&b->state, old_state, new_state);
+}
+
+static inline bool value_in_range(int64_t value, int64_t min_value,
+ int64_t max_value, const char *str,
+ Error **errp)
+{
+ if (value < min_value) {
+ error_setg(errp, "%s's value must be greater than %ld",
+ str, min_value);
+ return false;
+ }
+ if (value > max_value) {
+ error_setg(errp, "%s's value must be less than %ld",
+ str, max_value);
+ return false;
+ }
+ return true;
+}
+
+/*
+ * inspired from migration mechanism
+ */
+
+static BitmapLogState *logging_current_state(void)
+{
+ static BitmapLogState current_bitmaplogstate = {
+ .state = LOG_BITMAP_STATE_NONE,
+ };
+
+ return ¤t_bitmaplogstate;
+}
+
+/*
+ * syncing the logging_bitmap with the ram_list dirty bitmap
+ */
+
+static void dirty_bitmap_sync(void)
+{
+ RAMBlock *block;
+ address_space_sync_dirty_bitmap(&address_space_memory);
+ QTAILQ_FOREACH(block, &ram_list.blocks, next) {
+ qemu_bitmap_sync_range(block->mr->ram_addr, block->length,
+ logging_bitmap, false);
+ }
+}
+
+static inline void logging_bitmap_close(BitmapLogState *b)
+{
+ logging_lock();
+ memory_global_dirty_log_stop();
+ logging_unlock();
+
+ g_free(logging_bitmap);
+ logging_bitmap = NULL;
+ qemu_close(b->fd);
+ b->fd = -1;
+}
+
+static bool ram_block_info_dump(int fd)
+{
+ int64_t ram_bitmap_pages = last_ram_offset() >> TARGET_PAGE_BITS;
+ int block_count = 0;
+ RAMBlock *block;
+ int ret;
+
+ if (qemu_write_full(fd, &ram_bitmap_pages, sizeof(int64_t)) < 0) {
+ return true;
+ }
+
+ QTAILQ_FOREACH(block, &ram_list.blocks, next) {
+ block_count++;
+ }
+
+ ret = qemu_write_full(fd, &block_count, sizeof(int));
+ if (ret < sizeof(int)) {
+ return true;
+ }
+
+ QTAILQ_FOREACH(block, &ram_list.blocks, next) {
+ ret = qemu_write_full(fd, &(block->idstr), sizeof(char) *
+ RAMBLOCK_NAME_LENGTH);
+ if (ret < sizeof(char) * RAMBLOCK_NAME_LENGTH) {
+ return true;
+ }
+ ret = qemu_write_full(fd, &(block->offset), sizeof(ram_addr_t));
+ if (ret < sizeof(ram_addr_t)) {
+ return true;
+ }
+ ret = qemu_write_full(fd, &(block->length), sizeof(ram_addr_t));
+ if (ret < sizeof(ram_addr_t)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void logging_state_update_status(BitmapLogState *b)
+{
+ switch (b->state) {
+ case LOG_BITMAP_STATE_ACTIVE:
+ logging_state_set_status(b, LOG_BITMAP_STATE_ACTIVE,
+ LOG_BITMAP_STATE_COMPLETED);
+ return;
+ case LOG_BITMAP_STATE_CANCELING:
+ logging_state_set_status(b, LOG_BITMAP_STATE_CANCELING,
+ LOG_BITMAP_STATE_COMPLETED);
+ return;
+ case LOG_BITMAP_STATE_ERROR:
+ logging_state_set_status(b, LOG_BITMAP_STATE_ERROR,
+ LOG_BITMAP_STATE_COMPLETED);
+ }
+ return;
+}
+
+static void *bitmap_logging_thread(void *opaque)
+{
+ /*
+ * setup basic structures
+ */
+
+ BitmapLogState *b = opaque;
+ int fd = b->fd;
+ int64_t epoch_count = 0;
+ int64_t total_epochs = b->total_epochs;
+ int64_t ram_bitmap_pages = last_ram_offset() >> TARGET_PAGE_BITS;
+ size_t bitmap_size = BITS_TO_LONGS(ram_bitmap_pages) *
+ sizeof(unsigned long);
+ int ret;
+ char marker = 'M';
+
+ logging_state_set_status(b, LOG_BITMAP_STATE_NONE,
+ LOG_BITMAP_STATE_SETUP);
+
+ logging_bitmap = bitmap_new(ram_bitmap_pages);
+
+ if (logging_bitmap == NULL) {
+ b->state = LOG_BITMAP_STATE_ERROR;
+ goto log_thread_end;
+ }
+
+ logging_state_set_status(b, LOG_BITMAP_STATE_SETUP,
+ LOG_BITMAP_STATE_ACTIVE);
+ /*
+ * start the logging period
+ */
+ logging_lock();
+ memory_global_dirty_log_start();
+ dirty_bitmap_sync();
+ bitmap_zero(logging_bitmap, ram_bitmap_pages);
+ logging_unlock();
+
+ if (ram_block_info_dump(fd)) {
+ b->state = LOG_BITMAP_STATE_ERROR;
+ goto log_thread_end;
+ }
+
+ /*
+ * sync the dirty bitmap along with saving it
+ * using the FILE pointer f.
+ */
+ while (epoch_count < total_epochs) {
+ if (!runstate_check(RUN_STATE_DUMP_BITMAP) ||
+ b->state != LOG_BITMAP_STATE_ACTIVE) {
+ goto log_thread_end;
+ }
+ bitmap_zero(logging_bitmap, ram_bitmap_pages);
+ logging_lock();
+ dirty_bitmap_sync();
+ logging_unlock();
+
+ ret = qemu_write_full(fd, logging_bitmap, bitmap_size);
+ if (ret < bitmap_size) {
+ b->state = LOG_BITMAP_STATE_ERROR;
+ goto log_thread_end;
+ }
+
+ ret = qemu_write_full(fd, &marker, sizeof(char));
+ if (ret < sizeof(char)) {
+ b->state = LOG_BITMAP_STATE_ERROR;
+ goto log_thread_end;
+ }
+ g_usleep(b->current_frequency * 1000);
+ epoch_count++;
+ }
+
+ /*
+ * stop the logging period.
+ */
+ log_thread_end:
+ logging_bitmap_close(b);
+ logging_state_update_status(b);
+ runstate_set(RUN_STATE_RUNNING);
+ return NULL;
+}
+
+void qmp_log_dirty_bitmap(const char *filename, bool has_epochs,
+ int64_t epochs, bool has_frequency,
+ int64_t frequency, Error **errp)
+{
+ int fd = -1;
+ BitmapLogState *b = logging_current_state();
+ Error *local_err = NULL;
+ if (runstate_check(RUN_STATE_DUMP_BITMAP) ||
+ b->state == LOG_BITMAP_STATE_ACTIVE ||
+ b->state == LOG_BITMAP_STATE_SETUP ||
+ b->state == LOG_BITMAP_STATE_CANCELING) {
+ error_setg(errp, "dirty bitmap dump in progress");
+ return;
+ }
+
+ if (!runstate_is_running()) {
+ error_setg(errp, "Guest is not in a running state");
+ return;
+ }
+
+ runstate_set(RUN_STATE_DUMP_BITMAP);
+ b->state = LOG_BITMAP_STATE_NONE;
+
+ /*
+ * checking the epoch range
+ */
+ if (!has_epochs) {
+ b->total_epochs = MIN_EPOCH_VALUE;
+ } else if (!value_in_range(epochs, MIN_EPOCH_VALUE,
+ MAX_EPOCH_VALUE, "epoch", &local_err)) {
+ if (local_err) {
+ error_propagate(errp, local_err);
+ }
+ runstate_set(RUN_STATE_RUNNING);
+ return;
+ } else {
+ b->total_epochs = epochs;
+ }
+
+ /*
+ * checking the frequency range
+ */
+ if (!has_frequency) {
+ b->current_frequency = MIN_FREQUENCY_VALUE;
+ } else if (!value_in_range(frequency, MIN_FREQUENCY_VALUE,
+ MAX_FREQUENCY_VALUE, "frequency", &local_err)) {
+ if (local_err) {
+ error_propagate(errp, local_err);
+ }
+ runstate_set(RUN_STATE_RUNNING);
+ return;
+ } else {
+ b->current_frequency = frequency;
+ }
+
+ fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR);
+ if (fd < 0) {
+ error_setg_file_open(errp, errno, filename);
+ runstate_set(RUN_STATE_RUNNING);
+ return;
+ }
+
+ b->fd = fd;
+ qemu_thread_create(&b->thread, "dirty-bitmap-dump",
+ bitmap_logging_thread, b,
+ QEMU_THREAD_JOINABLE);
+
+ return;
+}
+
void qmp_xen_save_devices_state(const char *filename, Error **errp)
{
QEMUFile *f;
--
1.9.3
- [Qemu-devel] [PATCH v3 0/7] Obtain dirty bitmap via VM logging, Sanidhya Kashyap, 2014/06/12
- [Qemu-devel] [PATCH v3 1/7] enable sharing of the function between migration and bitmap dump, Sanidhya Kashyap, 2014/06/12
- [Qemu-devel] [PATCH v3 2/7] RunState: added two new flags for bitmap dump and migration process, Sanidhya Kashyap, 2014/06/12
- [Qemu-devel] [PATCH v3 3/7] bitmap dump code via QAPI framework with runstates, Sanidhya Kashyap, 2014/06/12
- [Qemu-devel] [PATCH v3 4/7] hmp interface for dirty bitmap dump, Sanidhya Kashyap, 2014/06/12
- [Qemu-devel] [PATCH v3 5/7] cancel mechanism for an already running dump bitmap process, Sanidhya Kashyap, 2014/06/12
- [Qemu-devel] [PATCH v3 7/7] python script for extracting bitmap from a binary file, Sanidhya Kashyap, 2014/06/12
- [Qemu-devel] [PATCH v3 6/7] set the frequency of the dump bitmap process, Sanidhya Kashyap, 2014/06/12
- [Qemu-devel] [PATCH v3 3/7][RESEND PATCH] bitmap dump code via QAPI framework with runstates,
Sanidhya Kashyap <=