This is a simple block device, with the backend in userspace. While
performance is good, it's not production-ready because it need to keep
track of which backend process to kill when device goes away (look for
"So very, very wrong"), and also should use separate device numbers
for front and backend.
diff -r 20b744b2c4c0 .hgignore
--- a/.hgignore Mon Jun 5 06:41:24 2006
+++ b/.hgignore Tue Jun 6 14:56:24 2006
@@ -147,6 +147,7 @@
^tools/security/xen/.*$
^tools/tests/test_x86_emulator$
^tools/vdevice/vdevice$
+^tools/vdevice/xensblk$
^tools/vnet/gc$
^tools/vnet/gc.*/.*$
^tools/vnet/vnet-module/.*\.ko$
diff -r 20b744b2c4c0 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile Mon Jun 5 06:41:24 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Tue Jun 6 14:56:24 2006
@@ -10,6 +10,7 @@
obj-y += xenbus/
obj-y += vdevice/
obj-m += sharenet/
+obj-m += shareblock/
obj-y += xenshare.o
obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/
diff -r 20b744b2c4c0 tools/examples/Makefile
--- a/tools/examples/Makefile Mon Jun 5 06:41:24 2006
+++ b/tools/examples/Makefile Tue Jun 6 14:56:24 2006
@@ -35,7 +35,7 @@
XEN_SCRIPT_DATA += vtpm-migration.sh
XEN_HOTPLUG_DIR = /etc/hotplug
-XEN_HOTPLUG_SCRIPTS = xen-backend.agent
+XEN_HOTPLUG_SCRIPTS = xen-backend.agent vdevice.agent
UDEV_RULES_DIR = /etc/udev
UDEV_RULES = xen-backend.rules
diff -r 20b744b2c4c0 tools/vdevice/Makefile
--- a/tools/vdevice/Makefile Mon Jun 5 06:41:24 2006
+++ b/tools/vdevice/Makefile Tue Jun 6 14:56:24 2006
@@ -19,16 +19,21 @@
CFLAGS += $(BASECFLAGS)
LDFLAGS += $(PROFILE) -L$(XEN_LIBXC) -L$(XEN_XENSTORE)
-all: vdevice
+all: vdevice xensblk
clean:
- rm -f vdevice *.o .*.d
+ rm -f vdevice xensblk *.o
vdevice: vdevice.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxenctrl -lxenstore -o $@
-install: vdevice
+xensblk: xensblk.o
+ $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxenctrl -o $@
+
+
+install: vdevice xensblk
$(INSTALL_DIR) -p $(DESTDIR)/usr/sbin
$(INSTALL_PROG) vdevice $(DESTDIR)/usr/sbin
+ $(INSTALL_PROG) xensblk $(DESTDIR)/usr/sbin
-include $(PROG_DEP)
diff -r 20b744b2c4c0 tools/vdevice/vdevice.c
--- a/tools/vdevice/vdevice.c Mon Jun 5 06:41:24 2006
+++ b/tools/vdevice/vdevice.c Tue Jun 6 14:56:24 2006
@@ -22,6 +22,7 @@
#include <xen/event_channel.h>
#include <xen/linux/privcmd.h>
#include <xen/io/vdevice.h>
+#include <xen/linux/xensblk.h>
#include <xc_private.h>
@@ -368,6 +369,61 @@
/* FIXME: wait for ack! */
}
+/* --create. Returns argnum of first domain arg. */
+static int block_create(struct vdevice_type *type,
+ share_ref_t ref, void *map,
+ int argc, char *argv[])
+{
+ struct xensblk_page *sharepage = map;
+
+ /* We need backend and file. */
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "Usage:\n\t"
+ "%s --create block <backend-file> <backend-domid>
[<frontend-domid>]\n",
+ PROGRAM_NAME);
+ return -1;
+ }
+ /* FIXME: Check length before copying to shared page */
+ /* FIXME: Handle relative paths */
+ if (argv[0][0] != '/') {
+ fprintf(stderr, "%s: backend file must be an absolute path\n",
+ PROGRAM_NAME);
+ return -1;
+ }
+
+ /* FIXME: Allow other types here... */
+ sharepage->device_type = XENSBLK_DEVTYPE_FILE;
+ sharepage->flags = 0;
+ strcpy(sharepage->device_specific_info, argv[0]);
+
+ if (!add_vdevice_entry(argv[1], type->type, type->features,
+ type->num_pages, ref, VDEVICE_S_DRIVER_OK))
+ return -1;
+
+ return 2;
+}
+
+/* List info about this vdevice. */
+static void block_list(struct vdevice_type *type __unused,
+ const struct vdevice_desc *vdesc)
+{
+ struct xensblk_page *b;
+ unsigned int peer_id;
+
+ b = map_pages(vdesc->shared_ref, vdesc->nr_pages, &peer_id);
+ if (!b) {
+ printf(" *cannot map*");
+ return;
+ }
+ if (b->device_type == XENSBLK_DEVTYPE_FILE)
+ printf(" %.*s", sizeof(b->device_specific_info),
+ b->device_specific_info);
+ printf(" %u blocks (%llu bytes)", b->capacity_in_blocks,
+ b->capacity_in_blocks * 512ULL);
+ if (b->error)
+ printf(" ERR %i", b->error);
+}
+
/* FIXME: some callers need to recover, not exit if this fails... */
static share_ref_t domid_arg(const char *arg)
{
@@ -392,6 +448,13 @@
.num_pages = 1,
.create = net_create,
.list = net_list,
+ },
+ { .name = "block",
+ .type = 2,
+ .features = 1,
+ .num_pages = 1,
+ .create = block_create,
+ .list = block_list,
},
};
diff -r 20b744b2c4c0 linux-2.6-xen-sparse/drivers/xen/shareblock/Makefile
--- /dev/null Mon Jun 5 06:41:24 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/shareblock/Makefile Tue Jun 6
14:56:24 2006
@@ -0,0 +1,1 @@
+obj-m += xensblk.o
diff -r 20b744b2c4c0 linux-2.6-xen-sparse/drivers/xen/shareblock/xensblk.c
--- /dev/null Mon Jun 5 06:41:24 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/shareblock/xensblk.c Tue Jun 6
14:56:24 2006
@@ -0,0 +1,293 @@
+/* A simple block driver for Xen, using share ops.
+ *
+ * Copyright 2006 Rusty Russell <rusty@xxxxxxxxxxxxxxx> IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+//#define DEBUG
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/vdevice.h>
+#include <xen/public/xensblk.h>
+#include <xen/interface/share.h>
+#include <xen/evtchn.h>
+
+struct blockshare
+{
+ spinlock_t lock;
+
+ struct vdevice *vdev;
+
+ /* The disk structure for the kernel. */
+ struct gendisk *disk;
+
+ /* The major number for this disk. */
+ int major;
+
+ struct xensblk_page *xb_page;
+
+ /* Awaiting the response from the other end. */
+ struct request *req;
+ int op;
+ u32 req_len;
+
+ /* Handler which notifies us of changes. */
+ struct xen_share_handler handler;
+
+ /* For read, this holds bytes server sent. */
+ u32 bytes_read;
+ u32 write_done;
+};
+
+static void done_with_request(struct blockshare *bs, int error)
+{
+ pr_debug("Done with request, error %i\n", error);
+ end_request(bs->req, error == 0);
+ bs->req = NULL;
+ /* Reset error. */
+ bs->xb_page->error = 0;
+ blk_start_queue(bs->disk->queue);
+}
+
+static void blockshare_handler(struct xen_share_handler *handler)
+{
+ struct blockshare *bs;
+ unsigned long flags;
+
+ bs = container_of(handler, struct blockshare, handler);
+ /* Have they sent a reply? */
+ spin_lock_irqsave(&bs->lock, flags);
+ if (bs->req) {
+ int err = bs->xb_page->error;
+ if (err)
+ done_with_request(bs, err);
+ else if (bs->op == 1) {
+ if (bs->write_done == 0) {
+ /* Write simply fills in error field. */
+ pr_debug("xensblk: write error = %i\n",
+ bs->xb_page->error);
+ done_with_request(bs, bs->xb_page->error);
+ } else
+ pr_debug("xensblk: write in progress?\n");
+ } else if (bs->op == 0) {
+ if (bs->bytes_read != 0) {
+ /* Read should have transferred data. */
+ done_with_request(bs,
+ bs->bytes_read!=bs->req_len);
+ } else
+ pr_debug("xensblk: read in progress?\n");
+ } else
+ BUG();
+ } else {
+ printk("No request %p\n", bs->req);
+ }
+ spin_unlock_irqrestore(&bs->lock, flags);
+}
+
+/* Returns number of sg elements used. */
+static unsigned req_to_sg(struct request *req, struct xen_sg sg[XEN_SG_MAX],
+ unsigned int *len)
+{
+ unsigned int i = 0, idx;
+ struct bio *bio;
+
+ *len = 0;
+ rq_for_each_bio(bio, req) {
+ struct bio_vec *bvec;
+ bio_for_each_segment(bvec, bio, idx) {
+ BUG_ON(i == XEN_SG_MAX);
+ sg[i].addr = page_to_pseudophys(bvec->bv_page)
+ + bvec->bv_offset;
+ sg[i].len = bvec->bv_len;
+ BUG_ON(sg[i].addr / PAGE_SIZE !=
+ (sg[i].addr + sg[i].len - 1) / PAGE_SIZE);
+ *len += sg[i].len;
+ i++;
+ }
+ }
+ return i;
+}
+
+static int send_op(struct blockshare *bs, struct request *req, int is_write)
+{
+ int ret;
+
+ pr_debug("send_op: %s sector %li\n",
+ is_write ? "WRITE" : "READ", req->sector);
+
+ bs->xb_page->req_type = is_write;
+ bs->xb_page->sector = req->sector;
+ bs->op = 0;
+ bs->req = req;
+
+ if (is_write) {
+ struct xen_sg out[XEN_SG_MAX];
+ unsigned int num;
+
+ num = req_to_sg(req, out, &bs->req_len);
+ bs->xb_page->num = bs->req_len / 512;
+ bs->op = 1;
+ bs->write_done = 1;
+ ret = xen_sg_xfer(bs->vdev->share, XENSBLK_SERVER_QUEUE,
+ XEN_SG_OUT, num, out);
+ pr_debug("Write xfer returned %i\n", ret);
+ if (ret < 0 || ret < bs->req_len) {
+ printk("xensblk: write xfer %i returned %i\n",
+ bs->req_len, ret);
+ goto fail;
+ }
+ } else {
+ struct xen_sg in[XEN_SG_MAX];
+ unsigned int num;
+
+ /* Get receive straight into req. */
+ num = req_to_sg(req, in, &bs->req_len);
+ bs->xb_page->num = bs->req_len / 512;
+ bs->bytes_read = 0;
+ ret = xen_sg_register(bs->vdev->share, XEN_SG_IN,
+ XENSBLK_CLIENT_QUEUE,
+ &bs->bytes_read, num, in);
+ if (ret != 0) {
+ printk("xensblk: could not set up receive sg: %i\n",
+ ret);
+ goto fail;
+ }
+ xen_share_trigger(bs->vdev->share, XENSBLK_OP_READY);
+ }
+ return 0;
+
+fail:
+ bs->req = NULL;
+ return -EIO;
+}
+
+static void do_blkshare_request(request_queue_t *q)
+{
+ struct request *req;
+
+ req = elv_next_request(q);
+ if (!req)
+ return;
+
+ if (!blk_fs_request(req)) {
+ printk("Got non-command 0x%08lx\n", req->flags);
+ req->errors++;
+ end_request(req, 0);
+ } else {
+ struct blockshare *bs;
+ bs = req->rq_disk->private_data;
+ if (send_op(bs, req, rq_data_dir(req) == WRITE) < 0) {
+ req->errors++;
+ end_request(req, 0);
+ } else {
+ blk_stop_queue(q);
+ }
+ }
+}
+
+static struct block_device_operations share_fops = {
+ .owner = THIS_MODULE,
+};
+
+static int xensblk_probe(struct vdevice *vdev, const struct vdevice_id *ent)
+{
+ struct blockshare *bs;
+ int err;
+
+ bs = kmalloc(sizeof(*bs), GFP_KERNEL);
+ if (!bs)
+ return -ENOMEM;
+
+ spin_lock_init(&bs->lock);
+ bs->vdev = vdev;
+ bs->xb_page = vdev->share->addr;
+ bs->disk = alloc_disk(1);
+ if (!bs->disk) {
+ err = -ENOMEM;
+ goto out_free_bs;
+ }
+
+ bs->disk->queue = blk_init_queue(do_blkshare_request, &bs->lock);
+ if (!bs->disk->queue) {
+ err = -ENOMEM;
+ goto out_put;
+ }
+
+ /* We want virtually-mapped pages. */
+ blk_queue_bounce_limit(bs->disk->queue, BLK_BOUNCE_HIGH);
+ /* We can only handle a certain number of sg entries (one for op) */
+ blk_queue_max_phys_segments(bs->disk->queue, XEN_SG_MAX - 1);
+ /* Buffers must not cross page boundaries */
+ blk_queue_segment_boundary(bs->disk->queue, PAGE_SIZE-1);
+
+ bs->major = register_blkdev(0, "xenblock");
+ if (bs->major < 0) {
+ err = bs->major;
+ goto out_cleanup_queue;
+ }
+
+ bs->handler.handler = blockshare_handler;
+ xen_share_add_handler(vdev->share, &bs->handler);
+
+ bs->write_done = 1;
+ xen_share_watch(vdev->share, XENSBLK_OP_DONE, &bs->write_done);
+
+ printk(KERN_INFO "xen block share device %li at major %d\n",
+ vdev->share->share_ref, bs->major);
+
+ bs->disk->major = bs->major;
+ bs->disk->first_minor = 0;
+ bs->disk->private_data = bs;
+ bs->disk->fops = &share_fops;
+ sprintf(bs->disk->disk_name, "xensblock%d", bs->vdev->vdevice_index);
+ set_capacity(bs->disk, bs->xb_page->capacity_in_blocks);
+ add_disk(bs->disk);
+ vdev->private = bs;
+ return 0;
+
+out_cleanup_queue:
+ blk_cleanup_queue(bs->disk->queue);
+out_put:
+ put_disk(bs->disk);
+out_free_bs:
+ kfree(bs);
+ return err;
+}
+
+static struct vdevice_id xensblk_ids[] = {
+ { .type = 2, .features = 1 },
+ { .type = 0 },
+};
+static struct vdevice_driver xensblk_drv = {
+ .name = "xensblk",
+ .owner = THIS_MODULE,
+ .ids = xensblk_ids,
+ .probe = xensblk_probe,
+ .remove = NULL,
+ .stop = NULL,
+ .reconnect = NULL,
+};
+static __init int init(void)
+{
+ return register_vdevice_driver(&xensblk_drv);
+}
+
+module_init(init);
+
+MODULE_DESCRIPTION("Xen block driver using share");
+MODULE_LICENSE("GPL");
diff -r 20b744b2c4c0 linux-2.6-xen-sparse/include/xen/public/xensblk.h
--- /dev/null Mon Jun 5 06:41:24 2006
+++ b/linux-2.6-xen-sparse/include/xen/public/xensblk.h Tue Jun 6 14:56:24 2006
@@ -0,0 +1,38 @@
+#ifndef _LINUX_XENSBLK_H
+#define _LINUX_XENSBLK_H
+
+/* Possible device types */
+#define XENSBLK_DEVTYPE_FILE 1 /* Followed by path of file to serve. */
+
+struct xensblk_page
+{
+ /* Filled in by the creation tool */
+ uint16_t device_type;
+ uint16_t flags;
+
+ /* Contents depends on device_type */
+ char device_specific_info[256];
+
+ /* Filled in by server. */
+ uint32_t capacity_in_blocks;
+ uint32_t error;
+
+ /* Request 0 = read, 1 = write. */
+ uint32_t req_type;
+ /* Length (sectors). */
+ uint32_t num;
+ /* Sector to read/write (multiply by 512 for offset). */
+ uint64_t sector;
+};
+
+/* Triggered by client when op ready (except write: xfer triggers) */
+#define XENSBLK_OP_READY 1
+
+/* Triggered by server has finished op (except read: xfer triggers) */
+#define XENSBLK_OP_DONE 2
+
+/* Where the server and client queue their sg lists */
+#define XENSBLK_CLIENT_QUEUE 0
+#define XENSBLK_SERVER_QUEUE 1
+
+#endif /* _LINUX_XENSBLK_H */
diff -r 20b744b2c4c0 tools/examples/vdevice.agent
--- /dev/null Mon Jun 5 06:41:24 2006
+++ b/tools/examples/vdevice.agent Tue Jun 6 14:56:24 2006
@@ -0,0 +1,18 @@
+#! /bin/sh
+
+PATH=/etc/xen/scripts:$PATH
+
+exec > /tmp/log 2>&1
+echo VDEVICE called: $DEVPATH
+
+if [ `cat /sys/$DEVPATH/type` == 2 ]; then
+ case "$ACTION" in
+ add)
+ /usr/sbin/xensblk $DEVPATH >> /tmp/log 2>&1 &
+ ;;
+ remove)
+ # FIXME: So very, very wrong...
+ killall /usr/sbin/xensblk
+ ;;
+ esac
+fi
diff -r 20b744b2c4c0 tools/examples/vdevice.rules
--- /dev/null Mon Jun 5 06:41:24 2006
+++ b/tools/examples/vdevice.rules Tue Jun 6 14:56:24 2006
@@ -0,0 +1,3 @@
+SUBSYSTEM=="vdevice", SYSFS{type}=="2", ACTION=="add", RUN+="/usr/sbin/xensblk
%p &"
+# FIXME: So very, very wrong...
+SUBSYSTEM=="vdevice", SYSFS{type}=="2", ACTION=="remove", RUN+="killall
/usr/sbin/xensblk"
diff -r 20b744b2c4c0 tools/vdevice/xensblk.c
--- /dev/null Mon Jun 5 06:41:24 2006
+++ b/tools/vdevice/xensblk.c Tue Jun 6 14:56:24 2006
@@ -0,0 +1,269 @@
+/* Simple code for a userspace block device backend. */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <xen/linux/xenshare.h>
+#include <xen/io/vdevice.h>
+#include <xen/linux/xensblk.h>
+#include <err.h>
+#include <errno.h>
+#include <stdbool.h>
+#include "xenctrl.h"
+
+#define BUFFER_SIZE (getpagesize() * XEN_SG_MAX)
+
+static unsigned long get_share_ref(const char *devpath)
+{
+ char *fname;
+ FILE *f;
+ unsigned long share_ref;
+
+ asprintf(&fname, "%s/%s/share_ref", "/sys", devpath);
+ f = fopen(fname, "r");
+ if (!f)
+ err(1, "Could not open %s", fname);
+ if (fscanf(f, "%lu", &share_ref) != 1)
+ err(1, "Could not read share_ref from %s", fname);
+ fclose(f);
+ free(fname);
+ return share_ref;
+}
+
+/* We OR in these status bits. */
+static char *status_file;
+static bool add_status(uint32_t status)
+{
+ FILE *f;
+ uint32_t old_status;
+
+ f = fopen(status_file, "r+");
+ if (!f)
+ return false;
+ if (fscanf(f, "%u", &old_status) != 1)
+ return false;
+ rewind(f);
+ if (fprintf(f, "%u", old_status | status) < 0)
+ return false;
+ if (fclose(f) != 0)
+ return false;
+ return true;
+}
+
+static void set_fail_status(void)
+{
+ add_status(VDEVICE_S_FAILED);
+}
+
+static uint32_t size_in_blocks(int fd)
+{
+ struct stat st;
+
+ fstat(fd, &st);
+ return st.st_size / 512;
+}
+
+static void share_error(int err, int shareiofd, struct xensblk_page *share)
+{
+ share->error = err;
+ ioctl(shareiofd, IOCTL_XENSHARE_TRIGGER, XENSBLK_OP_DONE);
+}
+
+static void handle_read(int backingfd, int shareiofd,
+ void *buffer,
+ uint32_t num_blocks,
+ struct xensblk_page *share)
+{
+ struct xenshare_sg send;
+ int ret;
+ uint32_t num = share->num;
+ uint64_t sector = share->sector;
+
+ if ((uint64_t)num + sector > num_blocks) {
+ printf("xensblk READ: num=%u sector=%llu: out of range!\n",
+ num, sector);
+ share_error(ENOSPC, shareiofd, share);
+ return;
+ }
+
+ lseek(backingfd, sector*512, SEEK_SET);
+ ret = read(backingfd, buffer, num*512);
+ if (ret != num*512) {
+ printf("xensblk READ: num=%u sector=%llu: short read: %i!\n",
+ num, sector, ret);
+ share_error(EIO, shareiofd, share);
+ return;
+ }
+
+ send.len = num*512;
+ send.queue = XENSBLK_CLIENT_QUEUE;
+
+ ret = ioctl(shareiofd, IOCTL_XENSHARE_SG_SEND, &send);
+ if (ret != num*512) {
+ printf("xensblk READ: num=%u sector=%llu: xfer returned %i: %i",
+ num, sector, ret, errno);
+ /* They'll notice a partial xfer, but if completely failed,
+ * we have to trigger them.
+ */
+ if (ret < 0)
+ share_error(EFAULT, shareiofd, share);
+ }
+}
+
+static void handle_write(int backingfd, int shareiofd,
+ uint32_t num_blocks,
+ void *inbuf,
+ uint32_t len,
+ struct xensblk_page *share)
+{
+ int ret;
+ struct xenshare_sg reg;
+ uint32_t num = share->num;
+ uint64_t sector = share->sector;
+
+ if ((uint64_t)num + sector > num_blocks) {
+ printf("WRITE: num = %u, sector = %llu out of range!\n",
+ num, sector);
+ share->error = ENOSPC;
+ goto out;
+ }
+
+ if (len != num*512) {
+ printf("WRITE: num = %u, sector = %llu: %i bytes tranferred,
not %i!\n", num, sector, len, num*512);
+ share->error = EINVAL;
+ goto out;
+ }
+
+ lseek(backingfd, sector*512, SEEK_SET);
+ ret = write(backingfd, inbuf, num*512);
+ if (ret != num*512) {
+ printf("WRITE: num = %u, sector = %llu: Short write: %i!\n",
+ num, sector, ret);
+ share->error = EIO;
+ goto out;
+ }
+
+out:
+ /* Restore all the pages up for receiving data *before* we ack. */
+ reg.len = BUFFER_SIZE;
+ reg.queue = XENSBLK_SERVER_QUEUE;
+ if (ioctl(shareiofd, IOCTL_XENSHARE_SG_REGISTER, ®) != 0)
+ err(1, "Failed to re-register sg");
+
+ ioctl(shareiofd, IOCTL_XENSHARE_TRIGGER, XENSBLK_OP_DONE);
+}
+
+int main(int argc, char *argv[])
+{
+ int backingfd, xc, shareiofd;
+ struct xensblk_page *sharepage;
+ void *buffer;
+ int ret;
+ uint32_t num_blocks;
+ struct xenshare_get_share shareget;
+ struct xenshare_sg reg;
+
+ if (argc != 2)
+ err(1, "Usage: xensblk <devpath>");
+
+ asprintf(&status_file, "%s/%s/status", "/sys", argv[1]);
+
+ /* We have met the driver, and it is us. */
+ if (!add_status(VDEVICE_S_DRIVER))
+ err(1, "Could not update status");
+ atexit(set_fail_status);
+
+ shareiofd = open("/dev/xenshare", O_RDWR);
+ if (shareiofd < 0)
+ err(1, "Could not open '%s'", "/dev/xenshare");
+
+ xc = xc_interface_open();
+ if (xc < 0)
+ err(1, "Failed to open xc interface");
+
+ shareget.share_ref = get_share_ref(argv[1]);
+ shareget.num_pages = 1;
+ ret = ioctl(shareiofd, IOCTL_XENSHARE_GET_SHARE, &shareget);
+ if (ret < 0)
+ err(1, "Getting shared pages gave %i", ret);
+ printf("I am peer %i\n", ret);
+
+ /* Map shared page */
+ sharepage = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE,
+ MAP_SHARED, shareiofd,
+ XENSHARE_MAP_SHARE_PAGE * getpagesize());
+ if (sharepage == MAP_FAILED)
+ err(1, "Failed to map shared page");
+
+ if (!add_status(VDEVICE_S_MAPPED))
+ err(1, "Could not update status");
+
+ if (sharepage->device_type != XENSBLK_DEVTYPE_FILE)
+ errx(1, "Unknown device type %i", sharepage->device_type);
+
+ backingfd = open(sharepage->device_specific_info, O_RDWR);
+ if (backingfd < 0)
+ err(1, "Could not open '%s'",
+ sharepage->device_specific_info);
+
+ sharepage->capacity_in_blocks = num_blocks = size_in_blocks(backingfd);
+ sharepage->error = 0;
+
+ /* Map input sg. */
+ buffer = mmap(NULL, BUFFER_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED,
+ shareiofd, 0);
+ if (buffer == MAP_FAILED)
+ err(1, "Failed to map sg");
+
+ reg.len = BUFFER_SIZE;
+ reg.queue = XENSBLK_SERVER_QUEUE;
+ if (ioctl(shareiofd, IOCTL_XENSHARE_SG_REGISTER, ®) != 0)
+ err(1, "Failed to register sg");
+
+ if (ioctl(shareiofd, IOCTL_XENSHARE_WATCH, XENSBLK_OP_READY) != 0)
+ err(1, "Failed to watch for op");
+
+ /* Now we're ready to serve... */
+ if (!add_status(VDEVICE_S_DRIVER_OK))
+ err(1, "Could not update status");
+
+ for(;;) {
+ int32_t len;
+ if (read(shareiofd, &len, sizeof(len)) != sizeof(len))
+ err(1, "Short read from shareiofd");
+
+ if (-len == XENSBLK_OP_READY) {
+ if (sharepage->req_type == 0)
+ handle_read(backingfd, shareiofd, buffer,
+ num_blocks, sharepage);
+ else {
+ fprintf(stderr, "Strange, op request %i!\n",
+ sharepage->req_type);
+ share_error(EINVAL, shareiofd, sharepage);
+ }
+ } else if (len <= 0) {
+ fprintf(stderr, "Strange, bufsize %i!\n", len);
+ share_error(EINVAL, shareiofd, sharepage);
+ } else {
+ if (sharepage->req_type == 1)
+ handle_write(backingfd, shareiofd,
+ num_blocks, buffer, len,
+ sharepage);
+ else {
+ fprintf(stderr, "Strange, xfer request %i!\n",
+ sharepage->req_type);
+ share_error(EINVAL, shareiofd, sharepage);
+ }
+ }
+ }
+}
+
+
+
--
ccontrol: http://ccontrol.ozlabs.org
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|