master
c 243 lines 6.39 KB
Raw
1 /*
2 * QEMU I/O channels block driver
3 *
4 * Copyright (c) 2022 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "qemu/osdep.h"
22 #include "migration/channel-block.h"
23 #include "qapi/error.h"
24 #include "block/block.h"
25 #include "trace.h"
26
27 QIOChannelBlock *
28 qio_channel_block_new(BlockDriverState *bs)
29 {
30 QIOChannelBlock *ioc;
31
32 ioc = QIO_CHANNEL_BLOCK(object_new(TYPE_QIO_CHANNEL_BLOCK));
33 qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SEEKABLE);
34
35 bdrv_ref(bs);
36 ioc->bs = bs;
37
38 return ioc;
39 }
40
41
42 static void
43 qio_channel_block_finalize(Object *obj)
44 {
45 QIOChannelBlock *ioc = QIO_CHANNEL_BLOCK(obj);
46
47 g_clear_pointer(&ioc->bs, bdrv_unref);
48 }
49
50
51 static ssize_t
52 qio_channel_block_readv(QIOChannel *ioc,
53 const struct iovec *iov,
54 size_t niov,
55 int **fds,
56 size_t *nfds,
57 int flags,
58 Error **errp)
59 {
60 QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc);
61 QEMUIOVector qiov;
62 int ret;
63
64 qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov);
65 ret = bdrv_readv_vmstate(bioc->bs, &qiov, bioc->offset);
66 if (ret < 0) {
67 error_setg_errno(errp, -ret, "bdrv_readv_vmstate failed");
68 return -1;
69 }
70
71 bioc->offset += qiov.size;
72 return qiov.size;
73 }
74
75
76 static ssize_t
77 qio_channel_block_writev(QIOChannel *ioc,
78 const struct iovec *iov,
79 size_t niov,
80 int *fds,
81 size_t nfds,
82 int flags,
83 Error **errp)
84 {
85 QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc);
86 QEMUIOVector qiov;
87 int ret;
88
89 qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov);
90 ret = bdrv_writev_vmstate(bioc->bs, &qiov, bioc->offset);
91 if (ret < 0) {
92 error_setg_errno(errp, -ret, "bdrv_writev_vmstate failed");
93 return -1;
94 }
95
96 bioc->offset += qiov.size;
97 return qiov.size;
98 }
99
100 static ssize_t
101 qio_channel_block_preadv(QIOChannel *ioc,
102 const struct iovec *iov,
103 size_t niov,
104 off_t offset,
105 Error **errp)
106 {
107 QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc);
108 QEMUIOVector qiov;
109 int ret;
110
111 qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov);
112 ret = bdrv_readv_vmstate(bioc->bs, &qiov, offset);
113 if (ret < 0) {
114 error_setg_errno(errp, -ret, "bdrv_readv_vmstate failed");
115 return -1;
116 }
117
118 return qiov.size;
119 }
120
121 static ssize_t
122 qio_channel_block_pwritev(QIOChannel *ioc,
123 const struct iovec *iov,
124 size_t niov,
125 off_t offset,
126 Error **errp)
127 {
128 QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc);
129 QEMUIOVector qiov;
130 int ret;
131
132 qemu_iovec_init_external(&qiov, (struct iovec *)iov, niov);
133 ret = bdrv_writev_vmstate(bioc->bs, &qiov, offset);
134 if (ret < 0) {
135 error_setg_errno(errp, -ret, "bdrv_writev_vmstate failed");
136 return -1;
137 }
138
139 return qiov.size;
140 }
141
142 static int
143 qio_channel_block_set_blocking(QIOChannel *ioc,
144 bool enabled,
145 Error **errp)
146 {
147 if (!enabled) {
148 error_setg(errp, "Non-blocking mode not supported for block devices");
149 return -1;
150 }
151 return 0;
152 }
153
154
155 static off_t
156 qio_channel_block_seek(QIOChannel *ioc,
157 off_t offset,
158 int whence,
159 Error **errp)
160 {
161 QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc);
162
163 switch (whence) {
164 case SEEK_SET:
165 bioc->offset = offset;
166 break;
167 case SEEK_CUR:
168 bioc->offset += offset;
169 break;
170 case SEEK_END:
171 error_setg(errp, "Size of VMstate region is unknown");
172 return (off_t)-1;
173 default:
174 g_assert_not_reached();
175 }
176
177 return bioc->offset;
178 }
179
180
181 static int
182 qio_channel_block_close(QIOChannel *ioc,
183 Error **errp)
184 {
185 QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc);
186 int rv = bdrv_flush(bioc->bs);
187
188 if (rv < 0) {
189 error_setg_errno(errp, -rv,
190 "Unable to flush VMState");
191 return -1;
192 }
193
194 g_clear_pointer(&bioc->bs, bdrv_unref);
195 bioc->offset = 0;
196
197 return 0;
198 }
199
200
201 static void
202 qio_channel_block_set_aio_fd_handler(QIOChannel *ioc,
203 AioContext *read_ctx,
204 IOHandler *io_read,
205 AioContext *write_ctx,
206 IOHandler *io_write,
207 void *opaque)
208 {
209 /* XXX anything we can do here ? */
210 }
211
212
213 static void
214 qio_channel_block_class_init(ObjectClass *klass,
215 const void *class_data G_GNUC_UNUSED)
216 {
217 QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
218
219 ioc_klass->io_writev = qio_channel_block_writev;
220 ioc_klass->io_readv = qio_channel_block_readv;
221 ioc_klass->io_set_blocking = qio_channel_block_set_blocking;
222 ioc_klass->io_preadv = qio_channel_block_preadv;
223 ioc_klass->io_pwritev = qio_channel_block_pwritev;
224 ioc_klass->io_seek = qio_channel_block_seek;
225 ioc_klass->io_close = qio_channel_block_close;
226 ioc_klass->io_set_aio_fd_handler = qio_channel_block_set_aio_fd_handler;
227 }
228
229 static const TypeInfo qio_channel_block_info = {
230 .parent = TYPE_QIO_CHANNEL,
231 .name = TYPE_QIO_CHANNEL_BLOCK,
232 .instance_size = sizeof(QIOChannelBlock),
233 .instance_finalize = qio_channel_block_finalize,
234 .class_init = qio_channel_block_class_init,
235 };
236
237 static void
238 qio_channel_block_register_types(void)
239 {
240 type_register_static(&qio_channel_block_info);
241 }
242
243 type_init(qio_channel_block_register_types);