--- /dev/null
+From fe316bf2d5847bc5dd975668671a7b1067603bc7 Mon Sep 17 00:00:00 2001
+From: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
+Date: Fri, 2 Mar 2012 10:38:33 +0100
+Subject: block: Fix NULL pointer dereference in sd_revalidate_disk
+
+From: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
+
+commit fe316bf2d5847bc5dd975668671a7b1067603bc7 upstream.
+
+Since 2.6.39 (1196f8b), when a driver returns -ENOMEDIUM for open(),
+__blkdev_get() calls rescan_partitions() to remove
+in-kernel partition structures and raise KOBJ_CHANGE uevent.
+
+However it ends up calling driver's revalidate_disk without open
+and could cause oops.
+
+In the case of SCSI:
+
+ process A process B
+ ----------------------------------------------
+ sys_open
+ __blkdev_get
+ sd_open
+ returns -ENOMEDIUM
+ scsi_remove_device
+ <scsi_device torn down>
+ rescan_partitions
+ sd_revalidate_disk
+ <oops>
+Oopses are reported here:
+http://marc.info/?l=linux-scsi&m=132388619710052
+
+This patch separates the partition invalidation from rescan_partitions()
+and use it for -ENOMEDIUM case.
+
+Reported-by: Huajun Li <huajun.li.lee@gmail.com>
+Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
+Acked-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/block_dev.c | 16 ++++++++++++----
+ fs/partitions/check.c | 48 ++++++++++++++++++++++++++++++++++++++++--------
+ include/linux/genhd.h | 1 +
+ 3 files changed, 53 insertions(+), 12 deletions(-)
+
+--- a/fs/block_dev.c
++++ b/fs/block_dev.c
+@@ -1159,8 +1159,12 @@ static int __blkdev_get(struct block_dev
+ * The latter is necessary to prevent ghost
+ * partitions on a removed medium.
+ */
+- if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
+- rescan_partitions(disk, bdev);
++ if (bdev->bd_invalidated) {
++ if (!ret)
++ rescan_partitions(disk, bdev);
++ else if (ret == -ENOMEDIUM)
++ invalidate_partitions(disk, bdev);
++ }
+ if (ret)
+ goto out_clear;
+ } else {
+@@ -1190,8 +1194,12 @@ static int __blkdev_get(struct block_dev
+ if (bdev->bd_disk->fops->open)
+ ret = bdev->bd_disk->fops->open(bdev, mode);
+ /* the same as first opener case, read comment there */
+- if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
+- rescan_partitions(bdev->bd_disk, bdev);
++ if (bdev->bd_invalidated) {
++ if (!ret)
++ rescan_partitions(bdev->bd_disk, bdev);
++ else if (ret == -ENOMEDIUM)
++ invalidate_partitions(bdev->bd_disk, bdev);
++ }
+ if (ret)
+ goto out_unlock_bdev;
+ }
+--- a/fs/partitions/check.c
++++ b/fs/partitions/check.c
+@@ -539,17 +539,11 @@ static bool disk_unlock_native_capacity(
+ }
+ }
+
+-int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
++static int drop_partitions(struct gendisk *disk, struct block_device *bdev)
+ {
+- struct parsed_partitions *state = NULL;
+ struct disk_part_iter piter;
+ struct hd_struct *part;
+- int p, highest, res;
+-rescan:
+- if (state && !IS_ERR(state)) {
+- kfree(state);
+- state = NULL;
+- }
++ int res;
+
+ if (bdev->bd_part_count)
+ return -EBUSY;
+@@ -562,6 +556,24 @@ rescan:
+ delete_partition(disk, part->partno);
+ disk_part_iter_exit(&piter);
+
++ return 0;
++}
++
++int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
++{
++ struct parsed_partitions *state = NULL;
++ struct hd_struct *part;
++ int p, highest, res;
++rescan:
++ if (state && !IS_ERR(state)) {
++ kfree(state);
++ state = NULL;
++ }
++
++ res = drop_partitions(disk, bdev);
++ if (res)
++ return res;
++
+ if (disk->fops->revalidate_disk)
+ disk->fops->revalidate_disk(disk);
+ check_disk_size_change(disk, bdev);
+@@ -665,6 +677,26 @@ rescan:
+ return 0;
+ }
+
++int invalidate_partitions(struct gendisk *disk, struct block_device *bdev)
++{
++ int res;
++
++ if (!bdev->bd_invalidated)
++ return 0;
++
++ res = drop_partitions(disk, bdev);
++ if (res)
++ return res;
++
++ set_capacity(disk, 0);
++ check_disk_size_change(disk, bdev);
++ bdev->bd_invalidated = 0;
++ /* tell userspace that the media / partition table may have changed */
++ kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
++
++ return 0;
++}
++
+ unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
+ {
+ struct address_space *mapping = bdev->bd_inode->i_mapping;
+--- a/include/linux/genhd.h
++++ b/include/linux/genhd.h
+@@ -596,6 +596,7 @@ extern char *disk_name (struct gendisk *
+
+ extern int disk_expand_part_tbl(struct gendisk *disk, int target);
+ extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
++extern int invalidate_partitions(struct gendisk *disk, struct block_device *bdev);
+ extern struct hd_struct * __must_check add_partition(struct gendisk *disk,
+ int partno, sector_t start,
+ sector_t len, int flags,
--- /dev/null
+From ea5f4db8ece896c2ab9eafa0924148a2596c52e4 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Sat, 3 Mar 2012 12:09:17 +0100
+Subject: block, sx8: fix pointer math issue getting fw version
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit ea5f4db8ece896c2ab9eafa0924148a2596c52e4 upstream.
+
+"mem" is type u8. We need parenthesis here or it screws up the pointer
+math probably leading to an oops.
+
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Acked-by: Jeff Garzik <jgarzik@redhat.com>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/sx8.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/block/sx8.c
++++ b/drivers/block/sx8.c
+@@ -1116,7 +1116,7 @@ static inline void carm_handle_resp(stru
+ break;
+ case MISC_GET_FW_VER: {
+ struct carm_fw_ver *ver = (struct carm_fw_ver *)
+- mem + sizeof(struct carm_msg_get_fw_ver);
++ (mem + sizeof(struct carm_msg_get_fw_ver));
+ if (!error) {
+ host->fw_ver = le32_to_cpu(ver->version);
+ host->flags |= (ver->features & FL_FW_VER_MASK);
--- /dev/null
+From f03570cf1709397ebe656608266b44ec772960c2 Mon Sep 17 00:00:00 2001
+From: Axel Lin <axel.lin@gmail.com>
+Date: Thu, 8 Mar 2012 10:02:17 +0800
+Subject: regulator: Fix setting selector in tps6524x set_voltage function
+
+From: Axel Lin <axel.lin@gmail.com>
+
+commit f03570cf1709397ebe656608266b44ec772960c2 upstream.
+
+Don't assign the voltage to selector.
+
+Signed-off-by: Axel Lin <axel.lin@gmail.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/regulator/tps6524x-regulator.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/regulator/tps6524x-regulator.c
++++ b/drivers/regulator/tps6524x-regulator.c
+@@ -481,7 +481,7 @@ static int set_voltage(struct regulator_
+ if (i >= info->n_voltages)
+ i = info->n_voltages - 1;
+
+- *selector = info->voltages[i];
++ *selector = i;
+
+ return write_field(hw, &info->voltage, i);
+ }