Merge branch 'for-2.6.36' of git://git.kernel.dk/linux-2.6-block
[pandora-kernel.git] / drivers / block / virtio_blk.c
index 0a3222f..2aafafc 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
+#include <linux/smp_lock.h>
 #include <linux/hdreg.h>
 #include <linux/virtio.h>
 #include <linux/virtio_blk.h>
@@ -217,22 +218,12 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
        return blk_execute_rq(vblk->disk->queue, vblk->disk, req, false);
 }
 
-static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
+static int virtblk_locked_ioctl(struct block_device *bdev, fmode_t mode,
                         unsigned cmd, unsigned long data)
 {
        struct gendisk *disk = bdev->bd_disk;
        struct virtio_blk *vblk = disk->private_data;
 
-       if (cmd == 0x56424944) { /* 'VBID' */
-               void __user *usr_data = (void __user *)data;
-               char id_str[VIRTIO_BLK_ID_BYTES];
-               int err;
-
-               err = virtblk_get_id(disk, id_str);
-               if (!err && copy_to_user(usr_data, id_str, VIRTIO_BLK_ID_BYTES))
-                       err = -EFAULT;
-               return err;
-       }
        /*
         * Only allow the generic SCSI ioctls if the host can support it.
         */
@@ -243,6 +234,18 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
                              (void __user *)data);
 }
 
+static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
+                            unsigned int cmd, unsigned long param)
+{
+       int ret;
+
+       lock_kernel();
+       ret = virtblk_locked_ioctl(bdev, mode, cmd, param);
+       unlock_kernel();
+
+       return ret;
+}
+
 /* We provide getgeo only to please some old bootloader/partitioning tools */
 static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
 {
@@ -269,7 +272,7 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
 }
 
 static const struct block_device_operations virtblk_fops = {
-       .locked_ioctl = virtblk_ioctl,
+       .ioctl  = virtblk_ioctl,
        .owner  = THIS_MODULE,
        .getgeo = virtblk_getgeo,
 };
@@ -279,6 +282,27 @@ static int index_to_minor(int index)
        return index << PART_BITS;
 }
 
+static ssize_t virtblk_serial_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct gendisk *disk = dev_to_disk(dev);
+       int err;
+
+       /* sysfs gives us a PAGE_SIZE buffer */
+       BUILD_BUG_ON(PAGE_SIZE < VIRTIO_BLK_ID_BYTES);
+
+       buf[VIRTIO_BLK_ID_BYTES] = '\0';
+       err = virtblk_get_id(disk, buf);
+       if (!err)
+               return strlen(buf);
+
+       if (err == -EIO) /* Unsupported? Make it empty. */
+               return 0;
+
+       return err;
+}
+DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL);
+
 static int __devinit virtblk_probe(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk;
@@ -364,11 +388,31 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
        vblk->disk->driverfs_dev = &vdev->dev;
        index++;
 
-       /* If barriers are supported, tell block layer that queue is ordered */
-       if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
+       if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) {
+               /*
+                * If the FLUSH feature is supported we do have support for
+                * flushing a volatile write cache on the host.  Use that
+                * to implement write barrier support.
+                */
                blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH);
-       else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
+       } else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) {
+               /*
+                * If the BARRIER feature is supported the host expects us
+                * to order request by tags.  This implies there is not
+                * volatile write cache on the host, and that the host
+                * never re-orders outstanding I/O.  This feature is not
+                * useful for real life scenarious and deprecated.
+                */
                blk_queue_ordered(q, QUEUE_ORDERED_TAG);
+       } else {
+               /*
+                * If the FLUSH feature is not supported we must assume that
+                * the host does not perform any kind of volatile write
+                * caching. We still need to drain the queue to provider
+                * proper barrier semantics.
+                */
+               blk_queue_ordered(q, QUEUE_ORDERED_DRAIN);
+       }
 
        /* If disk is read-only in the host, the guest should obey */
        if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
@@ -442,8 +486,15 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
 
 
        add_disk(vblk->disk);
+       err = device_create_file(disk_to_dev(vblk->disk), &dev_attr_serial);
+       if (err)
+               goto out_del_disk;
+
        return 0;
 
+out_del_disk:
+       del_gendisk(vblk->disk);
+       blk_cleanup_queue(vblk->disk->queue);
 out_put_disk:
        put_disk(vblk->disk);
 out_mempool: