* [Qemu-devel] [PATCH] migration: Add error_desc for file channel errors
@ 2019-04-22 10:34 Yury Kotov
2019-04-22 10:34 ` Yury Kotov
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Yury Kotov @ 2019-04-22 10:34 UTC (permalink / raw)
To: Juan Quintela, Dr. David Alan Gilbert
Cc: open list:All patches CC here, yc-core
Currently, there is no information about error if outgoing migration was failed
because of file channel errors.
Example (QMP session):
-> { "execute": "migrate", "arguments": { "uri": "exec:head -c 1" }}
<- { "return": {} }
...
-> { "execute": "query-migrate" }
<- { "return": { "status": "failed" }} // There is not error's description
And even in the QEMU's output there is nothing.
This patch
1) Adds errp for the most of QEMUFileOps
2) Adds qemu_file_get_error_obj/qemu_file_set_error_obj
3) And finally using of qemu_file_get_error_obj in migration.c
And now, the status for the mentioned fail will be:
-> { "execute": "query-migrate" }
<- { "return": { "status": "failed",
"error-desc": "Unable to write to command: Broken pipe" }}
Signed-off-by: Yury Kotov <yury-kotov@yandex-team.ru>
---
migration/migration.c | 10 ++++--
migration/qemu-file-channel.c | 30 +++++++++--------
migration/qemu-file.c | 63 ++++++++++++++++++++++++++++-------
migration/qemu-file.h | 15 ++++++---
migration/savevm.c | 6 ++--
5 files changed, 88 insertions(+), 36 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index 609e0df5d0..7bcdc4613b 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2949,6 +2949,7 @@ static MigThrError migration_detect_error(MigrationState *s)
{
int ret;
int state = s->state;
+ Error *local_error = NULL;
if (state == MIGRATION_STATUS_CANCELLING ||
state == MIGRATION_STATUS_CANCELLED) {
@@ -2957,13 +2958,18 @@ static MigThrError migration_detect_error(MigrationState *s)
}
/* Try to detect any file errors */
- ret = qemu_file_get_error(s->to_dst_file);
-
+ ret = qemu_file_get_error_obj(s->to_dst_file, &local_error);
if (!ret) {
/* Everything is fine */
+ assert(!local_error);
return MIG_THR_ERR_NONE;
}
+ if (local_error) {
+ migrate_set_error(s, local_error);
+ error_free(local_error);
+ }
+
if (state == MIGRATION_STATUS_POSTCOPY_ACTIVE && ret == -EIO) {
/*
* For postcopy, we allow the network to be down for a
diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c
index 8e639eb496..c382ea2d78 100644
--- a/migration/qemu-file-channel.c
+++ b/migration/qemu-file-channel.c
@@ -33,7 +33,8 @@
static ssize_t channel_writev_buffer(void *opaque,
struct iovec *iov,
int iovcnt,
- int64_t pos)
+ int64_t pos,
+ Error **errp)
{
QIOChannel *ioc = QIO_CHANNEL(opaque);
ssize_t done = 0;
@@ -47,7 +48,7 @@ static ssize_t channel_writev_buffer(void *opaque,
while (nlocal_iov > 0) {
ssize_t len;
- len = qio_channel_writev(ioc, local_iov, nlocal_iov, NULL);
+ len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
if (len == QIO_CHANNEL_ERR_BLOCK) {
if (qemu_in_coroutine()) {
qio_channel_yield(ioc, G_IO_OUT);
@@ -57,7 +58,6 @@ static ssize_t channel_writev_buffer(void *opaque,
continue;
}
if (len < 0) {
- /* XXX handle Error objects */
done = -EIO;
goto cleanup;
}
@@ -75,13 +75,14 @@ static ssize_t channel_writev_buffer(void *opaque,
static ssize_t channel_get_buffer(void *opaque,
uint8_t *buf,
int64_t pos,
- size_t size)
+ size_t size,
+ Error **errp)
{
QIOChannel *ioc = QIO_CHANNEL(opaque);
ssize_t ret;
do {
- ret = qio_channel_read(ioc, (char *)buf, size, NULL);
+ ret = qio_channel_read(ioc, (char *)buf, size, errp);
if (ret < 0) {
if (ret == QIO_CHANNEL_ERR_BLOCK) {
if (qemu_in_coroutine()) {
@@ -90,7 +91,6 @@ static ssize_t channel_get_buffer(void *opaque,
qio_channel_wait(ioc, G_IO_IN);
}
} else {
- /* XXX handle Error * object */
return -EIO;
}
}
@@ -100,18 +100,20 @@ static ssize_t channel_get_buffer(void *opaque,
}
-static int channel_close(void *opaque)
+static int channel_close(void *opaque, Error **errp)
{
+ int ret;
QIOChannel *ioc = QIO_CHANNEL(opaque);
- qio_channel_close(ioc, NULL);
+ ret = qio_channel_close(ioc, errp);
object_unref(OBJECT(ioc));
- return 0;
+ return ret;
}
static int channel_shutdown(void *opaque,
bool rd,
- bool wr)
+ bool wr,
+ Error **errp)
{
QIOChannel *ioc = QIO_CHANNEL(opaque);
@@ -125,8 +127,7 @@ static int channel_shutdown(void *opaque,
} else {
mode = QIO_CHANNEL_SHUTDOWN_WRITE;
}
- if (qio_channel_shutdown(ioc, mode, NULL) < 0) {
- /* XXX handler Error * object */
+ if (qio_channel_shutdown(ioc, mode, errp) < 0) {
return -EIO;
}
}
@@ -135,11 +136,12 @@ static int channel_shutdown(void *opaque,
static int channel_set_blocking(void *opaque,
- bool enabled)
+ bool enabled,
+ Error **errp)
{
QIOChannel *ioc = QIO_CHANNEL(opaque);
- if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) {
+ if (qio_channel_set_blocking(ioc, enabled, errp) < 0) {
return -1;
}
return 0;
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 977b9ae07c..c52160e08b 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -29,6 +29,7 @@
#include "migration.h"
#include "qemu-file.h"
#include "trace.h"
+#include "qapi/error.h"
#define IO_BUF_SIZE 32768
#define MAX_IOV_SIZE MIN(IOV_MAX, 64)
@@ -52,6 +53,7 @@ struct QEMUFile {
unsigned int iovcnt;
int last_error;
+ Error *last_error_obj;
};
/*
@@ -63,7 +65,7 @@ int qemu_file_shutdown(QEMUFile *f)
if (!f->ops->shut_down) {
return -ENOSYS;
}
- return f->ops->shut_down(f->opaque, true, true);
+ return f->ops->shut_down(f->opaque, true, true, NULL);
}
/*
@@ -108,24 +110,55 @@ void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks)
}
/*
- * Get last error for stream f
+ * Get last error for stream f with optional Error*
*
* Return negative error value if there has been an error on previous
* operations, return 0 if no error happened.
+ * Optional, it returns Error* in errp, but it may be NULL even if return value
+ * is not 0.
*
*/
-int qemu_file_get_error(QEMUFile *f)
+int qemu_file_get_error_obj(QEMUFile *f, Error **errp)
{
+ if (errp) {
+ *errp = f->last_error_obj ? error_copy(f->last_error_obj) : NULL;
+ }
return f->last_error;
}
-void qemu_file_set_error(QEMUFile *f, int ret)
+/*
+ * Set the last error for stream f with optional Error*
+ */
+void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err)
{
- if (f->last_error == 0) {
+ if (f->last_error == 0 && ret) {
f->last_error = ret;
+ error_propagate(&f->last_error_obj, err);
+ } else if (err) {
+ error_report_err(err);
}
}
+/*
+ * Get last error for stream f
+ *
+ * Return negative error value if there has been an error on previous
+ * operations, return 0 if no error happened.
+ *
+ */
+int qemu_file_get_error(QEMUFile *f)
+{
+ return qemu_file_get_error_obj(f, NULL);
+}
+
+/*
+ * Set the last error for stream f
+ */
+void qemu_file_set_error(QEMUFile *f, int ret)
+{
+ qemu_file_set_error_obj(f, ret, NULL);
+}
+
bool qemu_file_is_writable(QEMUFile *f)
{
return f->ops->writev_buffer;
@@ -177,6 +210,7 @@ void qemu_fflush(QEMUFile *f)
{
ssize_t ret = 0;
ssize_t expect = 0;
+ Error *local_error = NULL;
if (!qemu_file_is_writable(f)) {
return;
@@ -184,7 +218,8 @@ void qemu_fflush(QEMUFile *f)
if (f->iovcnt > 0) {
expect = iov_size(f->iov, f->iovcnt);
- ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
+ ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos,
+ &local_error);
qemu_iovec_release_ram(f);
}
@@ -196,7 +231,7 @@ void qemu_fflush(QEMUFile *f)
* data set we requested, so sanity check that.
*/
if (ret != expect) {
- qemu_file_set_error(f, ret < 0 ? ret : -EIO);
+ qemu_file_set_error_obj(f, ret < 0 ? ret : -EIO, local_error);
}
f->buf_index = 0;
f->iovcnt = 0;
@@ -284,6 +319,7 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
{
int len;
int pending;
+ Error *local_error = NULL;
assert(!qemu_file_is_writable(f));
@@ -295,14 +331,16 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
f->buf_size = pending;
len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
- IO_BUF_SIZE - pending);
+ IO_BUF_SIZE - pending, &local_error);
if (len > 0) {
f->buf_size += len;
f->pos += len;
} else if (len == 0) {
- qemu_file_set_error(f, -EIO);
+ qemu_file_set_error_obj(f, -EIO, local_error);
} else if (len != -EAGAIN) {
- qemu_file_set_error(f, len);
+ qemu_file_set_error_obj(f, len, local_error);
+ } else {
+ error_free(local_error);
}
return len;
@@ -328,7 +366,7 @@ int qemu_fclose(QEMUFile *f)
ret = qemu_file_get_error(f);
if (f->ops->close) {
- int ret2 = f->ops->close(f->opaque);
+ int ret2 = f->ops->close(f->opaque, NULL);
if (ret >= 0) {
ret = ret2;
}
@@ -339,6 +377,7 @@ int qemu_fclose(QEMUFile *f)
if (f->last_error) {
ret = f->last_error;
}
+ error_free(f->last_error_obj);
g_free(f);
trace_qemu_file_fclose();
return ret;
@@ -784,6 +823,6 @@ void qemu_put_counted_string(QEMUFile *f, const char *str)
void qemu_file_set_blocking(QEMUFile *f, bool block)
{
if (f->ops->set_blocking) {
- f->ops->set_blocking(f->opaque, block);
+ f->ops->set_blocking(f->opaque, block, NULL);
}
}
diff --git a/migration/qemu-file.h b/migration/qemu-file.h
index 13baf896bd..eb886db65f 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -32,7 +32,8 @@
* bytes actually read should be returned.
*/
typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
- int64_t pos, size_t size);
+ int64_t pos, size_t size,
+ Error **errp);
/* Close a file
*
@@ -41,7 +42,7 @@ typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
* The meaning of return value on success depends on the specific back-end being
* used.
*/
-typedef int (QEMUFileCloseFunc)(void *opaque);
+typedef int (QEMUFileCloseFunc)(void *opaque, Error **errp);
/* Called to return the OS file descriptor associated to the QEMUFile.
*/
@@ -49,14 +50,15 @@ typedef int (QEMUFileGetFD)(void *opaque);
/* Called to change the blocking mode of the file
*/
-typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled);
+typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled, Error **errp);
/*
* This function writes an iovec to file. The handler must write all
* of the data or return a negative errno value.
*/
typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov,
- int iovcnt, int64_t pos);
+ int iovcnt, int64_t pos,
+ Error **errp);
/*
* This function provides hooks around different
@@ -97,7 +99,8 @@ typedef QEMUFile *(QEMURetPathFunc)(void *opaque);
* Existing blocking reads/writes must be woken
* Returns 0 on success, -err on error
*/
-typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
+typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr,
+ Error **errp);
typedef struct QEMUFileOps {
QEMUFileGetBufferFunc *get_buffer;
@@ -149,6 +152,8 @@ void qemu_update_position(QEMUFile *f, size_t size);
void qemu_file_reset_rate_limit(QEMUFile *f);
void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
int64_t qemu_file_get_rate_limit(QEMUFile *f);
+int qemu_file_get_error_obj(QEMUFile *f, Error **errp);
+void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err);
void qemu_file_set_error(QEMUFile *f, int ret);
int qemu_file_shutdown(QEMUFile *f);
QEMUFile *qemu_file_get_return_path(QEMUFile *f);
diff --git a/migration/savevm.c b/migration/savevm.c
index 34bcad3807..a619af744d 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -124,7 +124,7 @@ static struct mig_cmd_args {
/* savevm/loadvm support */
static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
- int64_t pos)
+ int64_t pos, Error **errp)
{
int ret;
QEMUIOVector qiov;
@@ -139,12 +139,12 @@ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
}
static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
- size_t size)
+ size_t size, Error **errp)
{
return bdrv_load_vmstate(opaque, buf, pos, size);
}
-static int bdrv_fclose(void *opaque)
+static int bdrv_fclose(void *opaque, Error **errp)
{
return bdrv_flush(opaque);
}
--
2.21.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Qemu-devel] [PATCH] migration: Add error_desc for file channel errors
2019-04-22 10:34 [Qemu-devel] [PATCH] migration: Add error_desc for file channel errors Yury Kotov
@ 2019-04-22 10:34 ` Yury Kotov
2019-06-07 9:02 ` Yury Kotov
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Yury Kotov @ 2019-04-22 10:34 UTC (permalink / raw)
To: Juan Quintela, Dr. David Alan Gilbert
Cc: open list:All patches CC here, yc-core
Currently, there is no information about error if outgoing migration was failed
because of file channel errors.
Example (QMP session):
-> { "execute": "migrate", "arguments": { "uri": "exec:head -c 1" }}
<- { "return": {} }
...
-> { "execute": "query-migrate" }
<- { "return": { "status": "failed" }} // There is not error's description
And even in the QEMU's output there is nothing.
This patch
1) Adds errp for the most of QEMUFileOps
2) Adds qemu_file_get_error_obj/qemu_file_set_error_obj
3) And finally using of qemu_file_get_error_obj in migration.c
And now, the status for the mentioned fail will be:
-> { "execute": "query-migrate" }
<- { "return": { "status": "failed",
"error-desc": "Unable to write to command: Broken pipe" }}
Signed-off-by: Yury Kotov <yury-kotov@yandex-team.ru>
---
migration/migration.c | 10 ++++--
migration/qemu-file-channel.c | 30 +++++++++--------
migration/qemu-file.c | 63 ++++++++++++++++++++++++++++-------
migration/qemu-file.h | 15 ++++++---
migration/savevm.c | 6 ++--
5 files changed, 88 insertions(+), 36 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index 609e0df5d0..7bcdc4613b 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2949,6 +2949,7 @@ static MigThrError migration_detect_error(MigrationState *s)
{
int ret;
int state = s->state;
+ Error *local_error = NULL;
if (state == MIGRATION_STATUS_CANCELLING ||
state == MIGRATION_STATUS_CANCELLED) {
@@ -2957,13 +2958,18 @@ static MigThrError migration_detect_error(MigrationState *s)
}
/* Try to detect any file errors */
- ret = qemu_file_get_error(s->to_dst_file);
-
+ ret = qemu_file_get_error_obj(s->to_dst_file, &local_error);
if (!ret) {
/* Everything is fine */
+ assert(!local_error);
return MIG_THR_ERR_NONE;
}
+ if (local_error) {
+ migrate_set_error(s, local_error);
+ error_free(local_error);
+ }
+
if (state == MIGRATION_STATUS_POSTCOPY_ACTIVE && ret == -EIO) {
/*
* For postcopy, we allow the network to be down for a
diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c
index 8e639eb496..c382ea2d78 100644
--- a/migration/qemu-file-channel.c
+++ b/migration/qemu-file-channel.c
@@ -33,7 +33,8 @@
static ssize_t channel_writev_buffer(void *opaque,
struct iovec *iov,
int iovcnt,
- int64_t pos)
+ int64_t pos,
+ Error **errp)
{
QIOChannel *ioc = QIO_CHANNEL(opaque);
ssize_t done = 0;
@@ -47,7 +48,7 @@ static ssize_t channel_writev_buffer(void *opaque,
while (nlocal_iov > 0) {
ssize_t len;
- len = qio_channel_writev(ioc, local_iov, nlocal_iov, NULL);
+ len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
if (len == QIO_CHANNEL_ERR_BLOCK) {
if (qemu_in_coroutine()) {
qio_channel_yield(ioc, G_IO_OUT);
@@ -57,7 +58,6 @@ static ssize_t channel_writev_buffer(void *opaque,
continue;
}
if (len < 0) {
- /* XXX handle Error objects */
done = -EIO;
goto cleanup;
}
@@ -75,13 +75,14 @@ static ssize_t channel_writev_buffer(void *opaque,
static ssize_t channel_get_buffer(void *opaque,
uint8_t *buf,
int64_t pos,
- size_t size)
+ size_t size,
+ Error **errp)
{
QIOChannel *ioc = QIO_CHANNEL(opaque);
ssize_t ret;
do {
- ret = qio_channel_read(ioc, (char *)buf, size, NULL);
+ ret = qio_channel_read(ioc, (char *)buf, size, errp);
if (ret < 0) {
if (ret == QIO_CHANNEL_ERR_BLOCK) {
if (qemu_in_coroutine()) {
@@ -90,7 +91,6 @@ static ssize_t channel_get_buffer(void *opaque,
qio_channel_wait(ioc, G_IO_IN);
}
} else {
- /* XXX handle Error * object */
return -EIO;
}
}
@@ -100,18 +100,20 @@ static ssize_t channel_get_buffer(void *opaque,
}
-static int channel_close(void *opaque)
+static int channel_close(void *opaque, Error **errp)
{
+ int ret;
QIOChannel *ioc = QIO_CHANNEL(opaque);
- qio_channel_close(ioc, NULL);
+ ret = qio_channel_close(ioc, errp);
object_unref(OBJECT(ioc));
- return 0;
+ return ret;
}
static int channel_shutdown(void *opaque,
bool rd,
- bool wr)
+ bool wr,
+ Error **errp)
{
QIOChannel *ioc = QIO_CHANNEL(opaque);
@@ -125,8 +127,7 @@ static int channel_shutdown(void *opaque,
} else {
mode = QIO_CHANNEL_SHUTDOWN_WRITE;
}
- if (qio_channel_shutdown(ioc, mode, NULL) < 0) {
- /* XXX handler Error * object */
+ if (qio_channel_shutdown(ioc, mode, errp) < 0) {
return -EIO;
}
}
@@ -135,11 +136,12 @@ static int channel_shutdown(void *opaque,
static int channel_set_blocking(void *opaque,
- bool enabled)
+ bool enabled,
+ Error **errp)
{
QIOChannel *ioc = QIO_CHANNEL(opaque);
- if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) {
+ if (qio_channel_set_blocking(ioc, enabled, errp) < 0) {
return -1;
}
return 0;
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 977b9ae07c..c52160e08b 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -29,6 +29,7 @@
#include "migration.h"
#include "qemu-file.h"
#include "trace.h"
+#include "qapi/error.h"
#define IO_BUF_SIZE 32768
#define MAX_IOV_SIZE MIN(IOV_MAX, 64)
@@ -52,6 +53,7 @@ struct QEMUFile {
unsigned int iovcnt;
int last_error;
+ Error *last_error_obj;
};
/*
@@ -63,7 +65,7 @@ int qemu_file_shutdown(QEMUFile *f)
if (!f->ops->shut_down) {
return -ENOSYS;
}
- return f->ops->shut_down(f->opaque, true, true);
+ return f->ops->shut_down(f->opaque, true, true, NULL);
}
/*
@@ -108,24 +110,55 @@ void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks)
}
/*
- * Get last error for stream f
+ * Get last error for stream f with optional Error*
*
* Return negative error value if there has been an error on previous
* operations, return 0 if no error happened.
+ * Optional, it returns Error* in errp, but it may be NULL even if return value
+ * is not 0.
*
*/
-int qemu_file_get_error(QEMUFile *f)
+int qemu_file_get_error_obj(QEMUFile *f, Error **errp)
{
+ if (errp) {
+ *errp = f->last_error_obj ? error_copy(f->last_error_obj) : NULL;
+ }
return f->last_error;
}
-void qemu_file_set_error(QEMUFile *f, int ret)
+/*
+ * Set the last error for stream f with optional Error*
+ */
+void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err)
{
- if (f->last_error == 0) {
+ if (f->last_error == 0 && ret) {
f->last_error = ret;
+ error_propagate(&f->last_error_obj, err);
+ } else if (err) {
+ error_report_err(err);
}
}
+/*
+ * Get last error for stream f
+ *
+ * Return negative error value if there has been an error on previous
+ * operations, return 0 if no error happened.
+ *
+ */
+int qemu_file_get_error(QEMUFile *f)
+{
+ return qemu_file_get_error_obj(f, NULL);
+}
+
+/*
+ * Set the last error for stream f
+ */
+void qemu_file_set_error(QEMUFile *f, int ret)
+{
+ qemu_file_set_error_obj(f, ret, NULL);
+}
+
bool qemu_file_is_writable(QEMUFile *f)
{
return f->ops->writev_buffer;
@@ -177,6 +210,7 @@ void qemu_fflush(QEMUFile *f)
{
ssize_t ret = 0;
ssize_t expect = 0;
+ Error *local_error = NULL;
if (!qemu_file_is_writable(f)) {
return;
@@ -184,7 +218,8 @@ void qemu_fflush(QEMUFile *f)
if (f->iovcnt > 0) {
expect = iov_size(f->iov, f->iovcnt);
- ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
+ ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos,
+ &local_error);
qemu_iovec_release_ram(f);
}
@@ -196,7 +231,7 @@ void qemu_fflush(QEMUFile *f)
* data set we requested, so sanity check that.
*/
if (ret != expect) {
- qemu_file_set_error(f, ret < 0 ? ret : -EIO);
+ qemu_file_set_error_obj(f, ret < 0 ? ret : -EIO, local_error);
}
f->buf_index = 0;
f->iovcnt = 0;
@@ -284,6 +319,7 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
{
int len;
int pending;
+ Error *local_error = NULL;
assert(!qemu_file_is_writable(f));
@@ -295,14 +331,16 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
f->buf_size = pending;
len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
- IO_BUF_SIZE - pending);
+ IO_BUF_SIZE - pending, &local_error);
if (len > 0) {
f->buf_size += len;
f->pos += len;
} else if (len == 0) {
- qemu_file_set_error(f, -EIO);
+ qemu_file_set_error_obj(f, -EIO, local_error);
} else if (len != -EAGAIN) {
- qemu_file_set_error(f, len);
+ qemu_file_set_error_obj(f, len, local_error);
+ } else {
+ error_free(local_error);
}
return len;
@@ -328,7 +366,7 @@ int qemu_fclose(QEMUFile *f)
ret = qemu_file_get_error(f);
if (f->ops->close) {
- int ret2 = f->ops->close(f->opaque);
+ int ret2 = f->ops->close(f->opaque, NULL);
if (ret >= 0) {
ret = ret2;
}
@@ -339,6 +377,7 @@ int qemu_fclose(QEMUFile *f)
if (f->last_error) {
ret = f->last_error;
}
+ error_free(f->last_error_obj);
g_free(f);
trace_qemu_file_fclose();
return ret;
@@ -784,6 +823,6 @@ void qemu_put_counted_string(QEMUFile *f, const char *str)
void qemu_file_set_blocking(QEMUFile *f, bool block)
{
if (f->ops->set_blocking) {
- f->ops->set_blocking(f->opaque, block);
+ f->ops->set_blocking(f->opaque, block, NULL);
}
}
diff --git a/migration/qemu-file.h b/migration/qemu-file.h
index 13baf896bd..eb886db65f 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -32,7 +32,8 @@
* bytes actually read should be returned.
*/
typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
- int64_t pos, size_t size);
+ int64_t pos, size_t size,
+ Error **errp);
/* Close a file
*
@@ -41,7 +42,7 @@ typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
* The meaning of return value on success depends on the specific back-end being
* used.
*/
-typedef int (QEMUFileCloseFunc)(void *opaque);
+typedef int (QEMUFileCloseFunc)(void *opaque, Error **errp);
/* Called to return the OS file descriptor associated to the QEMUFile.
*/
@@ -49,14 +50,15 @@ typedef int (QEMUFileGetFD)(void *opaque);
/* Called to change the blocking mode of the file
*/
-typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled);
+typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled, Error **errp);
/*
* This function writes an iovec to file. The handler must write all
* of the data or return a negative errno value.
*/
typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov,
- int iovcnt, int64_t pos);
+ int iovcnt, int64_t pos,
+ Error **errp);
/*
* This function provides hooks around different
@@ -97,7 +99,8 @@ typedef QEMUFile *(QEMURetPathFunc)(void *opaque);
* Existing blocking reads/writes must be woken
* Returns 0 on success, -err on error
*/
-typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
+typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr,
+ Error **errp);
typedef struct QEMUFileOps {
QEMUFileGetBufferFunc *get_buffer;
@@ -149,6 +152,8 @@ void qemu_update_position(QEMUFile *f, size_t size);
void qemu_file_reset_rate_limit(QEMUFile *f);
void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
int64_t qemu_file_get_rate_limit(QEMUFile *f);
+int qemu_file_get_error_obj(QEMUFile *f, Error **errp);
+void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err);
void qemu_file_set_error(QEMUFile *f, int ret);
int qemu_file_shutdown(QEMUFile *f);
QEMUFile *qemu_file_get_return_path(QEMUFile *f);
diff --git a/migration/savevm.c b/migration/savevm.c
index 34bcad3807..a619af744d 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -124,7 +124,7 @@ static struct mig_cmd_args {
/* savevm/loadvm support */
static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
- int64_t pos)
+ int64_t pos, Error **errp)
{
int ret;
QEMUIOVector qiov;
@@ -139,12 +139,12 @@ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
}
static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
- size_t size)
+ size_t size, Error **errp)
{
return bdrv_load_vmstate(opaque, buf, pos, size);
}
-static int bdrv_fclose(void *opaque)
+static int bdrv_fclose(void *opaque, Error **errp)
{
return bdrv_flush(opaque);
}
--
2.21.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH] migration: Add error_desc for file channel errors
2019-04-22 10:34 [Qemu-devel] [PATCH] migration: Add error_desc for file channel errors Yury Kotov
2019-04-22 10:34 ` Yury Kotov
@ 2019-06-07 9:02 ` Yury Kotov
2019-06-14 16:39 ` Dr. David Alan Gilbert
2019-08-07 17:08 ` Dr. David Alan Gilbert
3 siblings, 0 replies; 7+ messages in thread
From: Yury Kotov @ 2019-06-07 9:02 UTC (permalink / raw)
To: Juan Quintela, Dr. David Alan Gilbert
Cc: open list:All patches CC here, yc-core
Ping
22.04.2019, 13:50, "Yury Kotov" <yury-kotov@yandex-team.ru>:
> Currently, there is no information about error if outgoing migration was failed
> because of file channel errors.
> Example (QMP session):
> -> { "execute": "migrate", "arguments": { "uri": "exec:head -c 1" }}
> <- { "return": {} }
> ...
> -> { "execute": "query-migrate" }
> <- { "return": { "status": "failed" }} // There is not error's description
>
> And even in the QEMU's output there is nothing.
>
> This patch
> 1) Adds errp for the most of QEMUFileOps
> 2) Adds qemu_file_get_error_obj/qemu_file_set_error_obj
> 3) And finally using of qemu_file_get_error_obj in migration.c
>
> And now, the status for the mentioned fail will be:
> -> { "execute": "query-migrate" }
> <- { "return": { "status": "failed",
> "error-desc": "Unable to write to command: Broken pipe" }}
>
> Signed-off-by: Yury Kotov <yury-kotov@yandex-team.ru>
> ---
> migration/migration.c | 10 ++++--
> migration/qemu-file-channel.c | 30 +++++++++--------
> migration/qemu-file.c | 63 ++++++++++++++++++++++++++++-------
> migration/qemu-file.h | 15 ++++++---
> migration/savevm.c | 6 ++--
> 5 files changed, 88 insertions(+), 36 deletions(-)
>
> diff --git a/migration/migration.c b/migration/migration.c
> index 609e0df5d0..7bcdc4613b 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -2949,6 +2949,7 @@ static MigThrError migration_detect_error(MigrationState *s)
> {
> int ret;
> int state = s->state;
> + Error *local_error = NULL;
>
> if (state == MIGRATION_STATUS_CANCELLING ||
> state == MIGRATION_STATUS_CANCELLED) {
> @@ -2957,13 +2958,18 @@ static MigThrError migration_detect_error(MigrationState *s)
> }
>
> /* Try to detect any file errors */
> - ret = qemu_file_get_error(s->to_dst_file);
> -
> + ret = qemu_file_get_error_obj(s->to_dst_file, &local_error);
> if (!ret) {
> /* Everything is fine */
> + assert(!local_error);
> return MIG_THR_ERR_NONE;
> }
>
> + if (local_error) {
> + migrate_set_error(s, local_error);
> + error_free(local_error);
> + }
> +
> if (state == MIGRATION_STATUS_POSTCOPY_ACTIVE && ret == -EIO) {
> /*
> * For postcopy, we allow the network to be down for a
> diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c
> index 8e639eb496..c382ea2d78 100644
> --- a/migration/qemu-file-channel.c
> +++ b/migration/qemu-file-channel.c
> @@ -33,7 +33,8 @@
> static ssize_t channel_writev_buffer(void *opaque,
> struct iovec *iov,
> int iovcnt,
> - int64_t pos)
> + int64_t pos,
> + Error **errp)
> {
> QIOChannel *ioc = QIO_CHANNEL(opaque);
> ssize_t done = 0;
> @@ -47,7 +48,7 @@ static ssize_t channel_writev_buffer(void *opaque,
>
> while (nlocal_iov > 0) {
> ssize_t len;
> - len = qio_channel_writev(ioc, local_iov, nlocal_iov, NULL);
> + len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
> if (len == QIO_CHANNEL_ERR_BLOCK) {
> if (qemu_in_coroutine()) {
> qio_channel_yield(ioc, G_IO_OUT);
> @@ -57,7 +58,6 @@ static ssize_t channel_writev_buffer(void *opaque,
> continue;
> }
> if (len < 0) {
> - /* XXX handle Error objects */
> done = -EIO;
> goto cleanup;
> }
> @@ -75,13 +75,14 @@ static ssize_t channel_writev_buffer(void *opaque,
> static ssize_t channel_get_buffer(void *opaque,
> uint8_t *buf,
> int64_t pos,
> - size_t size)
> + size_t size,
> + Error **errp)
> {
> QIOChannel *ioc = QIO_CHANNEL(opaque);
> ssize_t ret;
>
> do {
> - ret = qio_channel_read(ioc, (char *)buf, size, NULL);
> + ret = qio_channel_read(ioc, (char *)buf, size, errp);
> if (ret < 0) {
> if (ret == QIO_CHANNEL_ERR_BLOCK) {
> if (qemu_in_coroutine()) {
> @@ -90,7 +91,6 @@ static ssize_t channel_get_buffer(void *opaque,
> qio_channel_wait(ioc, G_IO_IN);
> }
> } else {
> - /* XXX handle Error * object */
> return -EIO;
> }
> }
> @@ -100,18 +100,20 @@ static ssize_t channel_get_buffer(void *opaque,
> }
>
> -static int channel_close(void *opaque)
> +static int channel_close(void *opaque, Error **errp)
> {
> + int ret;
> QIOChannel *ioc = QIO_CHANNEL(opaque);
> - qio_channel_close(ioc, NULL);
> + ret = qio_channel_close(ioc, errp);
> object_unref(OBJECT(ioc));
> - return 0;
> + return ret;
> }
>
> static int channel_shutdown(void *opaque,
> bool rd,
> - bool wr)
> + bool wr,
> + Error **errp)
> {
> QIOChannel *ioc = QIO_CHANNEL(opaque);
>
> @@ -125,8 +127,7 @@ static int channel_shutdown(void *opaque,
> } else {
> mode = QIO_CHANNEL_SHUTDOWN_WRITE;
> }
> - if (qio_channel_shutdown(ioc, mode, NULL) < 0) {
> - /* XXX handler Error * object */
> + if (qio_channel_shutdown(ioc, mode, errp) < 0) {
> return -EIO;
> }
> }
> @@ -135,11 +136,12 @@ static int channel_shutdown(void *opaque,
>
> static int channel_set_blocking(void *opaque,
> - bool enabled)
> + bool enabled,
> + Error **errp)
> {
> QIOChannel *ioc = QIO_CHANNEL(opaque);
>
> - if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) {
> + if (qio_channel_set_blocking(ioc, enabled, errp) < 0) {
> return -1;
> }
> return 0;
> diff --git a/migration/qemu-file.c b/migration/qemu-file.c
> index 977b9ae07c..c52160e08b 100644
> --- a/migration/qemu-file.c
> +++ b/migration/qemu-file.c
> @@ -29,6 +29,7 @@
> #include "migration.h"
> #include "qemu-file.h"
> #include "trace.h"
> +#include "qapi/error.h"
>
> #define IO_BUF_SIZE 32768
> #define MAX_IOV_SIZE MIN(IOV_MAX, 64)
> @@ -52,6 +53,7 @@ struct QEMUFile {
> unsigned int iovcnt;
>
> int last_error;
> + Error *last_error_obj;
> };
>
> /*
> @@ -63,7 +65,7 @@ int qemu_file_shutdown(QEMUFile *f)
> if (!f->ops->shut_down) {
> return -ENOSYS;
> }
> - return f->ops->shut_down(f->opaque, true, true);
> + return f->ops->shut_down(f->opaque, true, true, NULL);
> }
>
> /*
> @@ -108,24 +110,55 @@ void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks)
> }
>
> /*
> - * Get last error for stream f
> + * Get last error for stream f with optional Error*
> *
> * Return negative error value if there has been an error on previous
> * operations, return 0 if no error happened.
> + * Optional, it returns Error* in errp, but it may be NULL even if return value
> + * is not 0.
> *
> */
> -int qemu_file_get_error(QEMUFile *f)
> +int qemu_file_get_error_obj(QEMUFile *f, Error **errp)
> {
> + if (errp) {
> + *errp = f->last_error_obj ? error_copy(f->last_error_obj) : NULL;
> + }
> return f->last_error;
> }
>
> -void qemu_file_set_error(QEMUFile *f, int ret)
> +/*
> + * Set the last error for stream f with optional Error*
> + */
> +void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err)
> {
> - if (f->last_error == 0) {
> + if (f->last_error == 0 && ret) {
> f->last_error = ret;
> + error_propagate(&f->last_error_obj, err);
> + } else if (err) {
> + error_report_err(err);
> }
> }
>
> +/*
> + * Get last error for stream f
> + *
> + * Return negative error value if there has been an error on previous
> + * operations, return 0 if no error happened.
> + *
> + */
> +int qemu_file_get_error(QEMUFile *f)
> +{
> + return qemu_file_get_error_obj(f, NULL);
> +}
> +
> +/*
> + * Set the last error for stream f
> + */
> +void qemu_file_set_error(QEMUFile *f, int ret)
> +{
> + qemu_file_set_error_obj(f, ret, NULL);
> +}
> +
> bool qemu_file_is_writable(QEMUFile *f)
> {
> return f->ops->writev_buffer;
> @@ -177,6 +210,7 @@ void qemu_fflush(QEMUFile *f)
> {
> ssize_t ret = 0;
> ssize_t expect = 0;
> + Error *local_error = NULL;
>
> if (!qemu_file_is_writable(f)) {
> return;
> @@ -184,7 +218,8 @@ void qemu_fflush(QEMUFile *f)
>
> if (f->iovcnt > 0) {
> expect = iov_size(f->iov, f->iovcnt);
> - ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
> + ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos,
> + &local_error);
>
> qemu_iovec_release_ram(f);
> }
> @@ -196,7 +231,7 @@ void qemu_fflush(QEMUFile *f)
> * data set we requested, so sanity check that.
> */
> if (ret != expect) {
> - qemu_file_set_error(f, ret < 0 ? ret : -EIO);
> + qemu_file_set_error_obj(f, ret < 0 ? ret : -EIO, local_error);
> }
> f->buf_index = 0;
> f->iovcnt = 0;
> @@ -284,6 +319,7 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
> {
> int len;
> int pending;
> + Error *local_error = NULL;
>
> assert(!qemu_file_is_writable(f));
>
> @@ -295,14 +331,16 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
> f->buf_size = pending;
>
> len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
> - IO_BUF_SIZE - pending);
> + IO_BUF_SIZE - pending, &local_error);
> if (len > 0) {
> f->buf_size += len;
> f->pos += len;
> } else if (len == 0) {
> - qemu_file_set_error(f, -EIO);
> + qemu_file_set_error_obj(f, -EIO, local_error);
> } else if (len != -EAGAIN) {
> - qemu_file_set_error(f, len);
> + qemu_file_set_error_obj(f, len, local_error);
> + } else {
> + error_free(local_error);
> }
>
> return len;
> @@ -328,7 +366,7 @@ int qemu_fclose(QEMUFile *f)
> ret = qemu_file_get_error(f);
>
> if (f->ops->close) {
> - int ret2 = f->ops->close(f->opaque);
> + int ret2 = f->ops->close(f->opaque, NULL);
> if (ret >= 0) {
> ret = ret2;
> }
> @@ -339,6 +377,7 @@ int qemu_fclose(QEMUFile *f)
> if (f->last_error) {
> ret = f->last_error;
> }
> + error_free(f->last_error_obj);
> g_free(f);
> trace_qemu_file_fclose();
> return ret;
> @@ -784,6 +823,6 @@ void qemu_put_counted_string(QEMUFile *f, const char *str)
> void qemu_file_set_blocking(QEMUFile *f, bool block)
> {
> if (f->ops->set_blocking) {
> - f->ops->set_blocking(f->opaque, block);
> + f->ops->set_blocking(f->opaque, block, NULL);
> }
> }
> diff --git a/migration/qemu-file.h b/migration/qemu-file.h
> index 13baf896bd..eb886db65f 100644
> --- a/migration/qemu-file.h
> +++ b/migration/qemu-file.h
> @@ -32,7 +32,8 @@
> * bytes actually read should be returned.
> */
> typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
> - int64_t pos, size_t size);
> + int64_t pos, size_t size,
> + Error **errp);
>
> /* Close a file
> *
> @@ -41,7 +42,7 @@ typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
> * The meaning of return value on success depends on the specific back-end being
> * used.
> */
> -typedef int (QEMUFileCloseFunc)(void *opaque);
> +typedef int (QEMUFileCloseFunc)(void *opaque, Error **errp);
>
> /* Called to return the OS file descriptor associated to the QEMUFile.
> */
> @@ -49,14 +50,15 @@ typedef int (QEMUFileGetFD)(void *opaque);
>
> /* Called to change the blocking mode of the file
> */
> -typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled);
> +typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled, Error **errp);
>
> /*
> * This function writes an iovec to file. The handler must write all
> * of the data or return a negative errno value.
> */
> typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov,
> - int iovcnt, int64_t pos);
> + int iovcnt, int64_t pos,
> + Error **errp);
>
> /*
> * This function provides hooks around different
> @@ -97,7 +99,8 @@ typedef QEMUFile *(QEMURetPathFunc)(void *opaque);
> * Existing blocking reads/writes must be woken
> * Returns 0 on success, -err on error
> */
> -typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
> +typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr,
> + Error **errp);
>
> typedef struct QEMUFileOps {
> QEMUFileGetBufferFunc *get_buffer;
> @@ -149,6 +152,8 @@ void qemu_update_position(QEMUFile *f, size_t size);
> void qemu_file_reset_rate_limit(QEMUFile *f);
> void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
> int64_t qemu_file_get_rate_limit(QEMUFile *f);
> +int qemu_file_get_error_obj(QEMUFile *f, Error **errp);
> +void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err);
> void qemu_file_set_error(QEMUFile *f, int ret);
> int qemu_file_shutdown(QEMUFile *f);
> QEMUFile *qemu_file_get_return_path(QEMUFile *f);
> diff --git a/migration/savevm.c b/migration/savevm.c
> index 34bcad3807..a619af744d 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -124,7 +124,7 @@ static struct mig_cmd_args {
> /* savevm/loadvm support */
>
> static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
> - int64_t pos)
> + int64_t pos, Error **errp)
> {
> int ret;
> QEMUIOVector qiov;
> @@ -139,12 +139,12 @@ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
> }
>
> static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
> - size_t size)
> + size_t size, Error **errp)
> {
> return bdrv_load_vmstate(opaque, buf, pos, size);
> }
>
> -static int bdrv_fclose(void *opaque)
> +static int bdrv_fclose(void *opaque, Error **errp)
> {
> return bdrv_flush(opaque);
> }
> --
> 2.21.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH] migration: Add error_desc for file channel errors
2019-04-22 10:34 [Qemu-devel] [PATCH] migration: Add error_desc for file channel errors Yury Kotov
2019-04-22 10:34 ` Yury Kotov
2019-06-07 9:02 ` Yury Kotov
@ 2019-06-14 16:39 ` Dr. David Alan Gilbert
2019-07-17 10:19 ` Yury Kotov
2019-08-07 17:08 ` Dr. David Alan Gilbert
3 siblings, 1 reply; 7+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-14 16:39 UTC (permalink / raw)
To: Yury Kotov; +Cc: open list:All patches CC here, yc-core, Juan Quintela
* Yury Kotov (yury-kotov@yandex-team.ru) wrote:
> Currently, there is no information about error if outgoing migration was failed
> because of file channel errors.
> Example (QMP session):
> -> { "execute": "migrate", "arguments": { "uri": "exec:head -c 1" }}
> <- { "return": {} }
> ...
> -> { "execute": "query-migrate" }
> <- { "return": { "status": "failed" }} // There is not error's description
>
> And even in the QEMU's output there is nothing.
>
> This patch
> 1) Adds errp for the most of QEMUFileOps
> 2) Adds qemu_file_get_error_obj/qemu_file_set_error_obj
> 3) And finally using of qemu_file_get_error_obj in migration.c
>
> And now, the status for the mentioned fail will be:
> -> { "execute": "query-migrate" }
> <- { "return": { "status": "failed",
> "error-desc": "Unable to write to command: Broken pipe" }}
>
> Signed-off-by: Yury Kotov <yury-kotov@yandex-team.ru>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
> migration/migration.c | 10 ++++--
> migration/qemu-file-channel.c | 30 +++++++++--------
> migration/qemu-file.c | 63 ++++++++++++++++++++++++++++-------
> migration/qemu-file.h | 15 ++++++---
> migration/savevm.c | 6 ++--
> 5 files changed, 88 insertions(+), 36 deletions(-)
>
> diff --git a/migration/migration.c b/migration/migration.c
> index 609e0df5d0..7bcdc4613b 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -2949,6 +2949,7 @@ static MigThrError migration_detect_error(MigrationState *s)
> {
> int ret;
> int state = s->state;
> + Error *local_error = NULL;
>
> if (state == MIGRATION_STATUS_CANCELLING ||
> state == MIGRATION_STATUS_CANCELLED) {
> @@ -2957,13 +2958,18 @@ static MigThrError migration_detect_error(MigrationState *s)
> }
>
> /* Try to detect any file errors */
> - ret = qemu_file_get_error(s->to_dst_file);
> -
> + ret = qemu_file_get_error_obj(s->to_dst_file, &local_error);
> if (!ret) {
> /* Everything is fine */
> + assert(!local_error);
> return MIG_THR_ERR_NONE;
> }
>
> + if (local_error) {
> + migrate_set_error(s, local_error);
> + error_free(local_error);
> + }
> +
> if (state == MIGRATION_STATUS_POSTCOPY_ACTIVE && ret == -EIO) {
> /*
> * For postcopy, we allow the network to be down for a
> diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c
> index 8e639eb496..c382ea2d78 100644
> --- a/migration/qemu-file-channel.c
> +++ b/migration/qemu-file-channel.c
> @@ -33,7 +33,8 @@
> static ssize_t channel_writev_buffer(void *opaque,
> struct iovec *iov,
> int iovcnt,
> - int64_t pos)
> + int64_t pos,
> + Error **errp)
> {
> QIOChannel *ioc = QIO_CHANNEL(opaque);
> ssize_t done = 0;
> @@ -47,7 +48,7 @@ static ssize_t channel_writev_buffer(void *opaque,
>
> while (nlocal_iov > 0) {
> ssize_t len;
> - len = qio_channel_writev(ioc, local_iov, nlocal_iov, NULL);
> + len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
> if (len == QIO_CHANNEL_ERR_BLOCK) {
> if (qemu_in_coroutine()) {
> qio_channel_yield(ioc, G_IO_OUT);
> @@ -57,7 +58,6 @@ static ssize_t channel_writev_buffer(void *opaque,
> continue;
> }
> if (len < 0) {
> - /* XXX handle Error objects */
> done = -EIO;
> goto cleanup;
> }
> @@ -75,13 +75,14 @@ static ssize_t channel_writev_buffer(void *opaque,
> static ssize_t channel_get_buffer(void *opaque,
> uint8_t *buf,
> int64_t pos,
> - size_t size)
> + size_t size,
> + Error **errp)
> {
> QIOChannel *ioc = QIO_CHANNEL(opaque);
> ssize_t ret;
>
> do {
> - ret = qio_channel_read(ioc, (char *)buf, size, NULL);
> + ret = qio_channel_read(ioc, (char *)buf, size, errp);
> if (ret < 0) {
> if (ret == QIO_CHANNEL_ERR_BLOCK) {
> if (qemu_in_coroutine()) {
> @@ -90,7 +91,6 @@ static ssize_t channel_get_buffer(void *opaque,
> qio_channel_wait(ioc, G_IO_IN);
> }
> } else {
> - /* XXX handle Error * object */
> return -EIO;
> }
> }
> @@ -100,18 +100,20 @@ static ssize_t channel_get_buffer(void *opaque,
> }
>
>
> -static int channel_close(void *opaque)
> +static int channel_close(void *opaque, Error **errp)
> {
> + int ret;
> QIOChannel *ioc = QIO_CHANNEL(opaque);
> - qio_channel_close(ioc, NULL);
> + ret = qio_channel_close(ioc, errp);
> object_unref(OBJECT(ioc));
> - return 0;
> + return ret;
> }
>
>
> static int channel_shutdown(void *opaque,
> bool rd,
> - bool wr)
> + bool wr,
> + Error **errp)
> {
> QIOChannel *ioc = QIO_CHANNEL(opaque);
>
> @@ -125,8 +127,7 @@ static int channel_shutdown(void *opaque,
> } else {
> mode = QIO_CHANNEL_SHUTDOWN_WRITE;
> }
> - if (qio_channel_shutdown(ioc, mode, NULL) < 0) {
> - /* XXX handler Error * object */
> + if (qio_channel_shutdown(ioc, mode, errp) < 0) {
> return -EIO;
> }
> }
> @@ -135,11 +136,12 @@ static int channel_shutdown(void *opaque,
>
>
> static int channel_set_blocking(void *opaque,
> - bool enabled)
> + bool enabled,
> + Error **errp)
> {
> QIOChannel *ioc = QIO_CHANNEL(opaque);
>
> - if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) {
> + if (qio_channel_set_blocking(ioc, enabled, errp) < 0) {
> return -1;
> }
> return 0;
> diff --git a/migration/qemu-file.c b/migration/qemu-file.c
> index 977b9ae07c..c52160e08b 100644
> --- a/migration/qemu-file.c
> +++ b/migration/qemu-file.c
> @@ -29,6 +29,7 @@
> #include "migration.h"
> #include "qemu-file.h"
> #include "trace.h"
> +#include "qapi/error.h"
>
> #define IO_BUF_SIZE 32768
> #define MAX_IOV_SIZE MIN(IOV_MAX, 64)
> @@ -52,6 +53,7 @@ struct QEMUFile {
> unsigned int iovcnt;
>
> int last_error;
> + Error *last_error_obj;
> };
>
> /*
> @@ -63,7 +65,7 @@ int qemu_file_shutdown(QEMUFile *f)
> if (!f->ops->shut_down) {
> return -ENOSYS;
> }
> - return f->ops->shut_down(f->opaque, true, true);
> + return f->ops->shut_down(f->opaque, true, true, NULL);
> }
>
> /*
> @@ -108,24 +110,55 @@ void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks)
> }
>
> /*
> - * Get last error for stream f
> + * Get last error for stream f with optional Error*
> *
> * Return negative error value if there has been an error on previous
> * operations, return 0 if no error happened.
> + * Optional, it returns Error* in errp, but it may be NULL even if return value
> + * is not 0.
> *
> */
> -int qemu_file_get_error(QEMUFile *f)
> +int qemu_file_get_error_obj(QEMUFile *f, Error **errp)
> {
> + if (errp) {
> + *errp = f->last_error_obj ? error_copy(f->last_error_obj) : NULL;
> + }
> return f->last_error;
> }
>
> -void qemu_file_set_error(QEMUFile *f, int ret)
> +/*
> + * Set the last error for stream f with optional Error*
> + */
> +void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err)
> {
> - if (f->last_error == 0) {
> + if (f->last_error == 0 && ret) {
> f->last_error = ret;
> + error_propagate(&f->last_error_obj, err);
> + } else if (err) {
> + error_report_err(err);
> }
> }
>
> +/*
> + * Get last error for stream f
> + *
> + * Return negative error value if there has been an error on previous
> + * operations, return 0 if no error happened.
> + *
> + */
> +int qemu_file_get_error(QEMUFile *f)
> +{
> + return qemu_file_get_error_obj(f, NULL);
> +}
> +
> +/*
> + * Set the last error for stream f
> + */
> +void qemu_file_set_error(QEMUFile *f, int ret)
> +{
> + qemu_file_set_error_obj(f, ret, NULL);
> +}
> +
> bool qemu_file_is_writable(QEMUFile *f)
> {
> return f->ops->writev_buffer;
> @@ -177,6 +210,7 @@ void qemu_fflush(QEMUFile *f)
> {
> ssize_t ret = 0;
> ssize_t expect = 0;
> + Error *local_error = NULL;
>
> if (!qemu_file_is_writable(f)) {
> return;
> @@ -184,7 +218,8 @@ void qemu_fflush(QEMUFile *f)
>
> if (f->iovcnt > 0) {
> expect = iov_size(f->iov, f->iovcnt);
> - ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
> + ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos,
> + &local_error);
>
> qemu_iovec_release_ram(f);
> }
> @@ -196,7 +231,7 @@ void qemu_fflush(QEMUFile *f)
> * data set we requested, so sanity check that.
> */
> if (ret != expect) {
> - qemu_file_set_error(f, ret < 0 ? ret : -EIO);
> + qemu_file_set_error_obj(f, ret < 0 ? ret : -EIO, local_error);
> }
> f->buf_index = 0;
> f->iovcnt = 0;
> @@ -284,6 +319,7 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
> {
> int len;
> int pending;
> + Error *local_error = NULL;
>
> assert(!qemu_file_is_writable(f));
>
> @@ -295,14 +331,16 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
> f->buf_size = pending;
>
> len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
> - IO_BUF_SIZE - pending);
> + IO_BUF_SIZE - pending, &local_error);
> if (len > 0) {
> f->buf_size += len;
> f->pos += len;
> } else if (len == 0) {
> - qemu_file_set_error(f, -EIO);
> + qemu_file_set_error_obj(f, -EIO, local_error);
> } else if (len != -EAGAIN) {
> - qemu_file_set_error(f, len);
> + qemu_file_set_error_obj(f, len, local_error);
> + } else {
> + error_free(local_error);
> }
>
> return len;
> @@ -328,7 +366,7 @@ int qemu_fclose(QEMUFile *f)
> ret = qemu_file_get_error(f);
>
> if (f->ops->close) {
> - int ret2 = f->ops->close(f->opaque);
> + int ret2 = f->ops->close(f->opaque, NULL);
> if (ret >= 0) {
> ret = ret2;
> }
> @@ -339,6 +377,7 @@ int qemu_fclose(QEMUFile *f)
> if (f->last_error) {
> ret = f->last_error;
> }
> + error_free(f->last_error_obj);
> g_free(f);
> trace_qemu_file_fclose();
> return ret;
> @@ -784,6 +823,6 @@ void qemu_put_counted_string(QEMUFile *f, const char *str)
> void qemu_file_set_blocking(QEMUFile *f, bool block)
> {
> if (f->ops->set_blocking) {
> - f->ops->set_blocking(f->opaque, block);
> + f->ops->set_blocking(f->opaque, block, NULL);
> }
> }
> diff --git a/migration/qemu-file.h b/migration/qemu-file.h
> index 13baf896bd..eb886db65f 100644
> --- a/migration/qemu-file.h
> +++ b/migration/qemu-file.h
> @@ -32,7 +32,8 @@
> * bytes actually read should be returned.
> */
> typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
> - int64_t pos, size_t size);
> + int64_t pos, size_t size,
> + Error **errp);
>
> /* Close a file
> *
> @@ -41,7 +42,7 @@ typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
> * The meaning of return value on success depends on the specific back-end being
> * used.
> */
> -typedef int (QEMUFileCloseFunc)(void *opaque);
> +typedef int (QEMUFileCloseFunc)(void *opaque, Error **errp);
>
> /* Called to return the OS file descriptor associated to the QEMUFile.
> */
> @@ -49,14 +50,15 @@ typedef int (QEMUFileGetFD)(void *opaque);
>
> /* Called to change the blocking mode of the file
> */
> -typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled);
> +typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled, Error **errp);
>
> /*
> * This function writes an iovec to file. The handler must write all
> * of the data or return a negative errno value.
> */
> typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov,
> - int iovcnt, int64_t pos);
> + int iovcnt, int64_t pos,
> + Error **errp);
>
> /*
> * This function provides hooks around different
> @@ -97,7 +99,8 @@ typedef QEMUFile *(QEMURetPathFunc)(void *opaque);
> * Existing blocking reads/writes must be woken
> * Returns 0 on success, -err on error
> */
> -typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
> +typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr,
> + Error **errp);
>
> typedef struct QEMUFileOps {
> QEMUFileGetBufferFunc *get_buffer;
> @@ -149,6 +152,8 @@ void qemu_update_position(QEMUFile *f, size_t size);
> void qemu_file_reset_rate_limit(QEMUFile *f);
> void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
> int64_t qemu_file_get_rate_limit(QEMUFile *f);
> +int qemu_file_get_error_obj(QEMUFile *f, Error **errp);
> +void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err);
> void qemu_file_set_error(QEMUFile *f, int ret);
> int qemu_file_shutdown(QEMUFile *f);
> QEMUFile *qemu_file_get_return_path(QEMUFile *f);
> diff --git a/migration/savevm.c b/migration/savevm.c
> index 34bcad3807..a619af744d 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -124,7 +124,7 @@ static struct mig_cmd_args {
> /* savevm/loadvm support */
>
> static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
> - int64_t pos)
> + int64_t pos, Error **errp)
> {
> int ret;
> QEMUIOVector qiov;
> @@ -139,12 +139,12 @@ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
> }
>
> static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
> - size_t size)
> + size_t size, Error **errp)
> {
> return bdrv_load_vmstate(opaque, buf, pos, size);
> }
>
> -static int bdrv_fclose(void *opaque)
> +static int bdrv_fclose(void *opaque, Error **errp)
> {
> return bdrv_flush(opaque);
> }
> --
> 2.21.0
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH] migration: Add error_desc for file channel errors
2019-06-14 16:39 ` Dr. David Alan Gilbert
@ 2019-07-17 10:19 ` Yury Kotov
2019-08-06 15:51 ` Dr. David Alan Gilbert
0 siblings, 1 reply; 7+ messages in thread
From: Yury Kotov @ 2019-07-17 10:19 UTC (permalink / raw)
To: Dr. David Alan Gilbert
Cc: open list:All patches CC here, yc-core, Juan Quintela
Hi, I'm a bit worried that this patch might have been forgotten.
Is it queued? Thanks!
14.06.2019, 19:56, "Dr. David Alan Gilbert" <dgilbert@redhat.com>:
> * Yury Kotov (yury-kotov@yandex-team.ru) wrote:
>> Currently, there is no information about error if outgoing migration was failed
>> because of file channel errors.
>> Example (QMP session):
>> -> { "execute": "migrate", "arguments": { "uri": "exec:head -c 1" }}
>> <- { "return": {} }
>> ...
>> -> { "execute": "query-migrate" }
>> <- { "return": { "status": "failed" }} // There is not error's description
>>
>> And even in the QEMU's output there is nothing.
>>
>> This patch
>> 1) Adds errp for the most of QEMUFileOps
>> 2) Adds qemu_file_get_error_obj/qemu_file_set_error_obj
>> 3) And finally using of qemu_file_get_error_obj in migration.c
>>
>> And now, the status for the mentioned fail will be:
>> -> { "execute": "query-migrate" }
>> <- { "return": { "status": "failed",
>> "error-desc": "Unable to write to command: Broken pipe" }}
>>
>> Signed-off-by: Yury Kotov <yury-kotov@yandex-team.ru>
>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
>
>> ---
>> migration/migration.c | 10 ++++--
>> migration/qemu-file-channel.c | 30 +++++++++--------
>> migration/qemu-file.c | 63 ++++++++++++++++++++++++++++-------
>> migration/qemu-file.h | 15 ++++++---
>> migration/savevm.c | 6 ++--
>> 5 files changed, 88 insertions(+), 36 deletions(-)
>>
>> diff --git a/migration/migration.c b/migration/migration.c
>> index 609e0df5d0..7bcdc4613b 100644
>> --- a/migration/migration.c
>> +++ b/migration/migration.c
>> @@ -2949,6 +2949,7 @@ static MigThrError migration_detect_error(MigrationState *s)
>> {
>> int ret;
>> int state = s->state;
>> + Error *local_error = NULL;
>>
>> if (state == MIGRATION_STATUS_CANCELLING ||
>> state == MIGRATION_STATUS_CANCELLED) {
>> @@ -2957,13 +2958,18 @@ static MigThrError migration_detect_error(MigrationState *s)
>> }
>>
>> /* Try to detect any file errors */
>> - ret = qemu_file_get_error(s->to_dst_file);
>> -
>> + ret = qemu_file_get_error_obj(s->to_dst_file, &local_error);
>> if (!ret) {
>> /* Everything is fine */
>> + assert(!local_error);
>> return MIG_THR_ERR_NONE;
>> }
>>
>> + if (local_error) {
>> + migrate_set_error(s, local_error);
>> + error_free(local_error);
>> + }
>> +
>> if (state == MIGRATION_STATUS_POSTCOPY_ACTIVE && ret == -EIO) {
>> /*
>> * For postcopy, we allow the network to be down for a
>> diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c
>> index 8e639eb496..c382ea2d78 100644
>> --- a/migration/qemu-file-channel.c
>> +++ b/migration/qemu-file-channel.c
>> @@ -33,7 +33,8 @@
>> static ssize_t channel_writev_buffer(void *opaque,
>> struct iovec *iov,
>> int iovcnt,
>> - int64_t pos)
>> + int64_t pos,
>> + Error **errp)
>> {
>> QIOChannel *ioc = QIO_CHANNEL(opaque);
>> ssize_t done = 0;
>> @@ -47,7 +48,7 @@ static ssize_t channel_writev_buffer(void *opaque,
>>
>> while (nlocal_iov > 0) {
>> ssize_t len;
>> - len = qio_channel_writev(ioc, local_iov, nlocal_iov, NULL);
>> + len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
>> if (len == QIO_CHANNEL_ERR_BLOCK) {
>> if (qemu_in_coroutine()) {
>> qio_channel_yield(ioc, G_IO_OUT);
>> @@ -57,7 +58,6 @@ static ssize_t channel_writev_buffer(void *opaque,
>> continue;
>> }
>> if (len < 0) {
>> - /* XXX handle Error objects */
>> done = -EIO;
>> goto cleanup;
>> }
>> @@ -75,13 +75,14 @@ static ssize_t channel_writev_buffer(void *opaque,
>> static ssize_t channel_get_buffer(void *opaque,
>> uint8_t *buf,
>> int64_t pos,
>> - size_t size)
>> + size_t size,
>> + Error **errp)
>> {
>> QIOChannel *ioc = QIO_CHANNEL(opaque);
>> ssize_t ret;
>>
>> do {
>> - ret = qio_channel_read(ioc, (char *)buf, size, NULL);
>> + ret = qio_channel_read(ioc, (char *)buf, size, errp);
>> if (ret < 0) {
>> if (ret == QIO_CHANNEL_ERR_BLOCK) {
>> if (qemu_in_coroutine()) {
>> @@ -90,7 +91,6 @@ static ssize_t channel_get_buffer(void *opaque,
>> qio_channel_wait(ioc, G_IO_IN);
>> }
>> } else {
>> - /* XXX handle Error * object */
>> return -EIO;
>> }
>> }
>> @@ -100,18 +100,20 @@ static ssize_t channel_get_buffer(void *opaque,
>> }
>>
>> -static int channel_close(void *opaque)
>> +static int channel_close(void *opaque, Error **errp)
>> {
>> + int ret;
>> QIOChannel *ioc = QIO_CHANNEL(opaque);
>> - qio_channel_close(ioc, NULL);
>> + ret = qio_channel_close(ioc, errp);
>> object_unref(OBJECT(ioc));
>> - return 0;
>> + return ret;
>> }
>>
>> static int channel_shutdown(void *opaque,
>> bool rd,
>> - bool wr)
>> + bool wr,
>> + Error **errp)
>> {
>> QIOChannel *ioc = QIO_CHANNEL(opaque);
>>
>> @@ -125,8 +127,7 @@ static int channel_shutdown(void *opaque,
>> } else {
>> mode = QIO_CHANNEL_SHUTDOWN_WRITE;
>> }
>> - if (qio_channel_shutdown(ioc, mode, NULL) < 0) {
>> - /* XXX handler Error * object */
>> + if (qio_channel_shutdown(ioc, mode, errp) < 0) {
>> return -EIO;
>> }
>> }
>> @@ -135,11 +136,12 @@ static int channel_shutdown(void *opaque,
>>
>> static int channel_set_blocking(void *opaque,
>> - bool enabled)
>> + bool enabled,
>> + Error **errp)
>> {
>> QIOChannel *ioc = QIO_CHANNEL(opaque);
>>
>> - if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) {
>> + if (qio_channel_set_blocking(ioc, enabled, errp) < 0) {
>> return -1;
>> }
>> return 0;
>> diff --git a/migration/qemu-file.c b/migration/qemu-file.c
>> index 977b9ae07c..c52160e08b 100644
>> --- a/migration/qemu-file.c
>> +++ b/migration/qemu-file.c
>> @@ -29,6 +29,7 @@
>> #include "migration.h"
>> #include "qemu-file.h"
>> #include "trace.h"
>> +#include "qapi/error.h"
>>
>> #define IO_BUF_SIZE 32768
>> #define MAX_IOV_SIZE MIN(IOV_MAX, 64)
>> @@ -52,6 +53,7 @@ struct QEMUFile {
>> unsigned int iovcnt;
>>
>> int last_error;
>> + Error *last_error_obj;
>> };
>>
>> /*
>> @@ -63,7 +65,7 @@ int qemu_file_shutdown(QEMUFile *f)
>> if (!f->ops->shut_down) {
>> return -ENOSYS;
>> }
>> - return f->ops->shut_down(f->opaque, true, true);
>> + return f->ops->shut_down(f->opaque, true, true, NULL);
>> }
>>
>> /*
>> @@ -108,24 +110,55 @@ void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks)
>> }
>>
>> /*
>> - * Get last error for stream f
>> + * Get last error for stream f with optional Error*
>> *
>> * Return negative error value if there has been an error on previous
>> * operations, return 0 if no error happened.
>> + * Optional, it returns Error* in errp, but it may be NULL even if return value
>> + * is not 0.
>> *
>> */
>> -int qemu_file_get_error(QEMUFile *f)
>> +int qemu_file_get_error_obj(QEMUFile *f, Error **errp)
>> {
>> + if (errp) {
>> + *errp = f->last_error_obj ? error_copy(f->last_error_obj) : NULL;
>> + }
>> return f->last_error;
>> }
>>
>> -void qemu_file_set_error(QEMUFile *f, int ret)
>> +/*
>> + * Set the last error for stream f with optional Error*
>> + */
>> +void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err)
>> {
>> - if (f->last_error == 0) {
>> + if (f->last_error == 0 && ret) {
>> f->last_error = ret;
>> + error_propagate(&f->last_error_obj, err);
>> + } else if (err) {
>> + error_report_err(err);
>> }
>> }
>>
>> +/*
>> + * Get last error for stream f
>> + *
>> + * Return negative error value if there has been an error on previous
>> + * operations, return 0 if no error happened.
>> + *
>> + */
>> +int qemu_file_get_error(QEMUFile *f)
>> +{
>> + return qemu_file_get_error_obj(f, NULL);
>> +}
>> +
>> +/*
>> + * Set the last error for stream f
>> + */
>> +void qemu_file_set_error(QEMUFile *f, int ret)
>> +{
>> + qemu_file_set_error_obj(f, ret, NULL);
>> +}
>> +
>> bool qemu_file_is_writable(QEMUFile *f)
>> {
>> return f->ops->writev_buffer;
>> @@ -177,6 +210,7 @@ void qemu_fflush(QEMUFile *f)
>> {
>> ssize_t ret = 0;
>> ssize_t expect = 0;
>> + Error *local_error = NULL;
>>
>> if (!qemu_file_is_writable(f)) {
>> return;
>> @@ -184,7 +218,8 @@ void qemu_fflush(QEMUFile *f)
>>
>> if (f->iovcnt > 0) {
>> expect = iov_size(f->iov, f->iovcnt);
>> - ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
>> + ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos,
>> + &local_error);
>>
>> qemu_iovec_release_ram(f);
>> }
>> @@ -196,7 +231,7 @@ void qemu_fflush(QEMUFile *f)
>> * data set we requested, so sanity check that.
>> */
>> if (ret != expect) {
>> - qemu_file_set_error(f, ret < 0 ? ret : -EIO);
>> + qemu_file_set_error_obj(f, ret < 0 ? ret : -EIO, local_error);
>> }
>> f->buf_index = 0;
>> f->iovcnt = 0;
>> @@ -284,6 +319,7 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
>> {
>> int len;
>> int pending;
>> + Error *local_error = NULL;
>>
>> assert(!qemu_file_is_writable(f));
>>
>> @@ -295,14 +331,16 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
>> f->buf_size = pending;
>>
>> len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
>> - IO_BUF_SIZE - pending);
>> + IO_BUF_SIZE - pending, &local_error);
>> if (len > 0) {
>> f->buf_size += len;
>> f->pos += len;
>> } else if (len == 0) {
>> - qemu_file_set_error(f, -EIO);
>> + qemu_file_set_error_obj(f, -EIO, local_error);
>> } else if (len != -EAGAIN) {
>> - qemu_file_set_error(f, len);
>> + qemu_file_set_error_obj(f, len, local_error);
>> + } else {
>> + error_free(local_error);
>> }
>>
>> return len;
>> @@ -328,7 +366,7 @@ int qemu_fclose(QEMUFile *f)
>> ret = qemu_file_get_error(f);
>>
>> if (f->ops->close) {
>> - int ret2 = f->ops->close(f->opaque);
>> + int ret2 = f->ops->close(f->opaque, NULL);
>> if (ret >= 0) {
>> ret = ret2;
>> }
>> @@ -339,6 +377,7 @@ int qemu_fclose(QEMUFile *f)
>> if (f->last_error) {
>> ret = f->last_error;
>> }
>> + error_free(f->last_error_obj);
>> g_free(f);
>> trace_qemu_file_fclose();
>> return ret;
>> @@ -784,6 +823,6 @@ void qemu_put_counted_string(QEMUFile *f, const char *str)
>> void qemu_file_set_blocking(QEMUFile *f, bool block)
>> {
>> if (f->ops->set_blocking) {
>> - f->ops->set_blocking(f->opaque, block);
>> + f->ops->set_blocking(f->opaque, block, NULL);
>> }
>> }
>> diff --git a/migration/qemu-file.h b/migration/qemu-file.h
>> index 13baf896bd..eb886db65f 100644
>> --- a/migration/qemu-file.h
>> +++ b/migration/qemu-file.h
>> @@ -32,7 +32,8 @@
>> * bytes actually read should be returned.
>> */
>> typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
>> - int64_t pos, size_t size);
>> + int64_t pos, size_t size,
>> + Error **errp);
>>
>> /* Close a file
>> *
>> @@ -41,7 +42,7 @@ typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
>> * The meaning of return value on success depends on the specific back-end being
>> * used.
>> */
>> -typedef int (QEMUFileCloseFunc)(void *opaque);
>> +typedef int (QEMUFileCloseFunc)(void *opaque, Error **errp);
>>
>> /* Called to return the OS file descriptor associated to the QEMUFile.
>> */
>> @@ -49,14 +50,15 @@ typedef int (QEMUFileGetFD)(void *opaque);
>>
>> /* Called to change the blocking mode of the file
>> */
>> -typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled);
>> +typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled, Error **errp);
>>
>> /*
>> * This function writes an iovec to file. The handler must write all
>> * of the data or return a negative errno value.
>> */
>> typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov,
>> - int iovcnt, int64_t pos);
>> + int iovcnt, int64_t pos,
>> + Error **errp);
>>
>> /*
>> * This function provides hooks around different
>> @@ -97,7 +99,8 @@ typedef QEMUFile *(QEMURetPathFunc)(void *opaque);
>> * Existing blocking reads/writes must be woken
>> * Returns 0 on success, -err on error
>> */
>> -typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
>> +typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr,
>> + Error **errp);
>>
>> typedef struct QEMUFileOps {
>> QEMUFileGetBufferFunc *get_buffer;
>> @@ -149,6 +152,8 @@ void qemu_update_position(QEMUFile *f, size_t size);
>> void qemu_file_reset_rate_limit(QEMUFile *f);
>> void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
>> int64_t qemu_file_get_rate_limit(QEMUFile *f);
>> +int qemu_file_get_error_obj(QEMUFile *f, Error **errp);
>> +void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err);
>> void qemu_file_set_error(QEMUFile *f, int ret);
>> int qemu_file_shutdown(QEMUFile *f);
>> QEMUFile *qemu_file_get_return_path(QEMUFile *f);
>> diff --git a/migration/savevm.c b/migration/savevm.c
>> index 34bcad3807..a619af744d 100644
>> --- a/migration/savevm.c
>> +++ b/migration/savevm.c
>> @@ -124,7 +124,7 @@ static struct mig_cmd_args {
>> /* savevm/loadvm support */
>>
>> static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
>> - int64_t pos)
>> + int64_t pos, Error **errp)
>> {
>> int ret;
>> QEMUIOVector qiov;
>> @@ -139,12 +139,12 @@ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
>> }
>>
>> static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
>> - size_t size)
>> + size_t size, Error **errp)
>> {
>> return bdrv_load_vmstate(opaque, buf, pos, size);
>> }
>>
>> -static int bdrv_fclose(void *opaque)
>> +static int bdrv_fclose(void *opaque, Error **errp)
>> {
>> return bdrv_flush(opaque);
>> }
>> --
>> 2.21.0
> --
> Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
Regards,
Yury
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH] migration: Add error_desc for file channel errors
2019-07-17 10:19 ` Yury Kotov
@ 2019-08-06 15:51 ` Dr. David Alan Gilbert
0 siblings, 0 replies; 7+ messages in thread
From: Dr. David Alan Gilbert @ 2019-08-06 15:51 UTC (permalink / raw)
To: Yury Kotov; +Cc: open list:All patches CC here, yc-core, Juan Quintela
* Yury Kotov (yury-kotov@yandex-team.ru) wrote:
> Hi, I'm a bit worried that this patch might have been forgotten.
> Is it queued? Thanks!
I've added it to my list for the pull I'll do as soon as 4.2 opens.
Dave
> 14.06.2019, 19:56, "Dr. David Alan Gilbert" <dgilbert@redhat.com>:
> > * Yury Kotov (yury-kotov@yandex-team.ru) wrote:
> >> Currently, there is no information about error if outgoing migration was failed
> >> because of file channel errors.
> >> Example (QMP session):
> >> -> { "execute": "migrate", "arguments": { "uri": "exec:head -c 1" }}
> >> <- { "return": {} }
> >> ...
> >> -> { "execute": "query-migrate" }
> >> <- { "return": { "status": "failed" }} // There is not error's description
> >>
> >> And even in the QEMU's output there is nothing.
> >>
> >> This patch
> >> 1) Adds errp for the most of QEMUFileOps
> >> 2) Adds qemu_file_get_error_obj/qemu_file_set_error_obj
> >> 3) And finally using of qemu_file_get_error_obj in migration.c
> >>
> >> And now, the status for the mentioned fail will be:
> >> -> { "execute": "query-migrate" }
> >> <- { "return": { "status": "failed",
> >> "error-desc": "Unable to write to command: Broken pipe" }}
> >>
> >> Signed-off-by: Yury Kotov <yury-kotov@yandex-team.ru>
> >
> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> >
> >> ---
> >> migration/migration.c | 10 ++++--
> >> migration/qemu-file-channel.c | 30 +++++++++--------
> >> migration/qemu-file.c | 63 ++++++++++++++++++++++++++++-------
> >> migration/qemu-file.h | 15 ++++++---
> >> migration/savevm.c | 6 ++--
> >> 5 files changed, 88 insertions(+), 36 deletions(-)
> >>
> >> diff --git a/migration/migration.c b/migration/migration.c
> >> index 609e0df5d0..7bcdc4613b 100644
> >> --- a/migration/migration.c
> >> +++ b/migration/migration.c
> >> @@ -2949,6 +2949,7 @@ static MigThrError migration_detect_error(MigrationState *s)
> >> {
> >> int ret;
> >> int state = s->state;
> >> + Error *local_error = NULL;
> >>
> >> if (state == MIGRATION_STATUS_CANCELLING ||
> >> state == MIGRATION_STATUS_CANCELLED) {
> >> @@ -2957,13 +2958,18 @@ static MigThrError migration_detect_error(MigrationState *s)
> >> }
> >>
> >> /* Try to detect any file errors */
> >> - ret = qemu_file_get_error(s->to_dst_file);
> >> -
> >> + ret = qemu_file_get_error_obj(s->to_dst_file, &local_error);
> >> if (!ret) {
> >> /* Everything is fine */
> >> + assert(!local_error);
> >> return MIG_THR_ERR_NONE;
> >> }
> >>
> >> + if (local_error) {
> >> + migrate_set_error(s, local_error);
> >> + error_free(local_error);
> >> + }
> >> +
> >> if (state == MIGRATION_STATUS_POSTCOPY_ACTIVE && ret == -EIO) {
> >> /*
> >> * For postcopy, we allow the network to be down for a
> >> diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c
> >> index 8e639eb496..c382ea2d78 100644
> >> --- a/migration/qemu-file-channel.c
> >> +++ b/migration/qemu-file-channel.c
> >> @@ -33,7 +33,8 @@
> >> static ssize_t channel_writev_buffer(void *opaque,
> >> struct iovec *iov,
> >> int iovcnt,
> >> - int64_t pos)
> >> + int64_t pos,
> >> + Error **errp)
> >> {
> >> QIOChannel *ioc = QIO_CHANNEL(opaque);
> >> ssize_t done = 0;
> >> @@ -47,7 +48,7 @@ static ssize_t channel_writev_buffer(void *opaque,
> >>
> >> while (nlocal_iov > 0) {
> >> ssize_t len;
> >> - len = qio_channel_writev(ioc, local_iov, nlocal_iov, NULL);
> >> + len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
> >> if (len == QIO_CHANNEL_ERR_BLOCK) {
> >> if (qemu_in_coroutine()) {
> >> qio_channel_yield(ioc, G_IO_OUT);
> >> @@ -57,7 +58,6 @@ static ssize_t channel_writev_buffer(void *opaque,
> >> continue;
> >> }
> >> if (len < 0) {
> >> - /* XXX handle Error objects */
> >> done = -EIO;
> >> goto cleanup;
> >> }
> >> @@ -75,13 +75,14 @@ static ssize_t channel_writev_buffer(void *opaque,
> >> static ssize_t channel_get_buffer(void *opaque,
> >> uint8_t *buf,
> >> int64_t pos,
> >> - size_t size)
> >> + size_t size,
> >> + Error **errp)
> >> {
> >> QIOChannel *ioc = QIO_CHANNEL(opaque);
> >> ssize_t ret;
> >>
> >> do {
> >> - ret = qio_channel_read(ioc, (char *)buf, size, NULL);
> >> + ret = qio_channel_read(ioc, (char *)buf, size, errp);
> >> if (ret < 0) {
> >> if (ret == QIO_CHANNEL_ERR_BLOCK) {
> >> if (qemu_in_coroutine()) {
> >> @@ -90,7 +91,6 @@ static ssize_t channel_get_buffer(void *opaque,
> >> qio_channel_wait(ioc, G_IO_IN);
> >> }
> >> } else {
> >> - /* XXX handle Error * object */
> >> return -EIO;
> >> }
> >> }
> >> @@ -100,18 +100,20 @@ static ssize_t channel_get_buffer(void *opaque,
> >> }
> >>
> >> -static int channel_close(void *opaque)
> >> +static int channel_close(void *opaque, Error **errp)
> >> {
> >> + int ret;
> >> QIOChannel *ioc = QIO_CHANNEL(opaque);
> >> - qio_channel_close(ioc, NULL);
> >> + ret = qio_channel_close(ioc, errp);
> >> object_unref(OBJECT(ioc));
> >> - return 0;
> >> + return ret;
> >> }
> >>
> >> static int channel_shutdown(void *opaque,
> >> bool rd,
> >> - bool wr)
> >> + bool wr,
> >> + Error **errp)
> >> {
> >> QIOChannel *ioc = QIO_CHANNEL(opaque);
> >>
> >> @@ -125,8 +127,7 @@ static int channel_shutdown(void *opaque,
> >> } else {
> >> mode = QIO_CHANNEL_SHUTDOWN_WRITE;
> >> }
> >> - if (qio_channel_shutdown(ioc, mode, NULL) < 0) {
> >> - /* XXX handler Error * object */
> >> + if (qio_channel_shutdown(ioc, mode, errp) < 0) {
> >> return -EIO;
> >> }
> >> }
> >> @@ -135,11 +136,12 @@ static int channel_shutdown(void *opaque,
> >>
> >> static int channel_set_blocking(void *opaque,
> >> - bool enabled)
> >> + bool enabled,
> >> + Error **errp)
> >> {
> >> QIOChannel *ioc = QIO_CHANNEL(opaque);
> >>
> >> - if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) {
> >> + if (qio_channel_set_blocking(ioc, enabled, errp) < 0) {
> >> return -1;
> >> }
> >> return 0;
> >> diff --git a/migration/qemu-file.c b/migration/qemu-file.c
> >> index 977b9ae07c..c52160e08b 100644
> >> --- a/migration/qemu-file.c
> >> +++ b/migration/qemu-file.c
> >> @@ -29,6 +29,7 @@
> >> #include "migration.h"
> >> #include "qemu-file.h"
> >> #include "trace.h"
> >> +#include "qapi/error.h"
> >>
> >> #define IO_BUF_SIZE 32768
> >> #define MAX_IOV_SIZE MIN(IOV_MAX, 64)
> >> @@ -52,6 +53,7 @@ struct QEMUFile {
> >> unsigned int iovcnt;
> >>
> >> int last_error;
> >> + Error *last_error_obj;
> >> };
> >>
> >> /*
> >> @@ -63,7 +65,7 @@ int qemu_file_shutdown(QEMUFile *f)
> >> if (!f->ops->shut_down) {
> >> return -ENOSYS;
> >> }
> >> - return f->ops->shut_down(f->opaque, true, true);
> >> + return f->ops->shut_down(f->opaque, true, true, NULL);
> >> }
> >>
> >> /*
> >> @@ -108,24 +110,55 @@ void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks)
> >> }
> >>
> >> /*
> >> - * Get last error for stream f
> >> + * Get last error for stream f with optional Error*
> >> *
> >> * Return negative error value if there has been an error on previous
> >> * operations, return 0 if no error happened.
> >> + * Optional, it returns Error* in errp, but it may be NULL even if return value
> >> + * is not 0.
> >> *
> >> */
> >> -int qemu_file_get_error(QEMUFile *f)
> >> +int qemu_file_get_error_obj(QEMUFile *f, Error **errp)
> >> {
> >> + if (errp) {
> >> + *errp = f->last_error_obj ? error_copy(f->last_error_obj) : NULL;
> >> + }
> >> return f->last_error;
> >> }
> >>
> >> -void qemu_file_set_error(QEMUFile *f, int ret)
> >> +/*
> >> + * Set the last error for stream f with optional Error*
> >> + */
> >> +void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err)
> >> {
> >> - if (f->last_error == 0) {
> >> + if (f->last_error == 0 && ret) {
> >> f->last_error = ret;
> >> + error_propagate(&f->last_error_obj, err);
> >> + } else if (err) {
> >> + error_report_err(err);
> >> }
> >> }
> >>
> >> +/*
> >> + * Get last error for stream f
> >> + *
> >> + * Return negative error value if there has been an error on previous
> >> + * operations, return 0 if no error happened.
> >> + *
> >> + */
> >> +int qemu_file_get_error(QEMUFile *f)
> >> +{
> >> + return qemu_file_get_error_obj(f, NULL);
> >> +}
> >> +
> >> +/*
> >> + * Set the last error for stream f
> >> + */
> >> +void qemu_file_set_error(QEMUFile *f, int ret)
> >> +{
> >> + qemu_file_set_error_obj(f, ret, NULL);
> >> +}
> >> +
> >> bool qemu_file_is_writable(QEMUFile *f)
> >> {
> >> return f->ops->writev_buffer;
> >> @@ -177,6 +210,7 @@ void qemu_fflush(QEMUFile *f)
> >> {
> >> ssize_t ret = 0;
> >> ssize_t expect = 0;
> >> + Error *local_error = NULL;
> >>
> >> if (!qemu_file_is_writable(f)) {
> >> return;
> >> @@ -184,7 +218,8 @@ void qemu_fflush(QEMUFile *f)
> >>
> >> if (f->iovcnt > 0) {
> >> expect = iov_size(f->iov, f->iovcnt);
> >> - ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
> >> + ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos,
> >> + &local_error);
> >>
> >> qemu_iovec_release_ram(f);
> >> }
> >> @@ -196,7 +231,7 @@ void qemu_fflush(QEMUFile *f)
> >> * data set we requested, so sanity check that.
> >> */
> >> if (ret != expect) {
> >> - qemu_file_set_error(f, ret < 0 ? ret : -EIO);
> >> + qemu_file_set_error_obj(f, ret < 0 ? ret : -EIO, local_error);
> >> }
> >> f->buf_index = 0;
> >> f->iovcnt = 0;
> >> @@ -284,6 +319,7 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
> >> {
> >> int len;
> >> int pending;
> >> + Error *local_error = NULL;
> >>
> >> assert(!qemu_file_is_writable(f));
> >>
> >> @@ -295,14 +331,16 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
> >> f->buf_size = pending;
> >>
> >> len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
> >> - IO_BUF_SIZE - pending);
> >> + IO_BUF_SIZE - pending, &local_error);
> >> if (len > 0) {
> >> f->buf_size += len;
> >> f->pos += len;
> >> } else if (len == 0) {
> >> - qemu_file_set_error(f, -EIO);
> >> + qemu_file_set_error_obj(f, -EIO, local_error);
> >> } else if (len != -EAGAIN) {
> >> - qemu_file_set_error(f, len);
> >> + qemu_file_set_error_obj(f, len, local_error);
> >> + } else {
> >> + error_free(local_error);
> >> }
> >>
> >> return len;
> >> @@ -328,7 +366,7 @@ int qemu_fclose(QEMUFile *f)
> >> ret = qemu_file_get_error(f);
> >>
> >> if (f->ops->close) {
> >> - int ret2 = f->ops->close(f->opaque);
> >> + int ret2 = f->ops->close(f->opaque, NULL);
> >> if (ret >= 0) {
> >> ret = ret2;
> >> }
> >> @@ -339,6 +377,7 @@ int qemu_fclose(QEMUFile *f)
> >> if (f->last_error) {
> >> ret = f->last_error;
> >> }
> >> + error_free(f->last_error_obj);
> >> g_free(f);
> >> trace_qemu_file_fclose();
> >> return ret;
> >> @@ -784,6 +823,6 @@ void qemu_put_counted_string(QEMUFile *f, const char *str)
> >> void qemu_file_set_blocking(QEMUFile *f, bool block)
> >> {
> >> if (f->ops->set_blocking) {
> >> - f->ops->set_blocking(f->opaque, block);
> >> + f->ops->set_blocking(f->opaque, block, NULL);
> >> }
> >> }
> >> diff --git a/migration/qemu-file.h b/migration/qemu-file.h
> >> index 13baf896bd..eb886db65f 100644
> >> --- a/migration/qemu-file.h
> >> +++ b/migration/qemu-file.h
> >> @@ -32,7 +32,8 @@
> >> * bytes actually read should be returned.
> >> */
> >> typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
> >> - int64_t pos, size_t size);
> >> + int64_t pos, size_t size,
> >> + Error **errp);
> >>
> >> /* Close a file
> >> *
> >> @@ -41,7 +42,7 @@ typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
> >> * The meaning of return value on success depends on the specific back-end being
> >> * used.
> >> */
> >> -typedef int (QEMUFileCloseFunc)(void *opaque);
> >> +typedef int (QEMUFileCloseFunc)(void *opaque, Error **errp);
> >>
> >> /* Called to return the OS file descriptor associated to the QEMUFile.
> >> */
> >> @@ -49,14 +50,15 @@ typedef int (QEMUFileGetFD)(void *opaque);
> >>
> >> /* Called to change the blocking mode of the file
> >> */
> >> -typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled);
> >> +typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled, Error **errp);
> >>
> >> /*
> >> * This function writes an iovec to file. The handler must write all
> >> * of the data or return a negative errno value.
> >> */
> >> typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov,
> >> - int iovcnt, int64_t pos);
> >> + int iovcnt, int64_t pos,
> >> + Error **errp);
> >>
> >> /*
> >> * This function provides hooks around different
> >> @@ -97,7 +99,8 @@ typedef QEMUFile *(QEMURetPathFunc)(void *opaque);
> >> * Existing blocking reads/writes must be woken
> >> * Returns 0 on success, -err on error
> >> */
> >> -typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
> >> +typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr,
> >> + Error **errp);
> >>
> >> typedef struct QEMUFileOps {
> >> QEMUFileGetBufferFunc *get_buffer;
> >> @@ -149,6 +152,8 @@ void qemu_update_position(QEMUFile *f, size_t size);
> >> void qemu_file_reset_rate_limit(QEMUFile *f);
> >> void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
> >> int64_t qemu_file_get_rate_limit(QEMUFile *f);
> >> +int qemu_file_get_error_obj(QEMUFile *f, Error **errp);
> >> +void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err);
> >> void qemu_file_set_error(QEMUFile *f, int ret);
> >> int qemu_file_shutdown(QEMUFile *f);
> >> QEMUFile *qemu_file_get_return_path(QEMUFile *f);
> >> diff --git a/migration/savevm.c b/migration/savevm.c
> >> index 34bcad3807..a619af744d 100644
> >> --- a/migration/savevm.c
> >> +++ b/migration/savevm.c
> >> @@ -124,7 +124,7 @@ static struct mig_cmd_args {
> >> /* savevm/loadvm support */
> >>
> >> static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
> >> - int64_t pos)
> >> + int64_t pos, Error **errp)
> >> {
> >> int ret;
> >> QEMUIOVector qiov;
> >> @@ -139,12 +139,12 @@ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
> >> }
> >>
> >> static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
> >> - size_t size)
> >> + size_t size, Error **errp)
> >> {
> >> return bdrv_load_vmstate(opaque, buf, pos, size);
> >> }
> >>
> >> -static int bdrv_fclose(void *opaque)
> >> +static int bdrv_fclose(void *opaque, Error **errp)
> >> {
> >> return bdrv_flush(opaque);
> >> }
> >> --
> >> 2.21.0
> > --
> > Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
>
> Regards,
> Yury
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH] migration: Add error_desc for file channel errors
2019-04-22 10:34 [Qemu-devel] [PATCH] migration: Add error_desc for file channel errors Yury Kotov
` (2 preceding siblings ...)
2019-06-14 16:39 ` Dr. David Alan Gilbert
@ 2019-08-07 17:08 ` Dr. David Alan Gilbert
3 siblings, 0 replies; 7+ messages in thread
From: Dr. David Alan Gilbert @ 2019-08-07 17:08 UTC (permalink / raw)
To: Yury Kotov; +Cc: open list:All patches CC here, yc-core, Juan Quintela
* Yury Kotov (yury-kotov@yandex-team.ru) wrote:
> Currently, there is no information about error if outgoing migration was failed
> because of file channel errors.
> Example (QMP session):
> -> { "execute": "migrate", "arguments": { "uri": "exec:head -c 1" }}
> <- { "return": {} }
> ...
> -> { "execute": "query-migrate" }
> <- { "return": { "status": "failed" }} // There is not error's description
>
> And even in the QEMU's output there is nothing.
>
> This patch
> 1) Adds errp for the most of QEMUFileOps
> 2) Adds qemu_file_get_error_obj/qemu_file_set_error_obj
> 3) And finally using of qemu_file_get_error_obj in migration.c
>
> And now, the status for the mentioned fail will be:
> -> { "execute": "query-migrate" }
> <- { "return": { "status": "failed",
> "error-desc": "Unable to write to command: Broken pipe" }}
>
> Signed-off-by: Yury Kotov <yury-kotov@yandex-team.ru>
Quued for 4.2
> ---
> migration/migration.c | 10 ++++--
> migration/qemu-file-channel.c | 30 +++++++++--------
> migration/qemu-file.c | 63 ++++++++++++++++++++++++++++-------
> migration/qemu-file.h | 15 ++++++---
> migration/savevm.c | 6 ++--
> 5 files changed, 88 insertions(+), 36 deletions(-)
>
> diff --git a/migration/migration.c b/migration/migration.c
> index 609e0df5d0..7bcdc4613b 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -2949,6 +2949,7 @@ static MigThrError migration_detect_error(MigrationState *s)
> {
> int ret;
> int state = s->state;
> + Error *local_error = NULL;
>
> if (state == MIGRATION_STATUS_CANCELLING ||
> state == MIGRATION_STATUS_CANCELLED) {
> @@ -2957,13 +2958,18 @@ static MigThrError migration_detect_error(MigrationState *s)
> }
>
> /* Try to detect any file errors */
> - ret = qemu_file_get_error(s->to_dst_file);
> -
> + ret = qemu_file_get_error_obj(s->to_dst_file, &local_error);
> if (!ret) {
> /* Everything is fine */
> + assert(!local_error);
> return MIG_THR_ERR_NONE;
> }
>
> + if (local_error) {
> + migrate_set_error(s, local_error);
> + error_free(local_error);
> + }
> +
> if (state == MIGRATION_STATUS_POSTCOPY_ACTIVE && ret == -EIO) {
> /*
> * For postcopy, we allow the network to be down for a
> diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c
> index 8e639eb496..c382ea2d78 100644
> --- a/migration/qemu-file-channel.c
> +++ b/migration/qemu-file-channel.c
> @@ -33,7 +33,8 @@
> static ssize_t channel_writev_buffer(void *opaque,
> struct iovec *iov,
> int iovcnt,
> - int64_t pos)
> + int64_t pos,
> + Error **errp)
> {
> QIOChannel *ioc = QIO_CHANNEL(opaque);
> ssize_t done = 0;
> @@ -47,7 +48,7 @@ static ssize_t channel_writev_buffer(void *opaque,
>
> while (nlocal_iov > 0) {
> ssize_t len;
> - len = qio_channel_writev(ioc, local_iov, nlocal_iov, NULL);
> + len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
> if (len == QIO_CHANNEL_ERR_BLOCK) {
> if (qemu_in_coroutine()) {
> qio_channel_yield(ioc, G_IO_OUT);
> @@ -57,7 +58,6 @@ static ssize_t channel_writev_buffer(void *opaque,
> continue;
> }
> if (len < 0) {
> - /* XXX handle Error objects */
> done = -EIO;
> goto cleanup;
> }
> @@ -75,13 +75,14 @@ static ssize_t channel_writev_buffer(void *opaque,
> static ssize_t channel_get_buffer(void *opaque,
> uint8_t *buf,
> int64_t pos,
> - size_t size)
> + size_t size,
> + Error **errp)
> {
> QIOChannel *ioc = QIO_CHANNEL(opaque);
> ssize_t ret;
>
> do {
> - ret = qio_channel_read(ioc, (char *)buf, size, NULL);
> + ret = qio_channel_read(ioc, (char *)buf, size, errp);
> if (ret < 0) {
> if (ret == QIO_CHANNEL_ERR_BLOCK) {
> if (qemu_in_coroutine()) {
> @@ -90,7 +91,6 @@ static ssize_t channel_get_buffer(void *opaque,
> qio_channel_wait(ioc, G_IO_IN);
> }
> } else {
> - /* XXX handle Error * object */
> return -EIO;
> }
> }
> @@ -100,18 +100,20 @@ static ssize_t channel_get_buffer(void *opaque,
> }
>
>
> -static int channel_close(void *opaque)
> +static int channel_close(void *opaque, Error **errp)
> {
> + int ret;
> QIOChannel *ioc = QIO_CHANNEL(opaque);
> - qio_channel_close(ioc, NULL);
> + ret = qio_channel_close(ioc, errp);
> object_unref(OBJECT(ioc));
> - return 0;
> + return ret;
> }
>
>
> static int channel_shutdown(void *opaque,
> bool rd,
> - bool wr)
> + bool wr,
> + Error **errp)
> {
> QIOChannel *ioc = QIO_CHANNEL(opaque);
>
> @@ -125,8 +127,7 @@ static int channel_shutdown(void *opaque,
> } else {
> mode = QIO_CHANNEL_SHUTDOWN_WRITE;
> }
> - if (qio_channel_shutdown(ioc, mode, NULL) < 0) {
> - /* XXX handler Error * object */
> + if (qio_channel_shutdown(ioc, mode, errp) < 0) {
> return -EIO;
> }
> }
> @@ -135,11 +136,12 @@ static int channel_shutdown(void *opaque,
>
>
> static int channel_set_blocking(void *opaque,
> - bool enabled)
> + bool enabled,
> + Error **errp)
> {
> QIOChannel *ioc = QIO_CHANNEL(opaque);
>
> - if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) {
> + if (qio_channel_set_blocking(ioc, enabled, errp) < 0) {
> return -1;
> }
> return 0;
> diff --git a/migration/qemu-file.c b/migration/qemu-file.c
> index 977b9ae07c..c52160e08b 100644
> --- a/migration/qemu-file.c
> +++ b/migration/qemu-file.c
> @@ -29,6 +29,7 @@
> #include "migration.h"
> #include "qemu-file.h"
> #include "trace.h"
> +#include "qapi/error.h"
>
> #define IO_BUF_SIZE 32768
> #define MAX_IOV_SIZE MIN(IOV_MAX, 64)
> @@ -52,6 +53,7 @@ struct QEMUFile {
> unsigned int iovcnt;
>
> int last_error;
> + Error *last_error_obj;
> };
>
> /*
> @@ -63,7 +65,7 @@ int qemu_file_shutdown(QEMUFile *f)
> if (!f->ops->shut_down) {
> return -ENOSYS;
> }
> - return f->ops->shut_down(f->opaque, true, true);
> + return f->ops->shut_down(f->opaque, true, true, NULL);
> }
>
> /*
> @@ -108,24 +110,55 @@ void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks)
> }
>
> /*
> - * Get last error for stream f
> + * Get last error for stream f with optional Error*
> *
> * Return negative error value if there has been an error on previous
> * operations, return 0 if no error happened.
> + * Optional, it returns Error* in errp, but it may be NULL even if return value
> + * is not 0.
> *
> */
> -int qemu_file_get_error(QEMUFile *f)
> +int qemu_file_get_error_obj(QEMUFile *f, Error **errp)
> {
> + if (errp) {
> + *errp = f->last_error_obj ? error_copy(f->last_error_obj) : NULL;
> + }
> return f->last_error;
> }
>
> -void qemu_file_set_error(QEMUFile *f, int ret)
> +/*
> + * Set the last error for stream f with optional Error*
> + */
> +void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err)
> {
> - if (f->last_error == 0) {
> + if (f->last_error == 0 && ret) {
> f->last_error = ret;
> + error_propagate(&f->last_error_obj, err);
> + } else if (err) {
> + error_report_err(err);
> }
> }
>
> +/*
> + * Get last error for stream f
> + *
> + * Return negative error value if there has been an error on previous
> + * operations, return 0 if no error happened.
> + *
> + */
> +int qemu_file_get_error(QEMUFile *f)
> +{
> + return qemu_file_get_error_obj(f, NULL);
> +}
> +
> +/*
> + * Set the last error for stream f
> + */
> +void qemu_file_set_error(QEMUFile *f, int ret)
> +{
> + qemu_file_set_error_obj(f, ret, NULL);
> +}
> +
> bool qemu_file_is_writable(QEMUFile *f)
> {
> return f->ops->writev_buffer;
> @@ -177,6 +210,7 @@ void qemu_fflush(QEMUFile *f)
> {
> ssize_t ret = 0;
> ssize_t expect = 0;
> + Error *local_error = NULL;
>
> if (!qemu_file_is_writable(f)) {
> return;
> @@ -184,7 +218,8 @@ void qemu_fflush(QEMUFile *f)
>
> if (f->iovcnt > 0) {
> expect = iov_size(f->iov, f->iovcnt);
> - ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
> + ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos,
> + &local_error);
>
> qemu_iovec_release_ram(f);
> }
> @@ -196,7 +231,7 @@ void qemu_fflush(QEMUFile *f)
> * data set we requested, so sanity check that.
> */
> if (ret != expect) {
> - qemu_file_set_error(f, ret < 0 ? ret : -EIO);
> + qemu_file_set_error_obj(f, ret < 0 ? ret : -EIO, local_error);
> }
> f->buf_index = 0;
> f->iovcnt = 0;
> @@ -284,6 +319,7 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
> {
> int len;
> int pending;
> + Error *local_error = NULL;
>
> assert(!qemu_file_is_writable(f));
>
> @@ -295,14 +331,16 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
> f->buf_size = pending;
>
> len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
> - IO_BUF_SIZE - pending);
> + IO_BUF_SIZE - pending, &local_error);
> if (len > 0) {
> f->buf_size += len;
> f->pos += len;
> } else if (len == 0) {
> - qemu_file_set_error(f, -EIO);
> + qemu_file_set_error_obj(f, -EIO, local_error);
> } else if (len != -EAGAIN) {
> - qemu_file_set_error(f, len);
> + qemu_file_set_error_obj(f, len, local_error);
> + } else {
> + error_free(local_error);
> }
>
> return len;
> @@ -328,7 +366,7 @@ int qemu_fclose(QEMUFile *f)
> ret = qemu_file_get_error(f);
>
> if (f->ops->close) {
> - int ret2 = f->ops->close(f->opaque);
> + int ret2 = f->ops->close(f->opaque, NULL);
> if (ret >= 0) {
> ret = ret2;
> }
> @@ -339,6 +377,7 @@ int qemu_fclose(QEMUFile *f)
> if (f->last_error) {
> ret = f->last_error;
> }
> + error_free(f->last_error_obj);
> g_free(f);
> trace_qemu_file_fclose();
> return ret;
> @@ -784,6 +823,6 @@ void qemu_put_counted_string(QEMUFile *f, const char *str)
> void qemu_file_set_blocking(QEMUFile *f, bool block)
> {
> if (f->ops->set_blocking) {
> - f->ops->set_blocking(f->opaque, block);
> + f->ops->set_blocking(f->opaque, block, NULL);
> }
> }
> diff --git a/migration/qemu-file.h b/migration/qemu-file.h
> index 13baf896bd..eb886db65f 100644
> --- a/migration/qemu-file.h
> +++ b/migration/qemu-file.h
> @@ -32,7 +32,8 @@
> * bytes actually read should be returned.
> */
> typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
> - int64_t pos, size_t size);
> + int64_t pos, size_t size,
> + Error **errp);
>
> /* Close a file
> *
> @@ -41,7 +42,7 @@ typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
> * The meaning of return value on success depends on the specific back-end being
> * used.
> */
> -typedef int (QEMUFileCloseFunc)(void *opaque);
> +typedef int (QEMUFileCloseFunc)(void *opaque, Error **errp);
>
> /* Called to return the OS file descriptor associated to the QEMUFile.
> */
> @@ -49,14 +50,15 @@ typedef int (QEMUFileGetFD)(void *opaque);
>
> /* Called to change the blocking mode of the file
> */
> -typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled);
> +typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled, Error **errp);
>
> /*
> * This function writes an iovec to file. The handler must write all
> * of the data or return a negative errno value.
> */
> typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov,
> - int iovcnt, int64_t pos);
> + int iovcnt, int64_t pos,
> + Error **errp);
>
> /*
> * This function provides hooks around different
> @@ -97,7 +99,8 @@ typedef QEMUFile *(QEMURetPathFunc)(void *opaque);
> * Existing blocking reads/writes must be woken
> * Returns 0 on success, -err on error
> */
> -typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
> +typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr,
> + Error **errp);
>
> typedef struct QEMUFileOps {
> QEMUFileGetBufferFunc *get_buffer;
> @@ -149,6 +152,8 @@ void qemu_update_position(QEMUFile *f, size_t size);
> void qemu_file_reset_rate_limit(QEMUFile *f);
> void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
> int64_t qemu_file_get_rate_limit(QEMUFile *f);
> +int qemu_file_get_error_obj(QEMUFile *f, Error **errp);
> +void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err);
> void qemu_file_set_error(QEMUFile *f, int ret);
> int qemu_file_shutdown(QEMUFile *f);
> QEMUFile *qemu_file_get_return_path(QEMUFile *f);
> diff --git a/migration/savevm.c b/migration/savevm.c
> index 34bcad3807..a619af744d 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -124,7 +124,7 @@ static struct mig_cmd_args {
> /* savevm/loadvm support */
>
> static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
> - int64_t pos)
> + int64_t pos, Error **errp)
> {
> int ret;
> QEMUIOVector qiov;
> @@ -139,12 +139,12 @@ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
> }
>
> static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
> - size_t size)
> + size_t size, Error **errp)
> {
> return bdrv_load_vmstate(opaque, buf, pos, size);
> }
>
> -static int bdrv_fclose(void *opaque)
> +static int bdrv_fclose(void *opaque, Error **errp)
> {
> return bdrv_flush(opaque);
> }
> --
> 2.21.0
>
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2019-08-07 17:09 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-22 10:34 [Qemu-devel] [PATCH] migration: Add error_desc for file channel errors Yury Kotov
2019-04-22 10:34 ` Yury Kotov
2019-06-07 9:02 ` Yury Kotov
2019-06-14 16:39 ` Dr. David Alan Gilbert
2019-07-17 10:19 ` Yury Kotov
2019-08-06 15:51 ` Dr. David Alan Gilbert
2019-08-07 17:08 ` Dr. David Alan Gilbert
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).