# also update debian/changelog
KVMVER=1.3
-KVMPKGREL=15
+KVMPKGREL=16
KVMPACKAGE=pve-qemu-kvm
KVMDIR=qemu-kvm
-pve-qemu-kvm (1.3-15) unstable; urgency=low
+pve-qemu-kvm (1.3-16) unstable; urgency=low
* update backup patches - removed threaded code - we use qemu-aio
instead to avoid problems in bdrv_drain_all().
-From f4a34368cdc254ea7602c5913c50506f61e7652e Mon Sep 17 00:00:00 2001
+From 5a37c10eb0991e86cba666b82ac756dc2ff1cd8c Mon Sep 17 00:00:00 2001
From: Dietmar Maurer <dietmar@proxmox.com>
Date: Tue, 13 Nov 2012 09:24:50 +0100
Subject: [PATCH v3 1/6] RFC: Efficient VM backup for qemu
* BackupDriver: remove cancel_cb
* use enum for BackupFormat
* vma: use bdrv_open instead of bdrv_file_open
-* vma: use extra writer thread
-* backup on drive after another (try to avoid high load)
+* vma: fix aio, use O_DIRECT
+* backup one drive after another (try to avoid high load)
Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
---
-From 4374768a3a4d92f0ac0a77688cb7f65ff108ef83 Mon Sep 17 00:00:00 2001
+From 26891c19f68a14927e8c52417112d80668be1b3a Mon Sep 17 00:00:00 2001
From: Dietmar Maurer <dietmar@proxmox.com>
Date: Tue, 13 Nov 2012 10:03:52 +0100
Subject: [PATCH v3 2/6] add basic backup support to block driver
Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
---
Makefile.objs | 1 +
- backup.c | 334 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ backup.c | 335 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
backup.h | 32 ++++++
block.c | 71 +++++++++++-
block.h | 2 +
blockjob.h | 10 ++
- 6 files changed, 444 insertions(+), 6 deletions(-)
+ 6 files changed, 445 insertions(+), 6 deletions(-)
create mode 100644 backup.c
create mode 100644 backup.h
block-obj-$(CONFIG_WIN32) += event_notifier-win32.o aio-win32.o
diff --git a/backup.c b/backup.c
new file mode 100644
-index 0000000..af511c7
+index 0000000..3ccb74c
--- /dev/null
+++ b/backup.c
-@@ -0,0 +1,334 @@
+@@ -0,0 +1,335 @@
+/*
+ * QEMU backup
+ *
+ while (backup_in_progress_count > 0) {
+ DPRINTF("backup_run backup_in_progress_count != 0 (%d)",
+ backup_in_progress_count);
-+ co_sleep_ns(rt_clock, 10000);
++ block_job_sleep_ns(&job->common, rt_clock, 10000);
++
+ }
+
+ DPRINTF("backup_run complete %d\n", ret);
-From b9c06929cb9e9583b002fa6de76ad3c318c89f35 Mon Sep 17 00:00:00 2001
+From cd593564217e6ae808cc8555845b14eabac95bd0 Mon Sep 17 00:00:00 2001
From: Dietmar Maurer <dietmar@proxmox.com>
Date: Tue, 13 Nov 2012 11:27:56 +0100
Subject: [PATCH v3 3/6] add backup related monitor commands
Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
---
backup.h | 12 ++
- blockdev.c | 412 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ blockdev.c | 419 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
hmp-commands.hx | 31 ++++
hmp.c | 63 ++++++++
hmp.h | 3 +
monitor.c | 7 +
qapi-schema.json | 91 ++++++++++++
qmp-commands.hx | 27 ++++
- 8 files changed, 646 insertions(+), 0 deletions(-)
+ 8 files changed, 653 insertions(+), 0 deletions(-)
diff --git a/backup.h b/backup.h
index a5f85e6..c9c20c9 100644
+
#endif /* QEMU_BACKUP_H */
diff --git a/blockdev.c b/blockdev.c
-index e73fd6e..bd2198e 100644
+index e73fd6e..ba28654 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -20,6 +20,7 @@
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
-@@ -1321,6 +1322,417 @@ void qmp_drive_mirror(const char *device, const char *target,
+@@ -1321,6 +1322,424 @@ void qmp_drive_mirror(const char *device, const char *target,
drive_get_ref(drive_get_by_blockdev(bs));
}
+ error_setg(&backup_state.error, "backup cancelled");
+ }
+
++ /* drain all i/o (awake jobs waiting for aio) */
++ bdrv_drain_all();
++
+ /* we only need to cancel the running job - backup_run_next_job() cancels
+ * the other jobs */
+
++ int job_count = 0;
+ GList *l = backup_state.bcb_list;
+ while (l) {
+ BackupCB *bcb = l->data;
+ l = g_list_next(l);
+ BlockJob *job = bcb->bs->job;
-+ if (!bcb->completed && job) {
-+ block_job_cancel(job);
-+ /* make sure we call the complete callback */
-+ if (!job->co) {
-+ block_job_completed(job, -1);
++ if (job) {
++ job_count++;
++ if (!bcb->completed) {
++ block_job_cancel(job);
++ /* make sure we call the complete callback */
++ if (!job->co) {
++ block_job_completed(job, -1);
++ }
++ break;
+ }
-+ break;
-+ }
++ }
+ }
+
-+ if (!l) { /* all jobs completed */
++ if (job_count == 0) { /* can happen when backup_start_jobs() fails */
+ backup_cleanup();
+ }
+}
-From bb18514bdcb93d9b2906bfb2a8aa9fd6c2265710 Mon Sep 17 00:00:00 2001
+From 2b6ca0c6087ed51bc8318731713bb3aa83f606db Mon Sep 17 00:00:00 2001
From: Dietmar Maurer <dietmar@proxmox.com>
Date: Tue, 13 Nov 2012 11:11:38 +0100
Subject: [PATCH v3 4/6] introduce new vma archive format
Makefile.objs | 2 +-
blockdev.c | 6 +-
docs/specs/vma_spec.txt | 24 ++
- vma-reader.c | 801 +++++++++++++++++++++++++++++++++++++++++
- vma-writer.c | 914 +++++++++++++++++++++++++++++++++++++++++++++++
- vma.c | 561 +++++++++++++++++++++++++++++
+ vma-reader.c | 801 ++++++++++++++++++++++++++++++++++++++++
+ vma-writer.c | 933 +++++++++++++++++++++++++++++++++++++++++++++++
+ vma.c | 561 ++++++++++++++++++++++++++++
vma.h | 145 ++++++++
- 8 files changed, 2452 insertions(+), 4 deletions(-)
+ 8 files changed, 2471 insertions(+), 4 deletions(-)
create mode 100644 docs/specs/vma_spec.txt
create mode 100644 vma-reader.c
create mode 100644 vma-writer.c
block-obj-$(CONFIG_POSIX) += event_notifier-posix.o aio-posix.o
block-obj-$(CONFIG_WIN32) += event_notifier-win32.o aio-win32.o
diff --git a/blockdev.c b/blockdev.c
-index bd2198e..99f3e02 100644
+index ba28654..a030a13 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -21,6 +21,7 @@
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
-@@ -1508,10 +1509,11 @@ char *qmp_backup(const char *backupfile, bool has_format, BackupFormat format,
+@@ -1515,10 +1516,11 @@ char *qmp_backup(const char *backupfile, bool has_format, BackupFormat format,
/* Todo: try to auto-detect format based on file name */
format = has_format ? format : BACKUP_FORMAT_VMA;
+
diff --git a/vma-writer.c b/vma-writer.c
new file mode 100644
-index 0000000..3f5bbd5
+index 0000000..08c4ee3
--- /dev/null
+++ b/vma-writer.c
-@@ -0,0 +1,914 @@
+@@ -0,0 +1,933 @@
+/*
+ * VMA: Virtual Machine Archive
+ *
+
+typedef struct VmaAIOCB VmaAIOCB;
+struct VmaAIOCB {
-+ VmaWriter *vmaw;
+ unsigned char buffer[VMA_MAX_EXTENT_SIZE];
++ VmaWriter *vmaw;
+ size_t bytes;
+ Coroutine *co;
+};
+ int outbuf_count; /* in VMA_BLOCKS */
+ uint64_t outbuf_block_info[VMA_BLOCKS_PER_EXTENT];
+
-+ VmaAIOCB aiocbs[WRITE_BUFFERS];
++ VmaAIOCB *aiocbs[WRITE_BUFFERS];
+ CoQueue wqueue;
+
+ GChecksum *md5csum;
+ qemu_coroutine_enter(vmaw->co_writer, NULL);
+}
+
++static int vma_co_write_finished(void *opaque)
++{
++ VmaWriter *vmaw = opaque;
++
++ return (vmaw->co_writer != 0);
++}
++
+static ssize_t coroutine_fn
+vma_co_write(VmaWriter *vmaw, const void *buf, size_t bytes)
+{
+
+ DPRINTF("vma_co_write enter %zd\n", bytes);
+
++ assert(vmaw->co_writer == NULL);
++
+ while (done < bytes) {
-+ ret = write(vmaw->fd, buf + done, bytes - done);
++ /* Note: we limit maximal write size - else VM gets slow */
++ ret = write(vmaw->fd, buf + done,
++ (bytes - done) > 4096 ? 4096 : bytes - done);
+ if (ret > 0) {
+ done += ret;
+ DPRINTF("vma_co_write written %zd %zd\n", done, ret);
+
+ vmaw->co_writer = qemu_coroutine_self();
+ qemu_aio_set_fd_handler(vmaw->fd, NULL, vma_co_continue_write,
-+ NULL, vmaw);
++ vma_co_write_finished, vmaw);
+
+ qemu_coroutine_yield();
+ DPRINTF("vma_co_write restart %zd\n", done);
+ }
+ }
+
++ vmaw->co_writer = NULL;
++
+ qemu_co_mutex_unlock(&vmaw->writer_lock);
+
+ DPRINTF("vma_co_write leave %zd\n", done);
+ int i;
+ VmaAIOCB *cb = NULL;
+ for (i = 0; i < WRITE_BUFFERS; i++) {
-+ if (vmaw->aiocbs[i].bytes) {
-+ cb = &vmaw->aiocbs[i];
++ if (vmaw->aiocbs[i]->bytes) {
++ cb = vmaw->aiocbs[i];
+ DPRINTF("FOUND USED AIO BUFFER %d %zd\n", i,
-+ vmaw->aiocbs[i].bytes);
++ vmaw->aiocbs[i]->bytes);
+ break;
+ }
+ }
+ while (!cb) {
+ int i;
+ for (i = 0; i < WRITE_BUFFERS; i++) {
-+ if (!vmaw->aiocbs[i].bytes) {
-+ cb = &vmaw->aiocbs[i];
++ if (!vmaw->aiocbs[i]->bytes) {
++ cb = vmaw->aiocbs[i];
+ break;
+ }
+ }
+ goto err;
+ }
+ vmaw->fd = fileno(vmaw->cmd);
-+ socket_set_nonblock(vmaw->fd);
++
++ /* try to use O_NONBLOCK and O_DIRECT */
++ fcntl(vmaw->fd, F_SETFL, fcntl(vmaw->fd, F_GETFL)|O_NONBLOCK);
++ fcntl(vmaw->fd, F_SETFL, fcntl(vmaw->fd, F_GETFL)|O_DIRECT);
+
+ } else {
+ struct stat st;
+ const char *tmp_id_str;
+
+ if ((stat(filename, &st) == 0) && S_ISFIFO(st.st_mode)) {
-+ oflags = O_NONBLOCK|O_WRONLY;
++ oflags = O_NONBLOCK|O_DIRECT|O_WRONLY;
+ vmaw->fd = qemu_open(filename, oflags, 0644);
+ } else if (strstart(filename, "/dev/fdset/", &tmp_id_str)) {
-+ oflags = O_NONBLOCK|O_WRONLY;
++ oflags = O_NONBLOCK|O_DIRECT|O_WRONLY;
+ vmaw->fd = qemu_open(filename, oflags, 0644);
+ } else if (strstart(filename, "/dev/fdname/", &tmp_id_str)) {
+ vmaw->fd = monitor_get_fd(cur_mon, tmp_id_str, errp);
+ if (vmaw->fd < 0) {
+ goto err;
+ }
++ /* try to use O_NONBLOCK and O_DIRECT */
++ fcntl(vmaw->fd, F_SETFL, fcntl(vmaw->fd, F_GETFL)|O_NONBLOCK);
++ fcntl(vmaw->fd, F_SETFL, fcntl(vmaw->fd, F_GETFL)|O_DIRECT);
+ } else {
-+ oflags = O_NONBLOCK|O_WRONLY|O_CREAT|O_EXCL;
++ oflags = O_NONBLOCK|O_DIRECT|O_WRONLY|O_CREAT|O_EXCL;
+ vmaw->fd = qemu_open(filename, oflags, 0644);
+ }
+
+ }
+ }
+
++ /* we use O_DIRECT, so we need to align IO buffers */
++ int i;
++ for (i = 0; i < WRITE_BUFFERS; i++) {
++ vmaw->aiocbs[i] = qemu_memalign(512, sizeof(VmaAIOCB));
++ memset(vmaw->aiocbs[i], 0, sizeof(VmaAIOCB));
++ }
++
+ vmaw->outbuf_count = 0;
+ vmaw->outbuf_pos = VMA_EXTENT_HEADER_SIZE;
+
+ return vmaw->status;
+}
+
-+static int vma_writer_get_buffer(VmaWriter *vmaw, size_t bytes)
++static int vma_writer_get_buffer(VmaWriter *vmaw)
+{
+ int ret = 0;
+
+ return -1;
+ }
+
-+ /* detect block containing zeroes */
-+ int i;
-+ int bit = 1;
-+ uint16_t mask = 0;
-+ size_t real_size = 0;
-+ for (i = 0; i < 16; i++) {
-+ unsigned char *vmablock = buf + (i*VMA_BLOCK_SIZE);
-+ if (!buffer_is_zero(vmablock, VMA_BLOCK_SIZE)) {
-+ mask |= bit;
-+ real_size += VMA_BLOCK_SIZE;
-+ }
-+ bit = bit << 1;
-+ }
-+
+ /* wait until buffer is available */
-+ if (vma_writer_get_buffer(vmaw, real_size) < 0) {
++ if (vma_writer_get_buffer(vmaw) < 0) {
+ vma_writer_set_error(vmaw, "vma_writer_write: "
+ "vma_writer_get_buffer failed");
+ return -1;
+
+ DPRINTF("VMA WRITE %d %zd\n", dev_id, cluster_num);
+
-+ bit = 1;
++ int i;
++ int bit = 1;
++ uint16_t mask = 0;
+ for (i = 0; i < 16; i++) {
+ unsigned char *vmablock = buf + (i*VMA_BLOCK_SIZE);
-+ if (mask & bit) {
++ if (!buffer_is_zero(vmablock, VMA_BLOCK_SIZE)) {
++ mask |= bit;
+ memcpy(vmaw->outbuf + vmaw->outbuf_pos, vmablock, VMA_BLOCK_SIZE);
+ vmaw->outbuf_pos += VMA_BLOCK_SIZE;
+ } else {
+ g_checksum_free(vmaw->md5csum);
+ }
+
++ for (i = 0; i < WRITE_BUFFERS; i++) {
++ free(vmaw->aiocbs[i]);
++ }
++
+ g_free(vmaw);
+}
+
-From 59bc6b7cd95ff518bb415ae49bc3078c145003f3 Mon Sep 17 00:00:00 2001
+From 43cf41bbbb32384d4a51e37868be363a11eda35b Mon Sep 17 00:00:00 2001
From: Dietmar Maurer <dietmar@proxmox.com>
Date: Wed, 14 Nov 2012 09:57:04 +0100
Subject: [PATCH v3 5/6] add regression tests for backup
-From 9901e8c82fb25ce5ce82c9e18276d8190bb4aca7 Mon Sep 17 00:00:00 2001
+From 6f87d124089c383af873d9774d3b47597dc7d5e9 Mon Sep 17 00:00:00 2001
From: Dietmar Maurer <dietmar@proxmox.com>
Date: Thu, 29 Nov 2012 10:46:49 +0100
Subject: [PATCH v3 6/6] add vm state to backups
3 files changed, 200 insertions(+), 5 deletions(-)
diff --git a/blockdev.c b/blockdev.c
-index 99f3e02..cb9293b 100644
+index a030a13..d5878c5 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -22,6 +22,8 @@
} backup_state;
typedef struct BackupCB {
-@@ -1494,10 +1500,170 @@ static void backup_start_jobs(void)
+@@ -1501,10 +1507,170 @@ static void backup_start_jobs(void)
backup_run_next_job();
}
{
BlockDriverState *bs;
Error *local_err = NULL;
-@@ -1506,6 +1672,8 @@ char *qmp_backup(const char *backupfile, bool has_format, BackupFormat format,
+@@ -1513,6 +1679,8 @@ char *qmp_backup(const char *backupfile, bool has_format, BackupFormat format,
gchar **devs = NULL;
GList *bcblist = NULL;
/* Todo: try to auto-detect format based on file name */
format = has_format ? format : BACKUP_FORMAT_VMA;
-@@ -1586,6 +1754,22 @@ char *qmp_backup(const char *backupfile, bool has_format, BackupFormat format,
+@@ -1593,6 +1761,22 @@ char *qmp_backup(const char *backupfile, bool has_format, BackupFormat format,
size_t total = 0;
/* register all devices for vma writer */
l = bcblist;
while (l) {
BackupCB *bcb = l->data;
-@@ -1651,6 +1835,9 @@ char *qmp_backup(const char *backupfile, bool has_format, BackupFormat format,
+@@ -1658,6 +1842,9 @@ char *qmp_backup(const char *backupfile, bool has_format, BackupFormat format,
backup_state.total = total;
backup_state.transferred = 0;
backup_state.zero_bytes = 0;
/* Grab a reference so hotplug does not delete the
* BlockDriverState from underneath us.
-@@ -1662,7 +1849,12 @@ char *qmp_backup(const char *backupfile, bool has_format, BackupFormat format,
+@@ -1669,7 +1856,12 @@ char *qmp_backup(const char *backupfile, bool has_format, BackupFormat format,
drive_get_ref(drive_get_by_blockdev(bcb->bs));
}
vma-writer.c | 296 +++++++++++++++++++++++++++++++++++-----------------------
1 files changed, 180 insertions(+), 116 deletions(-)
-diff --git a/vma-writer.c b/vma-writer.c
-index 688af4b..e18591e 100644
---- a/vma-writer.c
-+++ b/vma-writer.c
-@@ -38,13 +38,20 @@
+Index: new/vma-writer.c
+===================================================================
+--- new.orig/vma-writer.c 2013-01-23 07:35:12.000000000 +0100
++++ new/vma-writer.c 2013-01-23 09:24:19.000000000 +0100
+@@ -37,13 +37,21 @@
#define WRITE_BUFFERS 5
+ GMutex *mutex;
+ GCond *change_cond;
+ WriteBuffer wbuf[WRITE_BUFFERS];
++ CoQueue wqueue;
+} WriterThread;
struct VmaWriter {
int fd;
-@@ -61,8 +68,7 @@ struct VmaWriter {
+@@ -60,8 +68,7 @@
int outbuf_count; /* in VMA_BLOCKS */
uint64_t outbuf_block_info[VMA_BLOCKS_PER_EXTENT];
GChecksum *md5csum;
CoMutex writer_lock;
-@@ -88,6 +94,80 @@ struct VmaWriter {
+@@ -86,6 +93,107 @@
uint32_t config_count;
};
+ while (1) {
+ WriteBuffer *b = NULL;
+
-+ g_mutex_lock(wt->mutex);
++ qemu_mutex_lock_iothread();
+ int i;
+ for (i = 0; i < WRITE_BUFFERS; i++) {
+ if (wt->wbuf[i].bytes) {
+ break;
+ }
+ }
-+ g_mutex_unlock(wt->mutex);
++ qemu_mutex_unlock_iothread();
+
+ if (b) {
+ size_t done = 0;
+ done += ret;
+ } else if (ret < 0) {
+ if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
-+ g_mutex_lock(wt->mutex);
++ qemu_mutex_lock_iothread();
+ wt->error = errno;
-+ g_mutex_unlock(wt->mutex);
++ qemu_mutex_unlock_iothread();
+ break;
+ }
+ } else if (ret == 0) {
+ /* should not happen - simply try again */
+ }
+ }
-+ g_mutex_lock(wt->mutex);
++ qemu_mutex_lock_iothread();
+ b->bytes = 0;
-+ g_mutex_unlock(wt->mutex);
++ DPRINTF("AWAKE JOB %d\n", wt->error);
++ if (wt->error) {
++ for (i = 0; i < WRITE_BUFFERS; i++) {
++ wt->wbuf[i].bytes = 0;
++ }
++ qemu_co_queue_restart_all(&wt->wqueue);
++ } else {
++ qemu_co_queue_next(&wt->wqueue);
++ }
++ qemu_mutex_unlock_iothread();
++ DPRINTF("AWAKE JOB END\n");
+ }
+
+ if (wt->error) {
+ g_mutex_lock(wt->mutex);
+ bool cancel = wt->cancel;
+ if (!b && !cancel) {
++ DPRINTF("WRITER THREAD WAIT FOR DATA\n");
+ g_cond_wait(wt->change_cond, wt->mutex);
++ cancel = wt->cancel;
+ }
+ g_mutex_unlock(wt->mutex);
+
+ if (cancel) {
++ qemu_mutex_lock_iothread();
++ for (i = 0; i < WRITE_BUFFERS; i++) {
++ wt->wbuf[i].bytes = 0;
++ }
++ qemu_co_queue_restart_all(&wt->wqueue);
++ qemu_mutex_unlock_iothread();
+ DPRINTF("END WRITER THREAD\n");
+ g_thread_exit(NULL);
+ }
+{
+ assert(vmaw);
+
++ DPRINTF("vma_stop_writer_thread start\n");
++
+ if (vmaw->wt.thread) {
++ DPRINTF("vma_stop_writer_thread 1\n");
+ g_mutex_lock(vmaw->wt.mutex);
++ DPRINTF("vma_stop_writer_thread 2\n");
+ vmaw->wt.cancel = true;
+ g_cond_signal(vmaw->wt.change_cond);
+ g_mutex_unlock(vmaw->wt.mutex);
++ DPRINTF("vma_stop_writer_thread 3\n");
++ qemu_mutex_unlock_iothread();
+ g_thread_join(vmaw->wt.thread);
++ qemu_mutex_lock_iothread();
++ DPRINTF("vma_stop_writer_thread 4\n");
+ vmaw->wt.thread = NULL;
+ }
++ DPRINTF("vma_stop_writer_thread end\n");
+}
+
void vma_writer_set_error(VmaWriter *vmaw, const char *fmt, ...)
{
va_list ap;
-@@ -215,111 +295,47 @@ int vma_writer_register_stream(VmaWriter *vmaw, const char *devname,
+@@ -213,111 +321,45 @@
return n;
}
int i;
- VmaAIOCB *cb = NULL;
+ WriteBuffer *b = NULL;
-+ g_mutex_lock(vmaw->wt.mutex);
-+
++
+ error = vmaw->wt.error;
+
for (i = 0; i < WRITE_BUFFERS; i++) {
}
}
- if (!cb) {
-+ g_mutex_unlock(vmaw->wt.mutex);
+
+ if (!b || error) {
break;
}
- qemu_co_queue_wait(&vmaw->wqueue);
-+ uint64_t delay_ns = 10000;
-+ DPRINTF("WAIT FOR BUFFER FLUSH %zd\n", delay_ns);
-+ co_sleep_ns(rt_clock, delay_ns);
++ DPRINTF("WAIT FOR BUFFER FLUSH\n");
++ qemu_co_queue_wait(&vmaw->wt.wqueue);
++ DPRINTF("WAIT FOR BUFFER FLUSH END\n");
+ }
+
+ if (error) {
static ssize_t coroutine_fn
vma_queue_write(VmaWriter *vmaw, const void *buf, size_t bytes)
{
-@@ -329,29 +345,46 @@ vma_queue_write(VmaWriter *vmaw, const void *buf, size_t bytes)
+@@ -327,29 +369,42 @@
assert(buf);
assert(bytes <= VMA_MAX_EXTENT_SIZE);
+ int error = 0;
+
+ /* wait for a free output buffer */
-+ g_mutex_lock(vmaw->wt.mutex);
+ WriteBuffer *b = NULL;
+ while (!b) {
+ error = vmaw->wt.error;
+ if (error) {
-+ g_mutex_unlock(vmaw->wt.mutex);
-+ vma_writer_set_error(vmaw, "vma_queue_write error - %s",
++ vma_writer_set_error(vmaw, "vma_queue_write error - %s",
+ strerror(error));
+ return -1;
+ }
- if (!cb) {
- qemu_co_queue_wait(&vmaw->wqueue);
+ if (!b) {
-+ uint64_t delay_ns = 10000;
-+ DPRINTF("WAIT FOR BUFFER %zd\n", delay_ns);
-+ g_mutex_unlock(vmaw->wt.mutex);
-+ co_sleep_ns(rt_clock, delay_ns);
-+ g_mutex_lock(vmaw->wt.mutex);
++ DPRINTF("WAIT FOR BUFFER\n");
++ qemu_co_queue_wait(&vmaw->wt.wqueue);
++ DPRINTF("WAIT FOR BUFFER DONE\n");
}
}
+ /* copy data to output buffer */
+ memcpy(b->buffer, buf, bytes);
+ b->bytes = bytes;
-+
-+ /* signal writer thread that we have new data */
-+ g_cond_signal(vmaw->wt.change_cond);
- DPRINTF("vma_queue_write start %zd\n", bytes);
- cb->co = qemu_coroutine_create(vma_co_writer_task);
- qemu_coroutine_enter(cb->co, cb);
++ g_mutex_lock(vmaw->wt.mutex);
++ /* signal writer thread that we have new data */
++ g_cond_signal(vmaw->wt.change_cond);
+ g_mutex_unlock(vmaw->wt.mutex);
- DPRINTF("vma_queue_write leave\n");
return bytes;
}
-@@ -389,10 +422,10 @@ VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, int64_t speed,
+@@ -386,10 +441,10 @@
const char *tmp_id_str;
if ((stat(filename, &st) == 0) && S_ISFIFO(st.st_mode)) {
vmaw->fd = qemu_open(filename, oflags, 0644);
} else if (strstart(filename, "/dev/fdname/", &tmp_id_str)) {
vmaw->fd = monitor_get_fd(cur_mon, tmp_id_str, errp);
-@@ -400,7 +433,7 @@ VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, int64_t speed,
+@@ -397,7 +452,7 @@
goto err;
}
} else {
vmaw->fd = qemu_open(filename, oflags, 0644);
}
-@@ -418,7 +451,6 @@ VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, int64_t speed,
+@@ -415,10 +470,19 @@
qemu_co_mutex_init(&vmaw->writer_lock);
qemu_co_mutex_init(&vmaw->flush_lock);
- qemu_co_queue_init(&vmaw->wqueue);
++ qemu_co_queue_init(&vmaw->wt.wqueue);
uuid_copy(vmaw->uuid, uuid);
-@@ -428,6 +460,15 @@ VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, int64_t speed,
-
- ratelimit_set_speed(&vmaw->limit, speed, 100000000ULL /* 0.1 sec */);
-
+ vmaw->wt.mutex = g_mutex_new();
+ vmaw->wt.change_cond = g_cond_new();
+ vmaw->wt.fd = vmaw->fd;
return vmaw;
err:
-@@ -442,6 +483,14 @@ err:
+@@ -433,6 +497,14 @@
g_checksum_free(vmaw->md5csum);
}
g_free(vmaw);
}
-@@ -688,6 +737,16 @@ vma_writer_write(VmaWriter *vmaw, uint8_t dev_id, int64_t cluster_num,
+@@ -672,6 +744,14 @@
*zero_bytes = 0;
-+ g_mutex_lock(vmaw->wt.mutex);
+ int error = vmaw->wt.error;
-+ g_mutex_unlock(vmaw->wt.mutex);
+
+ if (error) {
+ vma_writer_set_error(vmaw, "vma_writer_get_buffer write error - %s",
if (vmaw->status < 0) {
return vmaw->status;
}
-@@ -801,11 +860,7 @@ int vma_writer_close(VmaWriter *vmaw, Error **errp)
+@@ -783,14 +863,17 @@
+
+ int i;
++ DPRINTF("vma_writer_close start\n");
vma_queue_flush(vmaw);
-- /* this should not happen - just to be sure */
+ /* this should not happen - just to be sure */
- while (!qemu_co_queue_empty(&vmaw->wqueue)) {
-- DPRINTF("vma_writer_close wait\n");
-- co_sleep_ns(rt_clock, 1000000);
-- }
-+ vma_stop_writer_thread(vmaw);
++ while (!qemu_co_queue_empty(&vmaw->wt.wqueue)) {
+ DPRINTF("vma_writer_close wait\n");
+ co_sleep_ns(rt_clock, 1000000);
+ }
++ vma_stop_writer_thread(vmaw);
++
if (vmaw->cmd) {
if (pclose(vmaw->cmd) < 0) {
-@@ -851,8 +906,9 @@ void vma_writer_destroy(VmaWriter *vmaw)
+ vma_writer_set_error(vmaw, "vma_writer_close: "
+@@ -835,8 +918,9 @@
{
assert(vmaw);
for (i = 0; i <= 255; i++) {
if (vmaw->stream_info[i].devname) {
g_free(vmaw->stream_info[i].devname);
-@@ -863,6 +919,14 @@ void vma_writer_destroy(VmaWriter *vmaw)
+@@ -847,6 +931,14 @@
g_checksum_free(vmaw->md5csum);
}
g_free(vmaw);
}
---
-1.7.2.5
-