xen/blkfront: add __exit to module_exit() handlers
[linux-block.git] / drivers / block / xen-blkfront.c
index 8afce67c0aa56293f815f55fb949983082ba2a9d..b00682e5739300d9d28b760de8402a3473eaf480 100644 (file)
@@ -37,6 +37,8 @@
 
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/cdrom.h>
 #include <linux/module.h>
 
 #include <xen/xenbus.h>
@@ -46,6 +48,7 @@
 
 #include <xen/interface/grant_table.h>
 #include <xen/interface/io/blkif.h>
+#include <xen/interface/io/protocols.h>
 
 #include <asm/xen/hypervisor.h>
 
@@ -73,7 +76,6 @@ static struct block_device_operations xlvbd_block_fops;
 struct blkfront_info
 {
        struct xenbus_device *xbdev;
-       dev_t dev;
        struct gendisk *gd;
        int vdevice;
        blkif_vdev_t handle;
@@ -87,6 +89,7 @@ struct blkfront_info
        struct blk_shadow shadow[BLK_RING_SIZE];
        unsigned long shadow_free;
        int feature_barrier;
+       int is_ready;
 
        /**
         * The number of people holding this device open.  We won't allow a
@@ -135,6 +138,56 @@ static void blkif_restart_queue_callback(void *arg)
        schedule_work(&info->work);
 }
 
+static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
+{
+       /* We don't have real geometry info, but let's at least return
+          values consistent with the size of the device */
+       sector_t nsect = get_capacity(bd->bd_disk);
+       sector_t cylinders = nsect;
+
+       hg->heads = 0xff;
+       hg->sectors = 0x3f;
+       sector_div(cylinders, hg->heads * hg->sectors);
+       hg->cylinders = cylinders;
+       if ((sector_t)(hg->cylinders + 1) * hg->heads * hg->sectors < nsect)
+               hg->cylinders = 0xffff;
+       return 0;
+}
+
+int blkif_ioctl(struct inode *inode, struct file *filep,
+               unsigned command, unsigned long argument)
+{
+       struct blkfront_info *info =
+               inode->i_bdev->bd_disk->private_data;
+       int i;
+
+       dev_dbg(&info->xbdev->dev, "command: 0x%x, argument: 0x%lx\n",
+               command, (long)argument);
+
+       switch (command) {
+       case CDROMMULTISESSION:
+               dev_dbg(&info->xbdev->dev, "FIXME: support multisession CDs later\n");
+               for (i = 0; i < sizeof(struct cdrom_multisession); i++)
+                       if (put_user(0, (char __user *)(argument + i)))
+                               return -EFAULT;
+               return 0;
+
+       case CDROM_GET_CAPABILITY: {
+               struct gendisk *gd = info->gd;
+               if (gd->flags & GENHD_FL_CD)
+                       return 0;
+               return -EINVAL;
+       }
+
+       default:
+               /*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n",
+                 command);*/
+               return -EINVAL; /* same return as native Linux */
+       }
+
+       return 0;
+}
+
 /*
  * blkif_queue_request
  *
@@ -306,6 +359,9 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
        /* Make sure buffer addresses are sector-aligned. */
        blk_queue_dma_alignment(rq, 511);
 
+       /* Make sure we don't use bounce buffers. */
+       blk_queue_bounce_limit(rq, BLK_BOUNCE_ANY);
+
        gd->queue = rq;
 
        return 0;
@@ -597,6 +653,12 @@ again:
                message = "writing event-channel";
                goto abort_transaction;
        }
+       err = xenbus_printf(xbt, dev->nodename, "protocol", "%s",
+                           XEN_IO_PROTO_ABI_NATIVE);
+       if (err) {
+               message = "writing protocol";
+               goto abort_transaction;
+       }
 
        err = xenbus_transaction_end(xbt, 0);
        if (err) {
@@ -816,6 +878,8 @@ static void blkfront_connect(struct blkfront_info *info)
        spin_unlock_irq(&blkif_io_lock);
 
        add_disk(info->gd);
+
+       info->is_ready = 1;
 }
 
 /**
@@ -879,7 +943,7 @@ static void backend_changed(struct xenbus_device *dev,
                break;
 
        case XenbusStateClosing:
-               bd = bdget(info->dev);
+               bd = bdget_disk(info->gd, 0);
                if (bd == NULL)
                        xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
 
@@ -908,6 +972,13 @@ static int blkfront_remove(struct xenbus_device *dev)
        return 0;
 }
 
+static int blkfront_is_ready(struct xenbus_device *dev)
+{
+       struct blkfront_info *info = dev->dev.driver_data;
+
+       return info->is_ready;
+}
+
 static int blkif_open(struct inode *inode, struct file *filep)
 {
        struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
@@ -926,7 +997,7 @@ static int blkif_release(struct inode *inode, struct file *filep)
                struct xenbus_device *dev = info->xbdev;
                enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
 
-               if (state == XenbusStateClosing)
+               if (state == XenbusStateClosing && info->is_ready)
                        blkfront_closing(dev);
        }
        return 0;
@@ -937,6 +1008,8 @@ static struct block_device_operations xlvbd_block_fops =
        .owner = THIS_MODULE,
        .open = blkif_open,
        .release = blkif_release,
+       .getgeo = blkif_getgeo,
+       .ioctl = blkif_ioctl,
 };
 
 
@@ -953,6 +1026,7 @@ static struct xenbus_driver blkfront = {
        .remove = blkfront_remove,
        .resume = blkfront_resume,
        .otherend_changed = backend_changed,
+       .is_ready = blkfront_is_ready,
 };
 
 static int __init xlblk_init(void)
@@ -971,7 +1045,7 @@ static int __init xlblk_init(void)
 module_init(xlblk_init);
 
 
-static void xlblk_exit(void)
+static void __exit xlblk_exit(void)
 {
        return xenbus_unregister_driver(&blkfront);
 }
@@ -980,3 +1054,5 @@ module_exit(xlblk_exit);
 MODULE_DESCRIPTION("Xen virtual block device frontend");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_BLOCKDEV_MAJOR(XENVBD_MAJOR);
+MODULE_ALIAS("xen:vbd");
+MODULE_ALIAS("xenblk");