Browse Source
Introduce a QIOChannelBlock class that exposes the BlockDriverState VMState region for I/O. This is kept in the migration/ directory rather than io/, to avoid a mutual dependancy between block/ <-> io/ directories. Also the VMState should only be used by the migration code. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> dgilbert: Fixed coding style in qio_channel_block_closepull/213/head
committed by
Dr. David Alan Gilbert
3 changed files with 255 additions and 0 deletions
@ -0,0 +1,195 @@ |
|||
/*
|
|||
* QEMU I/O channels block driver |
|||
* |
|||
* Copyright (c) 2022 Red Hat, Inc. |
|||
* |
|||
* This library is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU Lesser General Public |
|||
* License as published by the Free Software Foundation; either |
|||
* version 2.1 of the License, or (at your option) any later version. |
|||
* |
|||
* This library is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
* Lesser General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Lesser General Public |
|||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include "migration/channel-block.h" |
|||
#include "qapi/error.h" |
|||
#include "block/block.h" |
|||
#include "trace.h" |
|||
|
|||
QIOChannelBlock * |
|||
qio_channel_block_new(BlockDriverState *bs) |
|||
{ |
|||
QIOChannelBlock *ioc; |
|||
|
|||
ioc = QIO_CHANNEL_BLOCK(object_new(TYPE_QIO_CHANNEL_BLOCK)); |
|||
|
|||
bdrv_ref(bs); |
|||
ioc->bs = bs; |
|||
|
|||
return ioc; |
|||
} |
|||
|
|||
|
|||
static void |
|||
qio_channel_block_finalize(Object *obj) |
|||
{ |
|||
QIOChannelBlock *ioc = QIO_CHANNEL_BLOCK(obj); |
|||
|
|||
g_clear_pointer(&ioc->bs, bdrv_unref); |
|||
} |
|||
|
|||
|
|||
static ssize_t |
|||
qio_channel_block_readv(QIOChannel *ioc, |
|||
const struct iovec *iov, |
|||
size_t niov, |
|||
int **fds, |
|||
size_t *nfds, |
|||
Error **errp) |
|||
{ |
|||
QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); |
|||
QEMUIOVector qiov; |
|||
int ret; |
|||
|
|||
qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov); |
|||
ret = bdrv_readv_vmstate(bioc->bs, &qiov, bioc->offset); |
|||
if (ret < 0) { |
|||
return ret; |
|||
} |
|||
|
|||
bioc->offset += qiov.size; |
|||
return qiov.size; |
|||
} |
|||
|
|||
|
|||
static ssize_t |
|||
qio_channel_block_writev(QIOChannel *ioc, |
|||
const struct iovec *iov, |
|||
size_t niov, |
|||
int *fds, |
|||
size_t nfds, |
|||
int flags, |
|||
Error **errp) |
|||
{ |
|||
QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); |
|||
QEMUIOVector qiov; |
|||
int ret; |
|||
|
|||
qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov); |
|||
ret = bdrv_writev_vmstate(bioc->bs, &qiov, bioc->offset); |
|||
if (ret < 0) { |
|||
return ret; |
|||
} |
|||
|
|||
bioc->offset += qiov.size; |
|||
return qiov.size; |
|||
} |
|||
|
|||
|
|||
static int |
|||
qio_channel_block_set_blocking(QIOChannel *ioc, |
|||
bool enabled, |
|||
Error **errp) |
|||
{ |
|||
if (!enabled) { |
|||
error_setg(errp, "Non-blocking mode not supported for block devices"); |
|||
return -1; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
|
|||
static off_t |
|||
qio_channel_block_seek(QIOChannel *ioc, |
|||
off_t offset, |
|||
int whence, |
|||
Error **errp) |
|||
{ |
|||
QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); |
|||
|
|||
switch (whence) { |
|||
case SEEK_SET: |
|||
bioc->offset = offset; |
|||
break; |
|||
case SEEK_CUR: |
|||
bioc->offset += whence; |
|||
break; |
|||
case SEEK_END: |
|||
error_setg(errp, "Size of VMstate region is unknown"); |
|||
return (off_t)-1; |
|||
default: |
|||
g_assert_not_reached(); |
|||
} |
|||
|
|||
return bioc->offset; |
|||
} |
|||
|
|||
|
|||
static int |
|||
qio_channel_block_close(QIOChannel *ioc, |
|||
Error **errp) |
|||
{ |
|||
QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); |
|||
int rv = bdrv_flush(bioc->bs); |
|||
|
|||
if (rv < 0) { |
|||
error_setg_errno(errp, -rv, |
|||
"Unable to flush VMState"); |
|||
return -1; |
|||
} |
|||
|
|||
g_clear_pointer(&bioc->bs, bdrv_unref); |
|||
bioc->offset = 0; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
static void |
|||
qio_channel_block_set_aio_fd_handler(QIOChannel *ioc, |
|||
AioContext *ctx, |
|||
IOHandler *io_read, |
|||
IOHandler *io_write, |
|||
void *opaque) |
|||
{ |
|||
/* XXX anything we can do here ? */ |
|||
} |
|||
|
|||
|
|||
static void |
|||
qio_channel_block_class_init(ObjectClass *klass, |
|||
void *class_data G_GNUC_UNUSED) |
|||
{ |
|||
QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); |
|||
|
|||
ioc_klass->io_writev = qio_channel_block_writev; |
|||
ioc_klass->io_readv = qio_channel_block_readv; |
|||
ioc_klass->io_set_blocking = qio_channel_block_set_blocking; |
|||
ioc_klass->io_seek = qio_channel_block_seek; |
|||
ioc_klass->io_close = qio_channel_block_close; |
|||
ioc_klass->io_set_aio_fd_handler = qio_channel_block_set_aio_fd_handler; |
|||
} |
|||
|
|||
static const TypeInfo qio_channel_block_info = { |
|||
.parent = TYPE_QIO_CHANNEL, |
|||
.name = TYPE_QIO_CHANNEL_BLOCK, |
|||
.instance_size = sizeof(QIOChannelBlock), |
|||
.instance_finalize = qio_channel_block_finalize, |
|||
.class_init = qio_channel_block_class_init, |
|||
}; |
|||
|
|||
static void |
|||
qio_channel_block_register_types(void) |
|||
{ |
|||
type_register_static(&qio_channel_block_info); |
|||
} |
|||
|
|||
type_init(qio_channel_block_register_types); |
|||
@ -0,0 +1,59 @@ |
|||
/*
|
|||
* QEMU I/O channels block driver |
|||
* |
|||
* Copyright (c) 2022 Red Hat, Inc. |
|||
* |
|||
* This library is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU Lesser General Public |
|||
* License as published by the Free Software Foundation; either |
|||
* version 2.1 of the License, or (at your option) any later version. |
|||
* |
|||
* This library is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
* Lesser General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Lesser General Public |
|||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
|
|||
#ifndef QIO_CHANNEL_BLOCK_H |
|||
#define QIO_CHANNEL_BLOCK_H |
|||
|
|||
#include "io/channel.h" |
|||
#include "qom/object.h" |
|||
|
|||
#define TYPE_QIO_CHANNEL_BLOCK "qio-channel-block" |
|||
OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelBlock, QIO_CHANNEL_BLOCK) |
|||
|
|||
|
|||
/**
|
|||
* QIOChannelBlock: |
|||
* |
|||
* The QIOChannelBlock object provides a channel implementation |
|||
* that is able to perform I/O on the BlockDriverState objects |
|||
* to the VMState region. |
|||
*/ |
|||
|
|||
struct QIOChannelBlock { |
|||
QIOChannel parent; |
|||
BlockDriverState *bs; |
|||
off_t offset; |
|||
}; |
|||
|
|||
|
|||
/**
|
|||
* qio_channel_block_new: |
|||
* @bs: the block driver state |
|||
* |
|||
* Create a new IO channel object that can perform |
|||
* I/O on a BlockDriverState object to the VMState |
|||
* region |
|||
* |
|||
* Returns: the new channel object |
|||
*/ |
|||
QIOChannelBlock * |
|||
qio_channel_block_new(BlockDriverState *bs); |
|||
|
|||
#endif /* QIO_CHANNEL_BLOCK_H */ |
|||
Loading…
Reference in new issue