Merge branch 'wip-xinfo-fixed' into xseg
[archipelago] / xseg / sys / xsegbd.c
index 53c3497..5d6e2d5 100644 (file)
@@ -26,7 +26,7 @@ MODULE_DESCRIPTION("xsegbd");
 MODULE_AUTHOR("XSEG");
 MODULE_LICENSE("GPL");
 
-static long sector_size = 100000;
+static long sector_size = 0;
 static long blksize = 512;
 static int major = 0;
 static char name[XSEGBD_VOLUME_NAMELEN] = "xsegbd";
@@ -292,6 +292,7 @@ static struct xseg_peer xseg_peer_xsegdev = {
 int xsegbd_xseg_init(struct xsegbd *dev)
 {
        struct xseg_port *xport;
+       struct xsegdev *xsegdev;
        int r;
 
        if (!dev->name[0])
@@ -325,12 +326,16 @@ int xsegbd_xseg_init(struct xsegbd *dev)
                XSEGLOG("WARNING: unexpected segment type '%s' vs 'xsegdev'",
                         dev->config.type);
 
-       XSEGLOG("creating segment");
-       r = xseg_create(&dev->config);
-       if (r) {
-               XSEGLOG("cannot create segment");
-               goto err3;
+       xsegdev = xsegdev_get(0);
+       if (!xsegdev->segment) {
+               XSEGLOG("creating segment");
+               r = xseg_create(&dev->config);
+               if (r) {
+                       XSEGLOG("cannot create segment");
+                       goto err3;
+               }
        }
+       xsegdev_put(xsegdev);
 
        XSEGLOG("joining segment");
        dev->xseg = xseg_join("xsegdev", "xsegbd");
@@ -375,6 +380,9 @@ err0:
 
 int xsegbd_xseg_quit(struct xsegbd *dev)
 {
+       /* make sure to unmap the segment first */
+       dev->xseg->type.ops.unmap(dev->xseg, dev->xseg->segment_size);
+
        xseg_destroy(dev->xseg);
        dev->xseg = NULL;
        return 0;
@@ -432,11 +440,7 @@ static loff_t xsegbd_get_size(struct xsegbd *dev)
        uint64_t datasize;
        loff_t size;
 
-       xseg_prepare_wait(dev->xseg, dev->src_portno);
-
        if ((xreq = xseg_get_request(dev->xseg, dev->src_portno))) {
-               xseg_cancel_wait(dev->xseg, dev->src_portno);
-
                datasize = sizeof(loff_t);
                BUG_ON(xreq->buffersize - dev->namesize < datasize);
                BUG_ON(xseg_prep_request(xreq, dev->namesize, datasize));
@@ -453,12 +457,18 @@ static loff_t xsegbd_get_size(struct xsegbd *dev)
                xseg_signal(dev->xseg, dev->dst_portno);
        }
 
+       /* callback_fn doesn't handle X_INFO reqs atm, and more importantly we
+        * cannot use an async operation to learn the disk size. Currently, this
+        * behaves like a busy-wait loop and makes insmod block until a peer
+        * responds to our X_INFO req. This will change when the sysfs interface is
+        * implemented, to handle disk operations.
+        */
        while (!(xreq = xseg_receive(dev->xseg, dev->src_portno))) ;
 
-       xseg_cancel_wait(dev->xseg, dev->src_portno);
        while (!(xreq->state & XS_SERVED)) ;
 
        data = XSEG_TAKE_PTR(xreq->data, dev->xseg->segment);
+       /* TODO: make sure we use consistent types accross peers */
        size = *((off_t *) data);
 
        if (xreq)
@@ -471,13 +481,18 @@ static int xsegbd_dev_init(struct xsegbd *dev, int id, sector_t size)
 {
        int ret = -ENOMEM;
        struct gendisk *disk;
+       unsigned int max_request_size_bytes;
 
        spin_lock_init(&dev->lock);
 
        dev->id = id;
+       ret = xsegbd_xseg_init(dev);
+       if (ret < 0)
+               goto out;
+
        dev->blk_queue = blk_alloc_queue(GFP_KERNEL);
        if (!dev->blk_queue)
-               goto out;
+               goto free_xseg;
 
        blk_init_allocated_queue(dev->blk_queue, xseg_request_fn, &dev->lock);
        dev->blk_queue->queuedata = dev;
@@ -486,11 +501,18 @@ static int xsegbd_dev_init(struct xsegbd *dev, int id, sector_t size)
        blk_queue_logical_block_size(dev->blk_queue, 512);
        blk_queue_physical_block_size(dev->blk_queue, blksize);
        blk_queue_bounce_limit(dev->blk_queue, BLK_BOUNCE_ANY);
-       /* we can handle any number of segments, BUT
-        * parts of the request may be available far sooner than others
-        * but we cannot complete them (unless we handle their bios directly).
+       
+       //blk_queue_max_segments(dev->blk_queue, 512);
+       /* calculate maximum block request size
+        * request size in pages * page_size
+        * leave one page in buffer for name
         */
-       blk_queue_max_segments(dev->blk_queue, 1);
+       max_request_size_bytes = (unsigned int) (dev->config.request_size -1) * ( 1 << dev->config.page_shift) ;
+       blk_queue_max_hw_sectors(dev->blk_queue, max_request_size_bytes >> 9);
+       blk_queue_max_segment_size(dev->blk_queue, max_request_size_bytes);
+       blk_queue_io_min(dev->blk_queue, max_request_size_bytes);
+       blk_queue_io_opt(dev->blk_queue, max_request_size_bytes);
+
        queue_flag_set_unlocked(QUEUE_FLAG_NONROT, dev->blk_queue);
 
        /* vkoukis says we don't need partitions */
@@ -506,18 +528,16 @@ static int xsegbd_dev_init(struct xsegbd *dev, int id, sector_t size)
        disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
        snprintf(disk->disk_name, 32, "xsegbd%c", 'a' + id);
 
-       ret = xsegbd_xseg_init(dev);
-       if (ret < 0)
-               goto out_free_disk;
 
        if (!xq_alloc_seq(&dev->blk_queue_pending, nr_requests, nr_requests))
-               goto out_quit;
+               goto out_free_disk;
 
        dev->blk_req_pending = kmalloc(sizeof(struct request *) * nr_requests, GFP_KERNEL);
        if (!dev->blk_req_pending)
                goto out_free_pending;
 
-       dev->sectors = xsegbd_get_size(dev) / 512ULL;
+       /* allow a non-zero sector_size parameter to override the disk size */
+       dev->sectors = sector_size ? sector_size : xsegbd_get_size(dev) / 512ULL;
        set_capacity(disk, dev->sectors);
 
        add_disk(disk); /* immediately activates the device */
@@ -528,15 +548,14 @@ out:
 out_free_pending:
        xq_free(&dev->blk_queue_pending);
 
-out_quit:
-       xsegbd_xseg_quit(dev);
-
 out_free_disk:
        put_disk(disk);
 
 out_free_queue:
        blk_cleanup_queue(dev->blk_queue);
 
+free_xseg:
+       xsegbd_xseg_quit(dev);
        goto out;
 }
 
@@ -699,7 +718,9 @@ static void xseg_request_fn(struct request_queue *rq)
 
                BUG_ON(xseg_submit(dev->xseg, dev->dst_portno, xreq) == NoSerial);
        }
-
+       //This is going to happen at least once.
+       //TODO find out why it happens more than once.
+       WARN_ON(xseg_signal(dev->xseg, dev->dst_portno));
        if (xreq)
                xseg_put_request(dev->xseg, dev->src_portno, xreq);
 }