[glsdk/meta-ti-glsdk.git] / recipes-kernel / linux / linux-ti33x-psp-3.2 / 3.2.12 / 0029-block-Fix-NULL-pointer-dereference-in-sd_revalidate_.patch
1 From f90fbbb22b2a145c5a3d66a31a46a32bb54ed722 Mon Sep 17 00:00:00 2001
2 From: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
3 Date: Fri, 2 Mar 2012 10:38:33 +0100
4 Subject: [PATCH 29/42] block: Fix NULL pointer dereference in
5 sd_revalidate_disk
7 commit fe316bf2d5847bc5dd975668671a7b1067603bc7 upstream.
9 Since 2.6.39 (1196f8b), when a driver returns -ENOMEDIUM for open(),
10 __blkdev_get() calls rescan_partitions() to remove
11 in-kernel partition structures and raise KOBJ_CHANGE uevent.
13 However it ends up calling driver's revalidate_disk without open
14 and could cause oops.
16 In the case of SCSI:
18 process A process B
19 ----------------------------------------------
20 sys_open
21 __blkdev_get
22 sd_open
23 returns -ENOMEDIUM
24 scsi_remove_device
25 <scsi_device torn down>
26 rescan_partitions
27 sd_revalidate_disk
28 <oops>
29 Oopses are reported here:
30 http://marc.info/?l=linux-scsi&m=132388619710052
32 This patch separates the partition invalidation from rescan_partitions()
33 and use it for -ENOMEDIUM case.
35 Reported-by: Huajun Li <huajun.li.lee@gmail.com>
36 Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
37 Acked-by: Tejun Heo <tj@kernel.org>
38 Signed-off-by: Jens Axboe <axboe@kernel.dk>
39 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
40 ---
41 fs/block_dev.c | 16 ++++++++++++----
42 fs/partitions/check.c | 48 ++++++++++++++++++++++++++++++++++++++++--------
43 include/linux/genhd.h | 1 +
44 3 files changed, 53 insertions(+), 12 deletions(-)
46 diff --git a/fs/block_dev.c b/fs/block_dev.c
47 index b07f1da..abe9b48 100644
48 --- a/fs/block_dev.c
49 +++ b/fs/block_dev.c
50 @@ -1159,8 +1159,12 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
51 * The latter is necessary to prevent ghost
52 * partitions on a removed medium.
53 */
54 - if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
55 - rescan_partitions(disk, bdev);
56 + if (bdev->bd_invalidated) {
57 + if (!ret)
58 + rescan_partitions(disk, bdev);
59 + else if (ret == -ENOMEDIUM)
60 + invalidate_partitions(disk, bdev);
61 + }
62 if (ret)
63 goto out_clear;
64 } else {
65 @@ -1190,8 +1194,12 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
66 if (bdev->bd_disk->fops->open)
67 ret = bdev->bd_disk->fops->open(bdev, mode);
68 /* the same as first opener case, read comment there */
69 - if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
70 - rescan_partitions(bdev->bd_disk, bdev);
71 + if (bdev->bd_invalidated) {
72 + if (!ret)
73 + rescan_partitions(bdev->bd_disk, bdev);
74 + else if (ret == -ENOMEDIUM)
75 + invalidate_partitions(bdev->bd_disk, bdev);
76 + }
77 if (ret)
78 goto out_unlock_bdev;
79 }
80 diff --git a/fs/partitions/check.c b/fs/partitions/check.c
81 index e3c63d1..6b5fcc5 100644
82 --- a/fs/partitions/check.c
83 +++ b/fs/partitions/check.c
84 @@ -539,17 +539,11 @@ static bool disk_unlock_native_capacity(struct gendisk *disk)
85 }
86 }
88 -int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
89 +static int drop_partitions(struct gendisk *disk, struct block_device *bdev)
90 {
91 - struct parsed_partitions *state = NULL;
92 struct disk_part_iter piter;
93 struct hd_struct *part;
94 - int p, highest, res;
95 -rescan:
96 - if (state && !IS_ERR(state)) {
97 - kfree(state);
98 - state = NULL;
99 - }
100 + int res;
102 if (bdev->bd_part_count)
103 return -EBUSY;
104 @@ -562,6 +556,24 @@ rescan:
105 delete_partition(disk, part->partno);
106 disk_part_iter_exit(&piter);
108 + return 0;
109 +}
110 +
111 +int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
112 +{
113 + struct parsed_partitions *state = NULL;
114 + struct hd_struct *part;
115 + int p, highest, res;
116 +rescan:
117 + if (state && !IS_ERR(state)) {
118 + kfree(state);
119 + state = NULL;
120 + }
121 +
122 + res = drop_partitions(disk, bdev);
123 + if (res)
124 + return res;
125 +
126 if (disk->fops->revalidate_disk)
127 disk->fops->revalidate_disk(disk);
128 check_disk_size_change(disk, bdev);
129 @@ -665,6 +677,26 @@ rescan:
130 return 0;
131 }
133 +int invalidate_partitions(struct gendisk *disk, struct block_device *bdev)
134 +{
135 + int res;
136 +
137 + if (!bdev->bd_invalidated)
138 + return 0;
139 +
140 + res = drop_partitions(disk, bdev);
141 + if (res)
142 + return res;
143 +
144 + set_capacity(disk, 0);
145 + check_disk_size_change(disk, bdev);
146 + bdev->bd_invalidated = 0;
147 + /* tell userspace that the media / partition table may have changed */
148 + kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
149 +
150 + return 0;
151 +}
152 +
153 unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
154 {
155 struct address_space *mapping = bdev->bd_inode->i_mapping;
156 diff --git a/include/linux/genhd.h b/include/linux/genhd.h
157 index 6d18f35..c6f7f6a 100644
158 --- a/include/linux/genhd.h
159 +++ b/include/linux/genhd.h
160 @@ -596,6 +596,7 @@ extern char *disk_name (struct gendisk *hd, int partno, char *buf);
162 extern int disk_expand_part_tbl(struct gendisk *disk, int target);
163 extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
164 +extern int invalidate_partitions(struct gendisk *disk, struct block_device *bdev);
165 extern struct hd_struct * __must_check add_partition(struct gendisk *disk,
166 int partno, sector_t start,
167 sector_t len, int flags,
168 --
169 1.7.9.4