aboutsummaryrefslogtreecommitdiffstats
path: root/tools/ioemu/block-vbd.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/ioemu/block-vbd.c')
-rw-r--r--tools/ioemu/block-vbd.c345
1 files changed, 345 insertions, 0 deletions
diff --git a/tools/ioemu/block-vbd.c b/tools/ioemu/block-vbd.c
new file mode 100644
index 0000000000..937bb5e62d
--- /dev/null
+++ b/tools/ioemu/block-vbd.c
@@ -0,0 +1,345 @@
+/*
+ * Block driver for Mini-os PV devices
+ * Based on block-raw.c
+ *
+ * Copyright (c) 2006 Fabrice Bellard, 2007 Samuel Thibault
+ *
+ * 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 "vl.h"
+#include "block_int.h"
+#include <assert.h>
+#include <xenbus.h>
+#include <blkfront.h>
+#include <malloc.h>
+
+#define SECTOR_SIZE 512
+
+#ifndef QEMU_TOOL
+#include "exec-all.h"
+#endif
+
+#define DEBUG_BLOCK
+#ifdef DEBUG_BLOCK
+#define DEBUG_BLOCK_PRINT( formatCstr, args... ) fprintf( logfile, formatCstr, ##args ); fflush( logfile )
+#else
+#define DEBUG_BLOCK_PRINT( formatCstr, args... )
+#endif
+
+#define FTYPE_FILE 0
+#define FTYPE_CD 1
+#define FTYPE_FD 2
+
+typedef struct BDRVVbdState {
+ struct blkfront_dev *dev;
+ int fd;
+ int type;
+ int mode;
+ uint64_t sectors;
+ unsigned sector_size;
+ QEMU_LIST_ENTRY(BDRVVbdState) list;
+} BDRVVbdState;
+
+QEMU_LIST_HEAD(, BDRVVbdState) vbds;
+
+static int vbd_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+ char *value;
+ if (xenbus_read(XBT_NIL, filename, &value))
+ return 0;
+ free(value);
+ return 100;
+}
+
+static void vbd_io_completed(void *opaque)
+{
+ BDRVVbdState *s = opaque;
+ blkfront_aio_poll(s->dev);
+}
+
+static int vbd_open(BlockDriverState *bs, const char *filename, int flags)
+{
+ BDRVVbdState *s = bs->opaque;
+
+ //handy to test posix access
+ //return -EIO;
+
+ s->dev = init_blkfront((char *) filename, &s->sectors, &s->sector_size, &s->mode);
+
+ if (!s->dev)
+ return -EIO;
+
+ if (SECTOR_SIZE % s->sector_size) {
+ printf("sector size is %d, we only support sector sizes that divide %d\n", s->sector_size, SECTOR_SIZE);
+ return -EIO;
+ }
+
+ s->fd = blkfront_open(s->dev);
+ qemu_set_fd_handler(s->fd, vbd_io_completed, NULL, s);
+
+ QEMU_LIST_INSERT_HEAD(&vbds, s, list);
+
+ return 0;
+}
+
+typedef struct VbdAIOCB {
+ BlockDriverAIOCB common;
+ struct blkfront_aiocb aiocb;
+} VbdAIOCB;
+
+void qemu_aio_init(void)
+{
+}
+
+void qemu_aio_poll(void)
+{
+}
+
+/* Wait for all IO requests to complete. */
+void qemu_aio_flush(void)
+{
+ BDRVVbdState *s;
+ for (s = vbds.lh_first; s; s = s->list.le_next)
+ blkfront_sync(s->dev);
+}
+
+void qemu_aio_wait_start(void)
+{
+}
+
+void qemu_aio_wait(void)
+{
+ int some = 0;
+ DEFINE_WAIT(w);
+ while (1) {
+ BDRVVbdState *s;
+ add_waiter(w, blkfront_queue);
+ for (s = vbds.lh_first; s; s = s->list.le_next)
+ if (blkfront_aio_poll(s->dev))
+ some = 1;
+ if (some)
+ break;
+ schedule();
+ }
+ remove_waiter(w);
+}
+
+void qemu_aio_wait_end(void)
+{
+}
+
+static void vbd_aio_callback(struct blkfront_aiocb *aiocbp, int ret) {
+ VbdAIOCB *acb = aiocbp->data;
+
+ acb->common.cb(acb->common.opaque, ret);
+ qemu_aio_release(acb);
+}
+
+static VbdAIOCB *vbd_aio_setup(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BDRVVbdState *s = bs->opaque;
+ VbdAIOCB *acb;
+
+ acb = qemu_aio_get(bs, cb, opaque);
+ if (!acb)
+ return NULL;
+ acb->aiocb.aio_dev = s->dev;
+ acb->aiocb.aio_buf = buf;
+ acb->aiocb.aio_nbytes = nb_sectors * SECTOR_SIZE;
+ acb->aiocb.aio_offset = sector_num * SECTOR_SIZE;
+ acb->aiocb.aio_cb = vbd_aio_callback;
+ acb->aiocb.data = acb;
+
+ return acb;
+}
+
+static BlockDriverAIOCB *vbd_aio_read(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ VbdAIOCB *acb;
+
+ acb = vbd_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
+ if (!acb)
+ return NULL;
+ blkfront_aio(&acb->aiocb, 0);
+ return &acb->common;
+}
+
+static BlockDriverAIOCB *vbd_aio_write(BlockDriverState *bs,
+ int64_t sector_num, const uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ VbdAIOCB *acb;
+
+ acb = vbd_aio_setup(bs, sector_num, (uint8_t*) buf, nb_sectors, cb, opaque);
+ if (!acb)
+ return NULL;
+ blkfront_aio(&acb->aiocb, 1);
+ return &acb->common;
+}
+
+static void vbd_cb(void *data, int ret) {
+ int *result = data;
+ result[0] = 1;
+ result[1] = ret;
+}
+
+static int vbd_aligned_io(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors, int write)
+{
+ VbdAIOCB *acb;
+ int result[2];
+ result[0] = 0;
+ qemu_aio_wait_start();
+ acb = vbd_aio_setup(bs, sector_num, (uint8_t*) buf, nb_sectors, vbd_cb, &result);
+ blkfront_aio(&acb->aiocb, write);
+ while (!result[0])
+ qemu_aio_wait();
+ qemu_aio_wait_end();
+ return result[1];
+}
+
+static int vbd_read(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors)
+{
+ uint8_t *iobuf;
+ int ret;
+ /* page alignment would be a bit better, but that's still fine compared to
+ * copying */
+ if (!((uintptr_t)buf & (SECTOR_SIZE-1)))
+ return vbd_aligned_io(bs, sector_num, buf, nb_sectors, 0);
+ iobuf = qemu_memalign(PAGE_SIZE, nb_sectors * SECTOR_SIZE);
+ ret = vbd_aligned_io(bs, sector_num, iobuf, nb_sectors, 0);
+ memcpy(buf, iobuf, nb_sectors * SECTOR_SIZE);
+ free(iobuf);
+ if (ret < 0)
+ return ret;
+ else if (ret != nb_sectors * SECTOR_SIZE)
+ return -EINVAL;
+ else
+ return 0;
+}
+
+static int vbd_write(BlockDriverState *bs,
+ int64_t sector_num, const uint8_t *buf, int nb_sectors)
+{
+ uint8_t *iobuf;
+ int ret;
+ if (!((uintptr_t)buf & (SECTOR_SIZE-1)))
+ return vbd_aligned_io(bs, sector_num, (uint8_t*) buf, nb_sectors, 1);
+ iobuf = qemu_memalign(PAGE_SIZE, nb_sectors * SECTOR_SIZE);
+ memcpy(iobuf, buf, nb_sectors * SECTOR_SIZE);
+ ret = vbd_aligned_io(bs, sector_num, iobuf, nb_sectors, 1);
+ free(iobuf);
+ if (ret < 0)
+ return ret;
+ else if (ret != nb_sectors * SECTOR_SIZE)
+ return -EINVAL;
+ else
+ return 0;
+}
+
+static void vbd_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ /* TODO */
+ //VbdAIOCB *acb = (VbdAIOCB *)blockacb;
+
+ // Try to cancel. If can't, wait for it, drop the callback and call qemu_aio_release(acb)
+}
+
+static void vbd_close(BlockDriverState *bs)
+{
+ BDRVVbdState *s = bs->opaque;
+ bs->total_sectors = 0;
+ if (s->fd >= 0) {
+ close(s->fd);
+ s->fd = -1;
+ }
+ QEMU_LIST_REMOVE(s, list);
+}
+
+static int64_t vbd_getlength(BlockDriverState *bs)
+{
+ BDRVVbdState *s = bs->opaque;
+ return s->sectors * s->sector_size;
+}
+
+static void vbd_flush(BlockDriverState *bs)
+{
+ BDRVVbdState *s = bs->opaque;
+ blkfront_sync(s->dev);
+}
+
+/***********************************************/
+/* host device */
+
+static int vbd_is_inserted(BlockDriverState *bs)
+{
+ /* TODO: monitor the backend */
+ return 1;
+}
+
+/* currently only used by fdc.c, but a CD version would be good too */
+static int vbd_media_changed(BlockDriverState *bs)
+{
+ /* TODO: monitor the backend */
+ return -ENOTSUP;
+}
+
+static int vbd_eject(BlockDriverState *bs, int eject_flag)
+{
+ /* TODO: Xen support needed */
+ return -ENOTSUP;
+}
+
+static int vbd_set_locked(BlockDriverState *bs, int locked)
+{
+ /* TODO: Xen support needed */
+ return -ENOTSUP;
+}
+
+BlockDriver bdrv_vbd = {
+ "vbd",
+ sizeof(BDRVVbdState),
+ vbd_probe,
+ vbd_open,
+ NULL,
+ NULL,
+ vbd_close,
+ NULL,
+ vbd_flush,
+
+ .bdrv_aio_read = vbd_aio_read,
+ .bdrv_aio_write = vbd_aio_write,
+ .bdrv_aio_cancel = vbd_aio_cancel,
+ .aiocb_size = sizeof(VbdAIOCB),
+ .bdrv_read = vbd_read,
+ .bdrv_write = vbd_write,
+ .bdrv_getlength = vbd_getlength,
+
+ /* removable device support */
+ .bdrv_is_inserted = vbd_is_inserted,
+ .bdrv_media_changed = vbd_media_changed,
+ .bdrv_eject = vbd_eject,
+ .bdrv_set_locked = vbd_set_locked,
+};
+