diff options
-rw-r--r-- | block/genhd.c | 23 | ||||
-rw-r--r-- | include/linux/genhd.h | 1 |
2 files changed, 20 insertions, 4 deletions
diff --git a/block/genhd.c b/block/genhd.c index 2f7feda61e35..d84a7df1e2a0 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -181,6 +181,12 @@ void disk_part_iter_exit(struct disk_part_iter *piter) | |||
181 | } | 181 | } |
182 | EXPORT_SYMBOL_GPL(disk_part_iter_exit); | 182 | EXPORT_SYMBOL_GPL(disk_part_iter_exit); |
183 | 183 | ||
184 | static inline int sector_in_part(struct hd_struct *part, sector_t sector) | ||
185 | { | ||
186 | return part->start_sect <= sector && | ||
187 | sector < part->start_sect + part->nr_sects; | ||
188 | } | ||
189 | |||
184 | /** | 190 | /** |
185 | * disk_map_sector_rcu - map sector to partition | 191 | * disk_map_sector_rcu - map sector to partition |
186 | * @disk: gendisk of interest | 192 | * @disk: gendisk of interest |
@@ -199,16 +205,22 @@ EXPORT_SYMBOL_GPL(disk_part_iter_exit); | |||
199 | struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector) | 205 | struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector) |
200 | { | 206 | { |
201 | struct disk_part_tbl *ptbl; | 207 | struct disk_part_tbl *ptbl; |
208 | struct hd_struct *part; | ||
202 | int i; | 209 | int i; |
203 | 210 | ||
204 | ptbl = rcu_dereference(disk->part_tbl); | 211 | ptbl = rcu_dereference(disk->part_tbl); |
205 | 212 | ||
213 | part = rcu_dereference(ptbl->last_lookup); | ||
214 | if (part && sector_in_part(part, sector)) | ||
215 | return part; | ||
216 | |||
206 | for (i = 1; i < ptbl->len; i++) { | 217 | for (i = 1; i < ptbl->len; i++) { |
207 | struct hd_struct *part = rcu_dereference(ptbl->part[i]); | 218 | part = rcu_dereference(ptbl->part[i]); |
208 | 219 | ||
209 | if (part && part->start_sect <= sector && | 220 | if (part && sector_in_part(part, sector)) { |
210 | sector < part->start_sect + part->nr_sects) | 221 | rcu_assign_pointer(ptbl->last_lookup, part); |
211 | return part; | 222 | return part; |
223 | } | ||
212 | } | 224 | } |
213 | return &disk->part0; | 225 | return &disk->part0; |
214 | } | 226 | } |
@@ -888,8 +900,11 @@ static void disk_replace_part_tbl(struct gendisk *disk, | |||
888 | struct disk_part_tbl *old_ptbl = disk->part_tbl; | 900 | struct disk_part_tbl *old_ptbl = disk->part_tbl; |
889 | 901 | ||
890 | rcu_assign_pointer(disk->part_tbl, new_ptbl); | 902 | rcu_assign_pointer(disk->part_tbl, new_ptbl); |
891 | if (old_ptbl) | 903 | |
904 | if (old_ptbl) { | ||
905 | rcu_assign_pointer(old_ptbl->last_lookup, NULL); | ||
892 | call_rcu(&old_ptbl->rcu_head, disk_free_ptbl_rcu_cb); | 906 | call_rcu(&old_ptbl->rcu_head, disk_free_ptbl_rcu_cb); |
907 | } | ||
893 | } | 908 | } |
894 | 909 | ||
895 | /** | 910 | /** |
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 3df7742ce246..16948eaecae3 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
@@ -126,6 +126,7 @@ struct blk_scsi_cmd_filter { | |||
126 | struct disk_part_tbl { | 126 | struct disk_part_tbl { |
127 | struct rcu_head rcu_head; | 127 | struct rcu_head rcu_head; |
128 | int len; | 128 | int len; |
129 | struct hd_struct *last_lookup; | ||
129 | struct hd_struct *part[]; | 130 | struct hd_struct *part[]; |
130 | }; | 131 | }; |
131 | 132 | ||