aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block/genhd.c23
-rw-r--r--include/linux/genhd.h1
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}
182EXPORT_SYMBOL_GPL(disk_part_iter_exit); 182EXPORT_SYMBOL_GPL(disk_part_iter_exit);
183 183
184static 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);
199struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector) 205struct 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 {
126struct disk_part_tbl { 126struct 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