--- /dev/null
+From d4dc210f69bcb0b4bef5a83b1c323817be89bad1 Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Thu, 21 Apr 2011 20:54:46 +0200
+Subject: block: don't block events on excl write for non-optical
+ devices
+
+From: Tejun Heo <tj@kernel.org>
+
+commit d4dc210f69bcb0b4bef5a83b1c323817be89bad1 upstream.
+
+Disk event code automatically blocks events on excl write. This is
+primarily to avoid issuing polling commands while burning is in
+progress. This behavior doesn't fit other types of devices with
+removeable media where polling commands don't have adverse side
+effects and door locking usually doesn't exist.
+
+This patch introduces new genhd flag which controls the auto-blocking
+behavior and uses it to enable auto-blocking only on optical devices.
+
+Note for stable: 2.6.38 and later only
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reported-by: Kay Sievers <kay.sievers@vrfy.org>
+Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/block/paride/pcd.c | 1 +
+ drivers/cdrom/viocd.c | 3 ++-
+ drivers/ide/ide-cd.c | 3 ++-
+ drivers/scsi/sr.c | 2 +-
+ fs/block_dev.c | 17 ++++++++++-------
+ include/linux/genhd.h | 1 +
+ 6 files changed, 17 insertions(+), 10 deletions(-)
+
+--- a/drivers/block/paride/pcd.c
++++ b/drivers/block/paride/pcd.c
+@@ -320,6 +320,7 @@ static void pcd_init_units(void)
+ disk->first_minor = unit;
+ strcpy(disk->disk_name, cd->name); /* umm... */
+ disk->fops = &pcd_bdops;
++ disk->flags = GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
+ }
+ }
+
+--- a/drivers/cdrom/viocd.c
++++ b/drivers/cdrom/viocd.c
+@@ -625,7 +625,8 @@ static int viocd_probe(struct vio_dev *v
+ blk_queue_max_hw_sectors(q, 4096 / 512);
+ gendisk->queue = q;
+ gendisk->fops = &viocd_fops;
+- gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE;
++ gendisk->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE |
++ GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
+ set_capacity(gendisk, 0);
+ gendisk->private_data = d;
+ d->viocd_disk = gendisk;
+--- a/drivers/ide/ide-cd.c
++++ b/drivers/ide/ide-cd.c
+@@ -1773,7 +1773,8 @@ static int ide_cd_probe(ide_drive_t *dri
+
+ g->minors = 1;
+ g->driverfs_dev = &drive->gendev;
+- g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
++ g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE |
++ GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
+ if (ide_cdrom_setup(drive)) {
+ put_device(&info->dev);
+ goto failed;
+--- a/drivers/scsi/sr.c
++++ b/drivers/scsi/sr.c
+@@ -636,7 +636,7 @@ static int sr_probe(struct device *dev)
+ disk->first_minor = minor;
+ sprintf(disk->disk_name, "sr%d", minor);
+ disk->fops = &sr_bdops;
+- disk->flags = GENHD_FL_CD;
++ disk->flags = GENHD_FL_CD | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
+ disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST;
+
+ blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
+--- a/fs/block_dev.c
++++ b/fs/block_dev.c
+@@ -1238,6 +1238,8 @@ int blkdev_get(struct block_device *bdev
+ res = __blkdev_get(bdev, mode, 0);
+
+ if (whole) {
++ struct gendisk *disk = whole->bd_disk;
++
+ /* finish claiming */
+ mutex_lock(&bdev->bd_mutex);
+ spin_lock(&bdev_lock);
+@@ -1264,15 +1266,16 @@ int blkdev_get(struct block_device *bdev
+ spin_unlock(&bdev_lock);
+
+ /*
+- * Block event polling for write claims. Any write
+- * holder makes the write_holder state stick until all
+- * are released. This is good enough and tracking
+- * individual writeable reference is too fragile given
+- * the way @mode is used in blkdev_get/put().
++ * Block event polling for write claims if requested. Any
++ * write holder makes the write_holder state stick until
++ * all are released. This is good enough and tracking
++ * individual writeable reference is too fragile given the
++ * way @mode is used in blkdev_get/put().
+ */
+- if (!res && (mode & FMODE_WRITE) && !bdev->bd_write_holder) {
++ if ((disk->flags & GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE) &&
++ !res && (mode & FMODE_WRITE) && !bdev->bd_write_holder) {
+ bdev->bd_write_holder = true;
+- disk_block_events(bdev->bd_disk);
++ disk_block_events(disk);
+ }
+
+ mutex_unlock(&bdev->bd_mutex);
+--- a/include/linux/genhd.h
++++ b/include/linux/genhd.h
+@@ -127,6 +127,7 @@ struct hd_struct {
+ #define GENHD_FL_SUPPRESS_PARTITION_INFO 32
+ #define GENHD_FL_EXT_DEVT 64 /* allow extended devt */
+ #define GENHD_FL_NATIVE_CAPACITY 128
++#define GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE 256
+
+ enum {
+ DISK_EVENT_MEDIA_CHANGE = 1 << 0, /* media changed */