[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2] Move File operations to qemu-file.c
From: |
Blue Swirl |
Subject: |
Re: [Qemu-devel] [PATCH v2] Move File operations to qemu-file.c |
Date: |
Wed, 13 Feb 2013 21:25:22 +0000 |
On Wed, Feb 13, 2013 at 8:43 PM, Joel Schopp <address@hidden> wrote:
> This patch reorganizes qemu file operations to be in their own source file
> instead of being lumped in savevm.c. Besides being more logical for
> maintenance
> it also makes it easier for future users of the file functions to add tests.
>
> v2 forward port to resolve conflicts, strip trailing whitespace during move
>
> Signed-off-by: Stefan Berger <address@hidden>
> Signed-off-by: Joel Schopp <address@hidden>
> ---
> Makefile.objs | 2
> include/migration/qemu-file.h | 4
> qemu-file.c | 670
> ++++++++++++++++++++++++++++++++++++++++++
> savevm.c | 646 ----------------------------------------
> 4 files changed, 675 insertions(+), 647 deletions(-)
>
> Index: b/Makefile.objs
> ===================================================================
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -57,7 +57,7 @@ common-obj-$(CONFIG_POSIX) += os-posix.o
> common-obj-$(CONFIG_LINUX) += fsdev/
>
> common-obj-y += migration.o migration-tcp.o
> -common-obj-y += qemu-char.o #aio.o
> +common-obj-y += qemu-char.o qemu-file.o #aio.o
> common-obj-y += block-migration.o
> common-obj-y += page_cache.o xbzrle.o
>
> Index: b/include/migration/qemu-file.h
> ===================================================================
> --- a/include/migration/qemu-file.h
> +++ b/include/migration/qemu-file.h
> @@ -113,6 +113,10 @@ int qemu_file_rate_limit(QEMUFile *f);
> int64_t 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(QEMUFile *f);
> +QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable);
> +int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset);
> +int qemu_peek_byte(QEMUFile *f, int offset);
> +void qemu_file_skip(QEMUFile *f, int size);
>
> static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
> {
> Index: b/qemu-file.c
> ===================================================================
> --- /dev/null
> +++ b/qemu-file.c
> @@ -0,0 +1,670 @@
> +/*
> + * QEMU System Emulator
> + *
> + * Copyright (c) 2003-2008 Fabrice Bellard
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> copy
> + * of this software and associated documentation files (the "Software"), to
> deal
> + * in the Software without restriction, including without limitation the
> rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +#include "qemu-common.h"
> +#include "hw/hw.h"
> +#include "block/block.h"
> +#include "qemu/sockets.h"
> +
> +#define IO_BUF_SIZE 32768
> +
> +struct QEMUFile {
> + const QEMUFileOps *ops;
> + void *opaque;
> + int is_write;
> +
> + int64_t buf_offset; /* start of buffer when writing, end of buffer
> + when reading */
> + int buf_index;
> + int buf_size; /* 0 when writing */
> + uint8_t buf[IO_BUF_SIZE];
> +
> + int last_error;
> +};
> +
> +typedef struct QEMUFileStdio
> +{
> + FILE *stdio_file;
> + QEMUFile *file;
> +} QEMUFileStdio;
> +
> +typedef struct QEMUFileSocket
> +{
> + int fd;
> + QEMUFile *file;
> +} QEMUFileSocket;
> +
> +typedef struct {
> + Coroutine *co;
> + int fd;
> +} FDYieldUntilData;
> +
> +static void fd_coroutine_enter(void *opaque)
> +{
> + FDYieldUntilData *data = opaque;
> + qemu_set_fd_handler(data->fd, NULL, NULL, NULL);
> + qemu_coroutine_enter(data->co, NULL);
> +}
> +
> +/**
> + * Yield until a file descriptor becomes readable
> + *
> + * Note that this function clobbers the handlers for the file descriptor.
> + */
> +static void coroutine_fn yield_until_fd_readable(int fd)
> +{
> + FDYieldUntilData data;
> +
> + assert(qemu_in_coroutine());
> + data.co = qemu_coroutine_self();
> + data.fd = fd;
> + qemu_set_fd_handler(fd, fd_coroutine_enter, NULL, &data);
> + qemu_coroutine_yield();
> +}
> +
> +static int socket_get_fd(void *opaque)
> +{
> + QEMUFileSocket *s = opaque;
> +
> + return s->fd;
> +}
> +
> +static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int
> size)
> +{
> + QEMUFileSocket *s = opaque;
> + ssize_t len;
> +
> + for (;;) {
> + len = qemu_recv(s->fd, buf, size, 0);
> + if (len != -1) {
> + break;
> + }
> + if (socket_error() == EAGAIN) {
> + yield_until_fd_readable(s->fd);
> + } else if (socket_error() != EINTR) {
> + break;
> + }
> + }
> +
> + if (len == -1) {
> + len = -socket_error();
> + }
> + return len;
> +}
> +
> +static int socket_close(void *opaque)
> +{
> + QEMUFileSocket *s = opaque;
> + closesocket(s->fd);
> + g_free(s);
> + return 0;
> +}
> +
> +static int stdio_get_fd(void *opaque)
> +{
> + QEMUFileStdio *s = opaque;
> +
> + return fileno(s->stdio_file);
> +}
> +
> +static int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos,
> int size)
> +{
> + QEMUFileStdio *s = opaque;
> + return fwrite(buf, 1, size, s->stdio_file);
> +}
> +
> +static int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int
> size)
> +{
> + QEMUFileStdio *s = opaque;
> + FILE *fp = s->stdio_file;
> + int bytes;
> +
> + for (;;) {
> + clearerr(fp);
> + bytes = fread(buf, 1, size, fp);
> + if (bytes != 0 || !ferror(fp)) {
> + break;
> + }
> + if (errno == EAGAIN) {
> + yield_until_fd_readable(fileno(fp));
> + } else if (errno != EINTR) {
> + break;
> + }
> + }
> + return bytes;
> +}
> +
> +static int stdio_pclose(void *opaque)
> +{
> + QEMUFileStdio *s = opaque;
> + int ret;
> + ret = pclose(s->stdio_file);
> + if (ret == -1) {
> + ret = -errno;
> + }
> + g_free(s);
> + return ret;
> +}
> +
> +static int stdio_fclose(void *opaque)
> +{
> + QEMUFileStdio *s = opaque;
> + int ret = 0;
> + if (fclose(s->stdio_file) == EOF) {
> + ret = -errno;
> + }
> + g_free(s);
> + return ret;
> +}
> +
> +static const QEMUFileOps stdio_pipe_read_ops = {
> + .get_fd = stdio_get_fd,
> + .get_buffer = stdio_get_buffer,
> + .close = stdio_pclose
> +};
> +
> +static const QEMUFileOps stdio_pipe_write_ops = {
> + .get_fd = stdio_get_fd,
> + .put_buffer = stdio_put_buffer,
> + .close = stdio_pclose
> +};
> +
> +QEMUFile *qemu_popen(FILE *stdio_file, const char *mode)
> +{
> + QEMUFileStdio *s;
> +
> + if (stdio_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] !=
> 'w') || mode[1] != 0) {
> + fprintf(stderr, "qemu_popen: Argument validity check failed\n");
> + return NULL;
> + }
> +
> + s = g_malloc0(sizeof(QEMUFileStdio));
> +
> + s->stdio_file = stdio_file;
> +
> + if(mode[0] == 'r') {
> + s->file = qemu_fopen_ops(s, &stdio_pipe_read_ops);
> + } else {
> + s->file = qemu_fopen_ops(s, &stdio_pipe_write_ops);
> + }
> + return s->file;
> +}
> +
> +QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
> +{
> + FILE *popen_file;
> +
> + popen_file = popen(command, mode);
> + if(popen_file == NULL) {
Please make a preparatory patch which adds missing spaces between 'if'
statements and '('.
> + return NULL;
> + }
> +
> + return qemu_popen(popen_file, mode);
> +}
> +
> +static const QEMUFileOps stdio_file_read_ops = {
> + .get_fd = stdio_get_fd,
> + .get_buffer = stdio_get_buffer,
> + .close = stdio_fclose
> +};
> +
> +static const QEMUFileOps stdio_file_write_ops = {
> + .get_fd = stdio_get_fd,
> + .put_buffer = stdio_put_buffer,
> + .close = stdio_fclose
> +};
> +
> +QEMUFile *qemu_fdopen(int fd, const char *mode)
> +{
> + QEMUFileStdio *s;
> +
> + if (mode == NULL ||
> + (mode[0] != 'r' && mode[0] != 'w') ||
> + mode[1] != 'b' || mode[2] != 0) {
> + fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
> + return NULL;
> + }
> +
> + s = g_malloc0(sizeof(QEMUFileStdio));
> + s->stdio_file = fdopen(fd, mode);
> + if (!s->stdio_file)
Also braces for statements like this. Then the code movement patch
would not make checkpatch.pl unhappy and the new file would be fully
in line with CODING_STYLE.
> + goto fail;
> +
> + if(mode[0] == 'r') {
> + s->file = qemu_fopen_ops(s, &stdio_file_read_ops);
> + } else {
> + s->file = qemu_fopen_ops(s, &stdio_file_write_ops);
> + }
> + return s->file;
> +
> +fail:
> + g_free(s);
> + return NULL;
> +}
> +
> +static const QEMUFileOps socket_read_ops = {
> + .get_fd = socket_get_fd,
> + .get_buffer = socket_get_buffer,
> + .close = socket_close
> +};
> +
> +QEMUFile *qemu_fopen_socket(int fd)
> +{
> + QEMUFileSocket *s = g_malloc0(sizeof(QEMUFileSocket));
> +
> + s->fd = fd;
> + s->file = qemu_fopen_ops(s, &socket_read_ops);
> + return s->file;
> +}
> +
> +QEMUFile *qemu_fopen(const char *filename, const char *mode)
> +{
> + QEMUFileStdio *s;
> +
> + if (mode == NULL ||
> + (mode[0] != 'r' && mode[0] != 'w') ||
> + mode[1] != 'b' || mode[2] != 0) {
> + fprintf(stderr, "qemu_fopen: Argument validity check failed\n");
> + return NULL;
> + }
> +
> + s = g_malloc0(sizeof(QEMUFileStdio));
> +
> + s->stdio_file = fopen(filename, mode);
> + if (!s->stdio_file)
> + goto fail;
> +
> + if(mode[0] == 'w') {
> + s->file = qemu_fopen_ops(s, &stdio_file_write_ops);
> + } else {
> + s->file = qemu_fopen_ops(s, &stdio_file_read_ops);
> + }
> + return s->file;
> +fail:
> + g_free(s);
> + return NULL;
> +}
> +
> +static int block_put_buffer(void *opaque, const uint8_t *buf,
> + int64_t pos, int size)
> +{
> + bdrv_save_vmstate(opaque, buf, pos, size);
> + return size;
> +}
> +
> +static int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int
> size)
> +{
> + return bdrv_load_vmstate(opaque, buf, pos, size);
> +}
> +
> +static int bdrv_fclose(void *opaque)
> +{
> + return bdrv_flush(opaque);
> +}
> +
> +static const QEMUFileOps bdrv_read_ops = {
> + .get_buffer = block_get_buffer,
> + .close = bdrv_fclose
> +};
> +
> +static const QEMUFileOps bdrv_write_ops = {
> + .put_buffer = block_put_buffer,
> + .close = bdrv_fclose
> +};
> +
> +QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
> +{
> + if (is_writable)
> + return qemu_fopen_ops(bs, &bdrv_write_ops);
> + return qemu_fopen_ops(bs, &bdrv_read_ops);
> +}
> +
> +QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops)
> +{
> + QEMUFile *f;
> +
> + f = g_malloc0(sizeof(QEMUFile));
> +
> + f->opaque = opaque;
> + f->ops = ops;
> + f->is_write = 0;
> +
> + return f;
> +}
> +
> +int qemu_file_get_error(QEMUFile *f)
> +{
> + return f->last_error;
> +}
> +
> +static void qemu_file_set_error(QEMUFile *f, int ret)
> +{
> + if (f->last_error == 0) {
> + f->last_error = ret;
> + }
> +}
> +
> +/** Flushes QEMUFile buffer
> + *
> + */
> +static int qemu_fflush(QEMUFile *f)
> +{
> + int ret = 0;
> +
> + if (!f->ops->put_buffer)
> + return 0;
> +
> + if (f->is_write && f->buf_index > 0) {
> + ret = f->ops->put_buffer(f->opaque, f->buf, f->buf_offset,
> f->buf_index);
> + if (ret >= 0) {
> + f->buf_offset += f->buf_index;
> + }
> + f->buf_index = 0;
> + }
> + return ret;
> +}
> +
> +static void qemu_fill_buffer(QEMUFile *f)
> +{
> + int len;
> + int pending;
> +
> + if (!f->ops->get_buffer)
> + return;
> +
> + if (f->is_write)
> + abort();
> +
> + pending = f->buf_size - f->buf_index;
> + if (pending > 0) {
> + memmove(f->buf, f->buf + f->buf_index, pending);
> + }
> + f->buf_index = 0;
> + f->buf_size = pending;
> +
> + len = f->ops->get_buffer(f->opaque, f->buf + pending, f->buf_offset,
> + IO_BUF_SIZE - pending);
> + if (len > 0) {
> + f->buf_size += len;
> + f->buf_offset += len;
> + } else if (len == 0) {
> + qemu_file_set_error(f, -EIO);
> + } else if (len != -EAGAIN)
> + qemu_file_set_error(f, len);
> +}
> +
> +int qemu_get_fd(QEMUFile *f)
> +{
> + if (f->ops->get_fd) {
> + return f->ops->get_fd(f->opaque);
> + }
> + return -1;
> +}
> +
> +/** Closes the file
> + *
> + * Returns negative error value if any error happened on previous operations
> or
> + * while closing the file. Returns 0 or positive number on success.
> + *
> + * The meaning of return value on success depends on the specific backend
> + * being used.
> + */
> +int qemu_fclose(QEMUFile *f)
> +{
> + int ret;
> + ret = qemu_fflush(f);
> +
> + if (f->ops->close) {
> + int ret2 = f->ops->close(f->opaque);
> + if (ret >= 0) {
> + ret = ret2;
> + }
> + }
> + /* If any error was spotted before closing, we should report it
> + * instead of the close() return value.
> + */
> + if (f->last_error) {
> + ret = f->last_error;
> + }
> + g_free(f);
> + return ret;
> +}
> +
> +void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
> +{
> + int l;
> +
> + if (f->last_error) {
> + return;
> + }
> +
> + if (f->is_write == 0 && f->buf_index > 0) {
> + fprintf(stderr,
> + "Attempted to write to buffer while read buffer is not
> empty\n");
> + abort();
> + }
> +
> + while (size > 0) {
> + l = IO_BUF_SIZE - f->buf_index;
> + if (l > size)
> + l = size;
> + memcpy(f->buf + f->buf_index, buf, l);
> + f->is_write = 1;
> + f->buf_index += l;
> + buf += l;
> + size -= l;
> + if (f->buf_index >= IO_BUF_SIZE) {
> + int ret = qemu_fflush(f);
> + if (ret < 0) {
> + qemu_file_set_error(f, ret);
> + break;
> + }
> + }
> + }
> +}
> +
> +void qemu_put_byte(QEMUFile *f, int v)
> +{
> + if (f->last_error) {
> + return;
> + }
> +
> + if (f->is_write == 0 && f->buf_index > 0) {
> + fprintf(stderr,
> + "Attempted to write to buffer while read buffer is not
> empty\n");
> + abort();
> + }
> +
> + f->buf[f->buf_index++] = v;
> + f->is_write = 1;
> + if (f->buf_index >= IO_BUF_SIZE) {
> + int ret = qemu_fflush(f);
> + if (ret < 0) {
> + qemu_file_set_error(f, ret);
> + }
> + }
> +}
> +
> +void qemu_file_skip(QEMUFile *f, int size)
> +{
> + if (f->buf_index + size <= f->buf_size) {
> + f->buf_index += size;
> + }
> +}
> +
> +int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
> +{
> + int pending;
> + int index;
> +
> + if (f->is_write) {
> + abort();
> + }
> +
> + index = f->buf_index + offset;
> + pending = f->buf_size - index;
> + if (pending < size) {
> + qemu_fill_buffer(f);
> + index = f->buf_index + offset;
> + pending = f->buf_size - index;
> + }
> +
> + if (pending <= 0) {
> + return 0;
> + }
> + if (size > pending) {
> + size = pending;
> + }
> +
> + memcpy(buf, f->buf + index, size);
> + return size;
> +}
> +
> +int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
> +{
> + int pending = size;
> + int done = 0;
> +
> + while (pending > 0) {
> + int res;
> +
> + res = qemu_peek_buffer(f, buf, pending, 0);
> + if (res == 0) {
> + return done;
> + }
> + qemu_file_skip(f, res);
> + buf += res;
> + pending -= res;
> + done += res;
> + }
> + return done;
> +}
> +
> +int qemu_peek_byte(QEMUFile *f, int offset)
> +{
> + int index = f->buf_index + offset;
> +
> + if (f->is_write) {
> + abort();
> + }
> +
> + if (index >= f->buf_size) {
> + qemu_fill_buffer(f);
> + index = f->buf_index + offset;
> + if (index >= f->buf_size) {
> + return 0;
> + }
> + }
> + return f->buf[index];
> +}
> +
> +int qemu_get_byte(QEMUFile *f)
> +{
> + int result;
> +
> + result = qemu_peek_byte(f, 0);
> + qemu_file_skip(f, 1);
> + return result;
> +}
> +
> +int64_t qemu_ftell(QEMUFile *f)
> +{
> + /* buf_offset excludes buffer for writing but includes it for reading */
> + if (f->is_write) {
> + return f->buf_offset + f->buf_index;
> + } else {
> + return f->buf_offset - f->buf_size + f->buf_index;
> + }
> +}
> +
> +int qemu_file_rate_limit(QEMUFile *f)
> +{
> + if (f->ops->rate_limit)
> + return f->ops->rate_limit(f->opaque);
> +
> + return 0;
> +}
> +
> +int64_t qemu_file_get_rate_limit(QEMUFile *f)
> +{
> + if (f->ops->get_rate_limit)
> + return f->ops->get_rate_limit(f->opaque);
> +
> + return 0;
> +}
> +
> +int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate)
> +{
> + /* any failed or completed migration keeps its state to allow probing of
> + * migration data, but has no associated file anymore */
> + if (f && f->ops->set_rate_limit)
> + return f->ops->set_rate_limit(f->opaque, new_rate);
> +
> + return 0;
> +}
> +
> +void qemu_put_be16(QEMUFile *f, unsigned int v)
> +{
> + qemu_put_byte(f, v >> 8);
> + qemu_put_byte(f, v);
> +}
> +
> +void qemu_put_be32(QEMUFile *f, unsigned int v)
> +{
> + qemu_put_byte(f, v >> 24);
> + qemu_put_byte(f, v >> 16);
> + qemu_put_byte(f, v >> 8);
> + qemu_put_byte(f, v);
> +}
> +
> +void qemu_put_be64(QEMUFile *f, uint64_t v)
> +{
> + qemu_put_be32(f, v >> 32);
> + qemu_put_be32(f, v);
> +}
> +
> +unsigned int qemu_get_be16(QEMUFile *f)
> +{
> + unsigned int v;
> + v = qemu_get_byte(f) << 8;
> + v |= qemu_get_byte(f);
> + return v;
> +}
> +
> +unsigned int qemu_get_be32(QEMUFile *f)
> +{
> + unsigned int v;
> + v = qemu_get_byte(f) << 24;
> + v |= qemu_get_byte(f) << 16;
> + v |= qemu_get_byte(f) << 8;
> + v |= qemu_get_byte(f);
> + return v;
> +}
> +
> +uint64_t qemu_get_be64(QEMUFile *f)
> +{
> + uint64_t v;
> + v = (uint64_t)qemu_get_be32(f) << 32;
> + v |= qemu_get_be32(f);
> + return v;
> +}
> Index: b/savevm.c
> ===================================================================
> --- a/savevm.c
> +++ b/savevm.c
> @@ -109,652 +109,6 @@ void qemu_announce_self(void)
> qemu_announce_self_once(&timer);
> }
>
> -/***********************************************************/
> -/* savevm/loadvm support */
> -
> -#define IO_BUF_SIZE 32768
> -
> -struct QEMUFile {
> - const QEMUFileOps *ops;
> - void *opaque;
> - int is_write;
> -
> - int64_t buf_offset; /* start of buffer when writing, end of buffer
> - when reading */
> - int buf_index;
> - int buf_size; /* 0 when writing */
> - uint8_t buf[IO_BUF_SIZE];
> -
> - int last_error;
> -};
> -
> -typedef struct QEMUFileStdio
> -{
> - FILE *stdio_file;
> - QEMUFile *file;
> -} QEMUFileStdio;
> -
> -typedef struct QEMUFileSocket
> -{
> - int fd;
> - QEMUFile *file;
> -} QEMUFileSocket;
> -
> -typedef struct {
> - Coroutine *co;
> - int fd;
> -} FDYieldUntilData;
> -
> -static void fd_coroutine_enter(void *opaque)
> -{
> - FDYieldUntilData *data = opaque;
> - qemu_set_fd_handler(data->fd, NULL, NULL, NULL);
> - qemu_coroutine_enter(data->co, NULL);
> -}
> -
> -/**
> - * Yield until a file descriptor becomes readable
> - *
> - * Note that this function clobbers the handlers for the file descriptor.
> - */
> -static void coroutine_fn yield_until_fd_readable(int fd)
> -{
> - FDYieldUntilData data;
> -
> - assert(qemu_in_coroutine());
> - data.co = qemu_coroutine_self();
> - data.fd = fd;
> - qemu_set_fd_handler(fd, fd_coroutine_enter, NULL, &data);
> - qemu_coroutine_yield();
> -}
> -
> -static int socket_get_fd(void *opaque)
> -{
> - QEMUFileSocket *s = opaque;
> -
> - return s->fd;
> -}
> -
> -static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int
> size)
> -{
> - QEMUFileSocket *s = opaque;
> - ssize_t len;
> -
> - for (;;) {
> - len = qemu_recv(s->fd, buf, size, 0);
> - if (len != -1) {
> - break;
> - }
> - if (socket_error() == EAGAIN) {
> - yield_until_fd_readable(s->fd);
> - } else if (socket_error() != EINTR) {
> - break;
> - }
> - }
> -
> - if (len == -1) {
> - len = -socket_error();
> - }
> - return len;
> -}
> -
> -static int socket_close(void *opaque)
> -{
> - QEMUFileSocket *s = opaque;
> - closesocket(s->fd);
> - g_free(s);
> - return 0;
> -}
> -
> -static int stdio_get_fd(void *opaque)
> -{
> - QEMUFileStdio *s = opaque;
> -
> - return fileno(s->stdio_file);
> -}
> -
> -static int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos,
> int size)
> -{
> - QEMUFileStdio *s = opaque;
> - return fwrite(buf, 1, size, s->stdio_file);
> -}
> -
> -static int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int
> size)
> -{
> - QEMUFileStdio *s = opaque;
> - FILE *fp = s->stdio_file;
> - int bytes;
> -
> - for (;;) {
> - clearerr(fp);
> - bytes = fread(buf, 1, size, fp);
> - if (bytes != 0 || !ferror(fp)) {
> - break;
> - }
> - if (errno == EAGAIN) {
> - yield_until_fd_readable(fileno(fp));
> - } else if (errno != EINTR) {
> - break;
> - }
> - }
> - return bytes;
> -}
> -
> -static int stdio_pclose(void *opaque)
> -{
> - QEMUFileStdio *s = opaque;
> - int ret;
> - ret = pclose(s->stdio_file);
> - if (ret == -1) {
> - ret = -errno;
> - }
> - g_free(s);
> - return ret;
> -}
> -
> -static int stdio_fclose(void *opaque)
> -{
> - QEMUFileStdio *s = opaque;
> - int ret = 0;
> - if (fclose(s->stdio_file) == EOF) {
> - ret = -errno;
> - }
> - g_free(s);
> - return ret;
> -}
> -
> -static const QEMUFileOps stdio_pipe_read_ops = {
> - .get_fd = stdio_get_fd,
> - .get_buffer = stdio_get_buffer,
> - .close = stdio_pclose
> -};
> -
> -static const QEMUFileOps stdio_pipe_write_ops = {
> - .get_fd = stdio_get_fd,
> - .put_buffer = stdio_put_buffer,
> - .close = stdio_pclose
> -};
> -
> -QEMUFile *qemu_popen(FILE *stdio_file, const char *mode)
> -{
> - QEMUFileStdio *s;
> -
> - if (stdio_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] !=
> 'w') || mode[1] != 0) {
> - fprintf(stderr, "qemu_popen: Argument validity check failed\n");
> - return NULL;
> - }
> -
> - s = g_malloc0(sizeof(QEMUFileStdio));
> -
> - s->stdio_file = stdio_file;
> -
> - if(mode[0] == 'r') {
> - s->file = qemu_fopen_ops(s, &stdio_pipe_read_ops);
> - } else {
> - s->file = qemu_fopen_ops(s, &stdio_pipe_write_ops);
> - }
> - return s->file;
> -}
> -
> -QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
> -{
> - FILE *popen_file;
> -
> - popen_file = popen(command, mode);
> - if(popen_file == NULL) {
> - return NULL;
> - }
> -
> - return qemu_popen(popen_file, mode);
> -}
> -
> -static const QEMUFileOps stdio_file_read_ops = {
> - .get_fd = stdio_get_fd,
> - .get_buffer = stdio_get_buffer,
> - .close = stdio_fclose
> -};
> -
> -static const QEMUFileOps stdio_file_write_ops = {
> - .get_fd = stdio_get_fd,
> - .put_buffer = stdio_put_buffer,
> - .close = stdio_fclose
> -};
> -
> -QEMUFile *qemu_fdopen(int fd, const char *mode)
> -{
> - QEMUFileStdio *s;
> -
> - if (mode == NULL ||
> - (mode[0] != 'r' && mode[0] != 'w') ||
> - mode[1] != 'b' || mode[2] != 0) {
> - fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
> - return NULL;
> - }
> -
> - s = g_malloc0(sizeof(QEMUFileStdio));
> - s->stdio_file = fdopen(fd, mode);
> - if (!s->stdio_file)
> - goto fail;
> -
> - if(mode[0] == 'r') {
> - s->file = qemu_fopen_ops(s, &stdio_file_read_ops);
> - } else {
> - s->file = qemu_fopen_ops(s, &stdio_file_write_ops);
> - }
> - return s->file;
> -
> -fail:
> - g_free(s);
> - return NULL;
> -}
> -
> -static const QEMUFileOps socket_read_ops = {
> - .get_fd = socket_get_fd,
> - .get_buffer = socket_get_buffer,
> - .close = socket_close
> -};
> -
> -QEMUFile *qemu_fopen_socket(int fd)
> -{
> - QEMUFileSocket *s = g_malloc0(sizeof(QEMUFileSocket));
> -
> - s->fd = fd;
> - s->file = qemu_fopen_ops(s, &socket_read_ops);
> - return s->file;
> -}
> -
> -QEMUFile *qemu_fopen(const char *filename, const char *mode)
> -{
> - QEMUFileStdio *s;
> -
> - if (mode == NULL ||
> - (mode[0] != 'r' && mode[0] != 'w') ||
> - mode[1] != 'b' || mode[2] != 0) {
> - fprintf(stderr, "qemu_fopen: Argument validity check failed\n");
> - return NULL;
> - }
> -
> - s = g_malloc0(sizeof(QEMUFileStdio));
> -
> - s->stdio_file = fopen(filename, mode);
> - if (!s->stdio_file)
> - goto fail;
> -
> - if(mode[0] == 'w') {
> - s->file = qemu_fopen_ops(s, &stdio_file_write_ops);
> - } else {
> - s->file = qemu_fopen_ops(s, &stdio_file_read_ops);
> - }
> - return s->file;
> -fail:
> - g_free(s);
> - return NULL;
> -}
> -
> -static int block_put_buffer(void *opaque, const uint8_t *buf,
> - int64_t pos, int size)
> -{
> - bdrv_save_vmstate(opaque, buf, pos, size);
> - return size;
> -}
> -
> -static int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int
> size)
> -{
> - return bdrv_load_vmstate(opaque, buf, pos, size);
> -}
> -
> -static int bdrv_fclose(void *opaque)
> -{
> - return bdrv_flush(opaque);
> -}
> -
> -static const QEMUFileOps bdrv_read_ops = {
> - .get_buffer = block_get_buffer,
> - .close = bdrv_fclose
> -};
> -
> -static const QEMUFileOps bdrv_write_ops = {
> - .put_buffer = block_put_buffer,
> - .close = bdrv_fclose
> -};
> -
> -static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
> -{
> - if (is_writable)
> - return qemu_fopen_ops(bs, &bdrv_write_ops);
> - return qemu_fopen_ops(bs, &bdrv_read_ops);
> -}
> -
> -QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops)
> -{
> - QEMUFile *f;
> -
> - f = g_malloc0(sizeof(QEMUFile));
> -
> - f->opaque = opaque;
> - f->ops = ops;
> - f->is_write = 0;
> -
> - return f;
> -}
> -
> -int qemu_file_get_error(QEMUFile *f)
> -{
> - return f->last_error;
> -}
> -
> -static void qemu_file_set_error(QEMUFile *f, int ret)
> -{
> - if (f->last_error == 0) {
> - f->last_error = ret;
> - }
> -}
> -
> -/** Flushes QEMUFile buffer
> - *
> - */
> -static int qemu_fflush(QEMUFile *f)
> -{
> - int ret = 0;
> -
> - if (!f->ops->put_buffer)
> - return 0;
> -
> - if (f->is_write && f->buf_index > 0) {
> - ret = f->ops->put_buffer(f->opaque, f->buf, f->buf_offset,
> f->buf_index);
> - if (ret >= 0) {
> - f->buf_offset += f->buf_index;
> - }
> - f->buf_index = 0;
> - }
> - return ret;
> -}
> -
> -static void qemu_fill_buffer(QEMUFile *f)
> -{
> - int len;
> - int pending;
> -
> - if (!f->ops->get_buffer)
> - return;
> -
> - if (f->is_write)
> - abort();
> -
> - pending = f->buf_size - f->buf_index;
> - if (pending > 0) {
> - memmove(f->buf, f->buf + f->buf_index, pending);
> - }
> - f->buf_index = 0;
> - f->buf_size = pending;
> -
> - len = f->ops->get_buffer(f->opaque, f->buf + pending, f->buf_offset,
> - IO_BUF_SIZE - pending);
> - if (len > 0) {
> - f->buf_size += len;
> - f->buf_offset += len;
> - } else if (len == 0) {
> - qemu_file_set_error(f, -EIO);
> - } else if (len != -EAGAIN)
> - qemu_file_set_error(f, len);
> -}
> -
> -int qemu_get_fd(QEMUFile *f)
> -{
> - if (f->ops->get_fd) {
> - return f->ops->get_fd(f->opaque);
> - }
> - return -1;
> -}
> -
> -/** Closes the file
> - *
> - * Returns negative error value if any error happened on previous operations
> or
> - * while closing the file. Returns 0 or positive number on success.
> - *
> - * The meaning of return value on success depends on the specific backend
> - * being used.
> - */
> -int qemu_fclose(QEMUFile *f)
> -{
> - int ret;
> - ret = qemu_fflush(f);
> -
> - if (f->ops->close) {
> - int ret2 = f->ops->close(f->opaque);
> - if (ret >= 0) {
> - ret = ret2;
> - }
> - }
> - /* If any error was spotted before closing, we should report it
> - * instead of the close() return value.
> - */
> - if (f->last_error) {
> - ret = f->last_error;
> - }
> - g_free(f);
> - return ret;
> -}
> -
> -void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
> -{
> - int l;
> -
> - if (f->last_error) {
> - return;
> - }
> -
> - if (f->is_write == 0 && f->buf_index > 0) {
> - fprintf(stderr,
> - "Attempted to write to buffer while read buffer is not
> empty\n");
> - abort();
> - }
> -
> - while (size > 0) {
> - l = IO_BUF_SIZE - f->buf_index;
> - if (l > size)
> - l = size;
> - memcpy(f->buf + f->buf_index, buf, l);
> - f->is_write = 1;
> - f->buf_index += l;
> - buf += l;
> - size -= l;
> - if (f->buf_index >= IO_BUF_SIZE) {
> - int ret = qemu_fflush(f);
> - if (ret < 0) {
> - qemu_file_set_error(f, ret);
> - break;
> - }
> - }
> - }
> -}
> -
> -void qemu_put_byte(QEMUFile *f, int v)
> -{
> - if (f->last_error) {
> - return;
> - }
> -
> - if (f->is_write == 0 && f->buf_index > 0) {
> - fprintf(stderr,
> - "Attempted to write to buffer while read buffer is not
> empty\n");
> - abort();
> - }
> -
> - f->buf[f->buf_index++] = v;
> - f->is_write = 1;
> - if (f->buf_index >= IO_BUF_SIZE) {
> - int ret = qemu_fflush(f);
> - if (ret < 0) {
> - qemu_file_set_error(f, ret);
> - }
> - }
> -}
> -
> -static void qemu_file_skip(QEMUFile *f, int size)
> -{
> - if (f->buf_index + size <= f->buf_size) {
> - f->buf_index += size;
> - }
> -}
> -
> -static int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t
> offset)
> -{
> - int pending;
> - int index;
> -
> - if (f->is_write) {
> - abort();
> - }
> -
> - index = f->buf_index + offset;
> - pending = f->buf_size - index;
> - if (pending < size) {
> - qemu_fill_buffer(f);
> - index = f->buf_index + offset;
> - pending = f->buf_size - index;
> - }
> -
> - if (pending <= 0) {
> - return 0;
> - }
> - if (size > pending) {
> - size = pending;
> - }
> -
> - memcpy(buf, f->buf + index, size);
> - return size;
> -}
> -
> -int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
> -{
> - int pending = size;
> - int done = 0;
> -
> - while (pending > 0) {
> - int res;
> -
> - res = qemu_peek_buffer(f, buf, pending, 0);
> - if (res == 0) {
> - return done;
> - }
> - qemu_file_skip(f, res);
> - buf += res;
> - pending -= res;
> - done += res;
> - }
> - return done;
> -}
> -
> -static int qemu_peek_byte(QEMUFile *f, int offset)
> -{
> - int index = f->buf_index + offset;
> -
> - if (f->is_write) {
> - abort();
> - }
> -
> - if (index >= f->buf_size) {
> - qemu_fill_buffer(f);
> - index = f->buf_index + offset;
> - if (index >= f->buf_size) {
> - return 0;
> - }
> - }
> - return f->buf[index];
> -}
> -
> -int qemu_get_byte(QEMUFile *f)
> -{
> - int result;
> -
> - result = qemu_peek_byte(f, 0);
> - qemu_file_skip(f, 1);
> - return result;
> -}
> -
> -int64_t qemu_ftell(QEMUFile *f)
> -{
> - /* buf_offset excludes buffer for writing but includes it for reading */
> - if (f->is_write) {
> - return f->buf_offset + f->buf_index;
> - } else {
> - return f->buf_offset - f->buf_size + f->buf_index;
> - }
> -}
> -
> -int qemu_file_rate_limit(QEMUFile *f)
> -{
> - if (f->ops->rate_limit)
> - return f->ops->rate_limit(f->opaque);
> -
> - return 0;
> -}
> -
> -int64_t qemu_file_get_rate_limit(QEMUFile *f)
> -{
> - if (f->ops->get_rate_limit)
> - return f->ops->get_rate_limit(f->opaque);
> -
> - return 0;
> -}
> -
> -int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate)
> -{
> - /* any failed or completed migration keeps its state to allow probing of
> - * migration data, but has no associated file anymore */
> - if (f && f->ops->set_rate_limit)
> - return f->ops->set_rate_limit(f->opaque, new_rate);
> -
> - return 0;
> -}
> -
> -void qemu_put_be16(QEMUFile *f, unsigned int v)
> -{
> - qemu_put_byte(f, v >> 8);
> - qemu_put_byte(f, v);
> -}
> -
> -void qemu_put_be32(QEMUFile *f, unsigned int v)
> -{
> - qemu_put_byte(f, v >> 24);
> - qemu_put_byte(f, v >> 16);
> - qemu_put_byte(f, v >> 8);
> - qemu_put_byte(f, v);
> -}
> -
> -void qemu_put_be64(QEMUFile *f, uint64_t v)
> -{
> - qemu_put_be32(f, v >> 32);
> - qemu_put_be32(f, v);
> -}
> -
> -unsigned int qemu_get_be16(QEMUFile *f)
> -{
> - unsigned int v;
> - v = qemu_get_byte(f) << 8;
> - v |= qemu_get_byte(f);
> - return v;
> -}
> -
> -unsigned int qemu_get_be32(QEMUFile *f)
> -{
> - unsigned int v;
> - v = qemu_get_byte(f) << 24;
> - v |= qemu_get_byte(f) << 16;
> - v |= qemu_get_byte(f) << 8;
> - v |= qemu_get_byte(f);
> - return v;
> -}
> -
> -uint64_t qemu_get_be64(QEMUFile *f)
> -{
> - uint64_t v;
> - v = (uint64_t)qemu_get_be32(f) << 32;
> - v |= qemu_get_be32(f);
> - return v;
> -}
> -
>
> /* timer */
>
>
>