qemu/migration/qemu-file-channel.c
<<
>>
Prefs
   1/*
   2 * QEMUFile backend for QIOChannel objects
   3 *
   4 * Copyright (c) 2015-2016 Red Hat, Inc
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "qemu-file-channel.h"
  27#include "qemu-file.h"
  28#include "io/channel-socket.h"
  29#include "io/channel-tls.h"
  30#include "qemu/iov.h"
  31#include "qemu/yank.h"
  32#include "yank_functions.h"
  33
  34
  35static ssize_t channel_writev_buffer(void *opaque,
  36                                     struct iovec *iov,
  37                                     int iovcnt,
  38                                     int64_t pos,
  39                                     Error **errp)
  40{
  41    QIOChannel *ioc = QIO_CHANNEL(opaque);
  42    ssize_t done = 0;
  43    struct iovec *local_iov = g_new(struct iovec, iovcnt);
  44    struct iovec *local_iov_head = local_iov;
  45    unsigned int nlocal_iov = iovcnt;
  46
  47    nlocal_iov = iov_copy(local_iov, nlocal_iov,
  48                          iov, iovcnt,
  49                          0, iov_size(iov, iovcnt));
  50
  51    while (nlocal_iov > 0) {
  52        ssize_t len;
  53        len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
  54        if (len == QIO_CHANNEL_ERR_BLOCK) {
  55            if (qemu_in_coroutine()) {
  56                qio_channel_yield(ioc, G_IO_OUT);
  57            } else {
  58                qio_channel_wait(ioc, G_IO_OUT);
  59            }
  60            continue;
  61        }
  62        if (len < 0) {
  63            done = -EIO;
  64            goto cleanup;
  65        }
  66
  67        iov_discard_front(&local_iov, &nlocal_iov, len);
  68        done += len;
  69    }
  70
  71 cleanup:
  72    g_free(local_iov_head);
  73    return done;
  74}
  75
  76
  77static ssize_t channel_get_buffer(void *opaque,
  78                                  uint8_t *buf,
  79                                  int64_t pos,
  80                                  size_t size,
  81                                  Error **errp)
  82{
  83    QIOChannel *ioc = QIO_CHANNEL(opaque);
  84    ssize_t ret;
  85
  86    do {
  87        ret = qio_channel_read(ioc, (char *)buf, size, errp);
  88        if (ret < 0) {
  89            if (ret == QIO_CHANNEL_ERR_BLOCK) {
  90                if (qemu_in_coroutine()) {
  91                    qio_channel_yield(ioc, G_IO_IN);
  92                } else {
  93                    qio_channel_wait(ioc, G_IO_IN);
  94                }
  95            } else {
  96                return -EIO;
  97            }
  98        }
  99    } while (ret == QIO_CHANNEL_ERR_BLOCK);
 100
 101    return ret;
 102}
 103
 104
 105static int channel_close(void *opaque, Error **errp)
 106{
 107    int ret;
 108    QIOChannel *ioc = QIO_CHANNEL(opaque);
 109    ret = qio_channel_close(ioc, errp);
 110    if ((object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) ||
 111         object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS))
 112        && OBJECT(ioc)->ref == 1) {
 113        yank_unregister_function(MIGRATION_YANK_INSTANCE,
 114                                 migration_yank_iochannel,
 115                                 QIO_CHANNEL(ioc));
 116    }
 117    object_unref(OBJECT(ioc));
 118    return ret;
 119}
 120
 121
 122static int channel_shutdown(void *opaque,
 123                            bool rd,
 124                            bool wr,
 125                            Error **errp)
 126{
 127    QIOChannel *ioc = QIO_CHANNEL(opaque);
 128
 129    if (qio_channel_has_feature(ioc,
 130                                QIO_CHANNEL_FEATURE_SHUTDOWN)) {
 131        QIOChannelShutdown mode;
 132        if (rd && wr) {
 133            mode = QIO_CHANNEL_SHUTDOWN_BOTH;
 134        } else if (rd) {
 135            mode = QIO_CHANNEL_SHUTDOWN_READ;
 136        } else {
 137            mode = QIO_CHANNEL_SHUTDOWN_WRITE;
 138        }
 139        if (qio_channel_shutdown(ioc, mode, errp) < 0) {
 140            return -EIO;
 141        }
 142    }
 143    return 0;
 144}
 145
 146
 147static int channel_set_blocking(void *opaque,
 148                                bool enabled,
 149                                Error **errp)
 150{
 151    QIOChannel *ioc = QIO_CHANNEL(opaque);
 152
 153    if (qio_channel_set_blocking(ioc, enabled, errp) < 0) {
 154        return -1;
 155    }
 156    return 0;
 157}
 158
 159static QEMUFile *channel_get_input_return_path(void *opaque)
 160{
 161    QIOChannel *ioc = QIO_CHANNEL(opaque);
 162
 163    return qemu_fopen_channel_output(ioc);
 164}
 165
 166static QEMUFile *channel_get_output_return_path(void *opaque)
 167{
 168    QIOChannel *ioc = QIO_CHANNEL(opaque);
 169
 170    return qemu_fopen_channel_input(ioc);
 171}
 172
 173static const QEMUFileOps channel_input_ops = {
 174    .get_buffer = channel_get_buffer,
 175    .close = channel_close,
 176    .shut_down = channel_shutdown,
 177    .set_blocking = channel_set_blocking,
 178    .get_return_path = channel_get_input_return_path,
 179};
 180
 181
 182static const QEMUFileOps channel_output_ops = {
 183    .writev_buffer = channel_writev_buffer,
 184    .close = channel_close,
 185    .shut_down = channel_shutdown,
 186    .set_blocking = channel_set_blocking,
 187    .get_return_path = channel_get_output_return_path,
 188};
 189
 190
 191QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc)
 192{
 193    object_ref(OBJECT(ioc));
 194    return qemu_fopen_ops(ioc, &channel_input_ops);
 195}
 196
 197QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc)
 198{
 199    object_ref(OBJECT(ioc));
 200    return qemu_fopen_ops(ioc, &channel_output_ops);
 201}
 202