Commit 3d661c8a authored by Yury Kotov's avatar Yury Kotov Committed by Dr. David Alan Gilbert
Browse files

migration: Add error_desc for file channel errors



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: default avatarYury Kotov <yury-kotov@yandex-team.ru>
Message-Id: <20190422103420.15686-1-yury-kotov@yandex-team.ru>
Reviewed-by: default avatarDr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: default avatarDr. David Alan Gilbert <dgilbert@redhat.com>
parent f28ed74f
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -2963,6 +2963,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) {
@@ -2971,13 +2972,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
+16 −14
Original line number Diff line number Diff line
@@ -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;
+51 −12
Original line number Diff line number Diff line
@@ -28,6 +28,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)
@@ -51,6 +52,7 @@ struct QEMUFile {
    unsigned int iovcnt;

    int last_error;
    Error *last_error_obj;
};

/*
@@ -62,7 +64,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);
}

/*
@@ -107,22 +109,53 @@ 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)
@@ -176,6 +209,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;
@@ -183,7 +217,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);
    }
@@ -195,7 +230,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;
@@ -283,6 +318,7 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
{
    int len;
    int pending;
    Error *local_error = NULL;

    assert(!qemu_file_is_writable(f));

@@ -294,14 +330,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;
@@ -327,7 +365,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;
        }
@@ -338,6 +376,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;
@@ -783,6 +822,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);
    }
}
+10 −5
Original line number Diff line number Diff line
@@ -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);
+3 −3
Original line number Diff line number Diff line
@@ -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);
}