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 "exec/cpu-common.h"
  28#include "qemu-file.h"
  29#include "io/channel-socket.h"
  30#include "qemu/iov.h"
  31
  32
  33static ssize_t channel_writev_buffer(void *opaque,
  34                                     struct iovec *iov,
  35                                     int iovcnt,
  36                                     int64_t pos)
  37{
  38    QIOChannel *ioc = QIO_CHANNEL(opaque);
  39    ssize_t done = 0;
  40    struct iovec *local_iov = g_new(struct iovec, iovcnt);
  41    struct iovec *local_iov_head = local_iov;
  42    unsigned int nlocal_iov = iovcnt;
  43
  44    nlocal_iov = iov_copy(local_iov, nlocal_iov,
  45                          iov, iovcnt,
  46                          0, iov_size(iov, iovcnt));
  47
  48    while (nlocal_iov > 0) {
  49        ssize_t len;
  50        len = qio_channel_writev(ioc, local_iov, nlocal_iov, NULL);
  51        if (len == QIO_CHANNEL_ERR_BLOCK) {
  52            if (qemu_in_coroutine()) {
  53                qio_channel_yield(ioc, G_IO_OUT);
  54            } else {
  55                qio_channel_wait(ioc, G_IO_OUT);
  56            }
  57            continue;
  58        }
  59        if (len < 0) {
  60            /* XXX handle Error objects */
  61            done = -EIO;
  62            goto cleanup;
  63        }
  64
  65        iov_discard_front(&local_iov, &nlocal_iov, len);
  66        done += len;
  67    }
  68
  69 cleanup:
  70    g_free(local_iov_head);
  71    return done;
  72}
  73
  74
  75static ssize_t channel_get_buffer(void *opaque,
  76                                  uint8_t *buf,
  77                                  int64_t pos,
  78                                  size_t size)
  79{
  80    QIOChannel *ioc = QIO_CHANNEL(opaque);
  81    ssize_t ret;
  82
  83    do {
  84        ret = qio_channel_read(ioc, (char *)buf, size, NULL);
  85        if (ret < 0) {
  86            if (ret == QIO_CHANNEL_ERR_BLOCK) {
  87                if (qemu_in_coroutine()) {
  88                    qio_channel_yield(ioc, G_IO_IN);
  89                } else {
  90                    qio_channel_wait(ioc, G_IO_IN);
  91                }
  92            } else {
  93                /* XXX handle Error * object */
  94                return -EIO;
  95            }
  96        }
  97    } while (ret == QIO_CHANNEL_ERR_BLOCK);
  98
  99    return ret;
 100}
 101
 102
 103static int channel_close(void *opaque)
 104{
 105    QIOChannel *ioc = QIO_CHANNEL(opaque);
 106    qio_channel_close(ioc, NULL);
 107    object_unref(OBJECT(ioc));
 108    return 0;
 109}
 110
 111
 112static int channel_shutdown(void *opaque,
 113                            bool rd,
 114                            bool wr)
 115{
 116    QIOChannel *ioc = QIO_CHANNEL(opaque);
 117
 118    if (qio_channel_has_feature(ioc,
 119                                QIO_CHANNEL_FEATURE_SHUTDOWN)) {
 120        QIOChannelShutdown mode;
 121        if (rd && wr) {
 122            mode = QIO_CHANNEL_SHUTDOWN_BOTH;
 123        } else if (rd) {
 124            mode = QIO_CHANNEL_SHUTDOWN_READ;
 125        } else {
 126            mode = QIO_CHANNEL_SHUTDOWN_WRITE;
 127        }
 128        if (qio_channel_shutdown(ioc, mode, NULL) < 0) {
 129            /* XXX handler Error * object */
 130            return -EIO;
 131        }
 132    }
 133    return 0;
 134}
 135
 136
 137static int channel_set_blocking(void *opaque,
 138                                bool enabled)
 139{
 140    QIOChannel *ioc = QIO_CHANNEL(opaque);
 141
 142    if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) {
 143        return -1;
 144    }
 145    return 0;
 146}
 147
 148static QEMUFile *channel_get_input_return_path(void *opaque)
 149{
 150    QIOChannel *ioc = QIO_CHANNEL(opaque);
 151
 152    return qemu_fopen_channel_output(ioc);
 153}
 154
 155static QEMUFile *channel_get_output_return_path(void *opaque)
 156{
 157    QIOChannel *ioc = QIO_CHANNEL(opaque);
 158
 159    return qemu_fopen_channel_input(ioc);
 160}
 161
 162static const QEMUFileOps channel_input_ops = {
 163    .get_buffer = channel_get_buffer,
 164    .close = channel_close,
 165    .shut_down = channel_shutdown,
 166    .set_blocking = channel_set_blocking,
 167    .get_return_path = channel_get_input_return_path,
 168};
 169
 170
 171static const QEMUFileOps channel_output_ops = {
 172    .writev_buffer = channel_writev_buffer,
 173    .close = channel_close,
 174    .shut_down = channel_shutdown,
 175    .set_blocking = channel_set_blocking,
 176    .get_return_path = channel_get_output_return_path,
 177};
 178
 179
 180QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc)
 181{
 182    object_ref(OBJECT(ioc));
 183    return qemu_fopen_ops(ioc, &channel_input_ops);
 184}
 185
 186QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc)
 187{
 188    object_ref(OBJECT(ioc));
 189    return qemu_fopen_ops(ioc, &channel_output_ops);
 190}
 191