ia64/xen-unstable

view tools/ioemu/block-vbd.c @ 17397:6bf674bd386d

stubdom: add asynchronous disk flush support

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Sat Apr 05 22:20:25 2008 +0100 (2008-04-05)
parents 491a3b62ae5b
children 6c1eb35869fd
line source
1 /*
2 * Block driver for Mini-os PV devices
3 * Based on block-raw.c
4 *
5 * Copyright (c) 2006 Fabrice Bellard, 2007 Samuel Thibault
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25 #include "vl.h"
26 #include "block_int.h"
27 #include <assert.h>
28 #include <xenbus.h>
29 #include <blkfront.h>
30 #include <malloc.h>
32 #define SECTOR_SIZE 512
34 #ifndef QEMU_TOOL
35 #include "exec-all.h"
36 #endif
38 #define DEBUG_BLOCK
39 #ifdef DEBUG_BLOCK
40 #define DEBUG_BLOCK_PRINT( formatCstr, args... ) fprintf( logfile, formatCstr, ##args ); fflush( logfile )
41 #else
42 #define DEBUG_BLOCK_PRINT( formatCstr, args... )
43 #endif
45 #define FTYPE_FILE 0
46 #define FTYPE_CD 1
47 #define FTYPE_FD 2
49 typedef struct BDRVVbdState {
50 struct blkfront_dev *dev;
51 int fd;
52 struct blkfront_info info;
53 QEMU_LIST_ENTRY(BDRVVbdState) list;
54 } BDRVVbdState;
56 QEMU_LIST_HEAD(, BDRVVbdState) vbds;
58 static int vbd_probe(const uint8_t *buf, int buf_size, const char *filename)
59 {
60 char *value;
61 if (xenbus_read(XBT_NIL, filename, &value))
62 return 0;
63 free(value);
64 return 100;
65 }
67 static void vbd_io_completed(void *opaque)
68 {
69 BDRVVbdState *s = opaque;
70 blkfront_aio_poll(s->dev);
71 }
73 static int vbd_open(BlockDriverState *bs, const char *filename, int flags)
74 {
75 BDRVVbdState *s = bs->opaque;
77 //handy to test posix access
78 //return -EIO;
80 s->dev = init_blkfront((char *) filename, &s->info);
82 if (!s->dev)
83 return -EIO;
85 if (SECTOR_SIZE % s->info.sector_size) {
86 printf("sector size is %d, we only support sector sizes that divide %d\n", s->info.sector_size, SECTOR_SIZE);
87 return -EIO;
88 }
90 s->fd = blkfront_open(s->dev);
91 qemu_set_fd_handler(s->fd, vbd_io_completed, NULL, s);
93 QEMU_LIST_INSERT_HEAD(&vbds, s, list);
95 return 0;
96 }
98 typedef struct VbdAIOCB {
99 BlockDriverAIOCB common;
100 struct blkfront_aiocb aiocb;
101 } VbdAIOCB;
103 void qemu_aio_init(void)
104 {
105 }
107 void qemu_aio_poll(void)
108 {
109 }
111 /* Wait for all IO requests to complete. */
112 void qemu_aio_flush(void)
113 {
114 BDRVVbdState *s;
115 for (s = vbds.lh_first; s; s = s->list.le_next)
116 blkfront_sync(s->dev);
117 }
119 void qemu_aio_wait_start(void)
120 {
121 }
123 void qemu_aio_wait(void)
124 {
125 int some = 0;
126 DEFINE_WAIT(w);
127 while (1) {
128 BDRVVbdState *s;
129 add_waiter(w, blkfront_queue);
130 for (s = vbds.lh_first; s; s = s->list.le_next)
131 if (blkfront_aio_poll(s->dev))
132 some = 1;
133 if (some)
134 break;
135 schedule();
136 }
137 remove_waiter(w);
138 }
140 void qemu_aio_wait_end(void)
141 {
142 }
144 static void vbd_aio_callback(struct blkfront_aiocb *aiocbp, int ret) {
145 VbdAIOCB *acb = aiocbp->data;
147 acb->common.cb(acb->common.opaque, ret);
148 qemu_aio_release(acb);
149 }
151 static VbdAIOCB *vbd_aio_setup(BlockDriverState *bs,
152 int64_t sector_num, uint8_t *buf, int nb_sectors,
153 BlockDriverCompletionFunc *cb, void *opaque)
154 {
155 BDRVVbdState *s = bs->opaque;
156 VbdAIOCB *acb;
158 acb = qemu_aio_get(bs, cb, opaque);
159 if (!acb)
160 return NULL;
161 acb->aiocb.aio_dev = s->dev;
162 acb->aiocb.aio_buf = buf;
163 acb->aiocb.aio_nbytes = nb_sectors * SECTOR_SIZE;
164 acb->aiocb.aio_offset = sector_num * SECTOR_SIZE;
165 acb->aiocb.aio_cb = vbd_aio_callback;
166 acb->aiocb.data = acb;
168 return acb;
169 }
171 static BlockDriverAIOCB *vbd_aio_read(BlockDriverState *bs,
172 int64_t sector_num, uint8_t *buf, int nb_sectors,
173 BlockDriverCompletionFunc *cb, void *opaque)
174 {
175 VbdAIOCB *acb;
177 acb = vbd_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
178 if (!acb)
179 return NULL;
180 blkfront_aio(&acb->aiocb, 0);
181 return &acb->common;
182 }
184 static BlockDriverAIOCB *vbd_aio_write(BlockDriverState *bs,
185 int64_t sector_num, const uint8_t *buf, int nb_sectors,
186 BlockDriverCompletionFunc *cb, void *opaque)
187 {
188 VbdAIOCB *acb;
190 acb = vbd_aio_setup(bs, sector_num, (uint8_t*) buf, nb_sectors, cb, opaque);
191 if (!acb)
192 return NULL;
193 blkfront_aio(&acb->aiocb, 1);
194 return &acb->common;
195 }
197 static void vbd_cb(void *data, int ret) {
198 int *result = data;
199 result[0] = 1;
200 result[1] = ret;
201 }
203 static int vbd_aligned_io(BlockDriverState *bs,
204 int64_t sector_num, uint8_t *buf, int nb_sectors, int write)
205 {
206 VbdAIOCB *acb;
207 int result[2];
208 result[0] = 0;
209 qemu_aio_wait_start();
210 acb = vbd_aio_setup(bs, sector_num, (uint8_t*) buf, nb_sectors, vbd_cb, &result);
211 blkfront_aio(&acb->aiocb, write);
212 while (!result[0])
213 qemu_aio_wait();
214 qemu_aio_wait_end();
215 return result[1];
216 }
218 static int vbd_read(BlockDriverState *bs,
219 int64_t sector_num, uint8_t *buf, int nb_sectors)
220 {
221 uint8_t *iobuf;
222 int ret;
223 /* page alignment would be a bit better, but that's still fine compared to
224 * copying */
225 if (!((uintptr_t)buf & (SECTOR_SIZE-1)))
226 return vbd_aligned_io(bs, sector_num, buf, nb_sectors, 0);
227 iobuf = qemu_memalign(PAGE_SIZE, nb_sectors * SECTOR_SIZE);
228 ret = vbd_aligned_io(bs, sector_num, iobuf, nb_sectors, 0);
229 memcpy(buf, iobuf, nb_sectors * SECTOR_SIZE);
230 free(iobuf);
231 if (ret < 0)
232 return ret;
233 else if (ret != nb_sectors * SECTOR_SIZE)
234 return -EINVAL;
235 else
236 return 0;
237 }
239 static int vbd_write(BlockDriverState *bs,
240 int64_t sector_num, const uint8_t *buf, int nb_sectors)
241 {
242 uint8_t *iobuf;
243 int ret;
244 if (!((uintptr_t)buf & (SECTOR_SIZE-1)))
245 return vbd_aligned_io(bs, sector_num, (uint8_t*) buf, nb_sectors, 1);
246 iobuf = qemu_memalign(PAGE_SIZE, nb_sectors * SECTOR_SIZE);
247 memcpy(iobuf, buf, nb_sectors * SECTOR_SIZE);
248 ret = vbd_aligned_io(bs, sector_num, iobuf, nb_sectors, 1);
249 free(iobuf);
250 if (ret < 0)
251 return ret;
252 else if (ret != nb_sectors * SECTOR_SIZE)
253 return -EINVAL;
254 else
255 return 0;
256 }
258 static void vbd_aio_cancel(BlockDriverAIOCB *blockacb)
259 {
260 /* TODO */
261 //VbdAIOCB *acb = (VbdAIOCB *)blockacb;
263 // Try to cancel. If can't, wait for it, drop the callback and call qemu_aio_release(acb)
264 }
266 static void vbd_nop_cb(void *opaque, int ret)
267 {
268 }
270 static BlockDriverAIOCB *vbd_aio_flush(BlockDriverState *bs,
271 BlockDriverCompletionFunc *cb, void *opaque)
272 {
273 BDRVVbdState *s = bs->opaque;
274 VbdAIOCB *acb = NULL;
276 if (s->info.barrier == 1) {
277 acb = vbd_aio_setup(bs, 0, NULL, 0,
278 s->info.flush == 1 ? vbd_nop_cb : cb, opaque);
279 if (!acb)
280 return NULL;
281 blkfront_aio_push_operation(&acb->aiocb, BLKIF_OP_WRITE_BARRIER);
282 }
283 if (s->info.flush == 1) {
284 acb = vbd_aio_setup(bs, 0, NULL, 0, cb, opaque);
285 if (!acb)
286 return NULL;
287 blkfront_aio_push_operation(&acb->aiocb, BLKIF_OP_FLUSH_DISKCACHE);
288 }
289 return &acb->common;
290 }
292 static void vbd_close(BlockDriverState *bs)
293 {
294 BDRVVbdState *s = bs->opaque;
295 bs->total_sectors = 0;
296 if (s->fd >= 0) {
297 qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
298 close(s->fd);
299 s->fd = -1;
300 }
301 QEMU_LIST_REMOVE(s, list);
302 }
304 static int64_t vbd_getlength(BlockDriverState *bs)
305 {
306 BDRVVbdState *s = bs->opaque;
307 return s->info.sectors * s->info.sector_size;
308 }
310 static int vbd_flush(BlockDriverState *bs)
311 {
312 BDRVVbdState *s = bs->opaque;
313 blkfront_sync(s->dev);
314 return 0;
315 }
317 /***********************************************/
318 /* host device */
320 static int vbd_is_inserted(BlockDriverState *bs)
321 {
322 /* TODO: monitor the backend */
323 return 1;
324 }
326 /* currently only used by fdc.c, but a CD version would be good too */
327 static int vbd_media_changed(BlockDriverState *bs)
328 {
329 /* TODO: monitor the backend */
330 return -ENOTSUP;
331 }
333 static int vbd_eject(BlockDriverState *bs, int eject_flag)
334 {
335 /* TODO: Xen support needed */
336 return -ENOTSUP;
337 }
339 static int vbd_set_locked(BlockDriverState *bs, int locked)
340 {
341 /* TODO: Xen support needed */
342 return -ENOTSUP;
343 }
345 BlockDriver bdrv_vbd = {
346 "vbd",
347 sizeof(BDRVVbdState),
348 vbd_probe,
349 vbd_open,
350 NULL,
351 NULL,
352 vbd_close,
353 NULL,
354 vbd_flush,
356 .bdrv_aio_read = vbd_aio_read,
357 .bdrv_aio_write = vbd_aio_write,
358 .bdrv_aio_cancel = vbd_aio_cancel,
359 .bdrv_aio_flush = vbd_aio_flush,
360 .aiocb_size = sizeof(VbdAIOCB),
361 .bdrv_read = vbd_read,
362 .bdrv_write = vbd_write,
363 .bdrv_getlength = vbd_getlength,
365 /* removable device support */
366 .bdrv_is_inserted = vbd_is_inserted,
367 .bdrv_media_changed = vbd_media_changed,
368 .bdrv_eject = vbd_eject,
369 .bdrv_set_locked = vbd_set_locked,
370 };