diff options
-rw-r--r-- | block/blk-core.c | 26 | ||||
-rw-r--r-- | block/blk-merge.c | 3 | ||||
-rw-r--r-- | block/genhd.c | 1 | ||||
-rw-r--r-- | fs/partitions/check.c | 10 | ||||
-rw-r--r-- | include/linux/blkdev.h | 1 | ||||
-rw-r--r-- | include/linux/genhd.h | 2 |
6 files changed, 36 insertions, 7 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index 3689319a597..500c080a6a6 100644 --- a/block/blk-core.c +++ b/block/blk-core.c | |||
@@ -64,13 +64,27 @@ static void drive_stat_acct(struct request *rq, int new_io) | |||
64 | return; | 64 | return; |
65 | 65 | ||
66 | cpu = part_stat_lock(); | 66 | cpu = part_stat_lock(); |
67 | part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq)); | ||
68 | 67 | ||
69 | if (!new_io) | 68 | if (!new_io) { |
69 | part = rq->part; | ||
70 | part_stat_inc(cpu, part, merges[rw]); | 70 | part_stat_inc(cpu, part, merges[rw]); |
71 | else { | 71 | } else { |
72 | part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq)); | ||
73 | if (!kref_test_and_get(&part->ref)) { | ||
74 | /* | ||
75 | * The partition is already being removed, | ||
76 | * the request will be accounted on the disk only | ||
77 | * | ||
78 | * We take a reference on disk->part0 although that | ||
79 | * partition will never be deleted, so we can treat | ||
80 | * it as any other partition. | ||
81 | */ | ||
82 | part = &rq->rq_disk->part0; | ||
83 | kref_get(&part->ref); | ||
84 | } | ||
72 | part_round_stats(cpu, part); | 85 | part_round_stats(cpu, part); |
73 | part_inc_in_flight(part, rw); | 86 | part_inc_in_flight(part, rw); |
87 | rq->part = part; | ||
74 | } | 88 | } |
75 | 89 | ||
76 | part_stat_unlock(); | 90 | part_stat_unlock(); |
@@ -128,6 +142,7 @@ void blk_rq_init(struct request_queue *q, struct request *rq) | |||
128 | rq->ref_count = 1; | 142 | rq->ref_count = 1; |
129 | rq->start_time = jiffies; | 143 | rq->start_time = jiffies; |
130 | set_start_time_ns(rq); | 144 | set_start_time_ns(rq); |
145 | rq->part = NULL; | ||
131 | } | 146 | } |
132 | EXPORT_SYMBOL(blk_rq_init); | 147 | EXPORT_SYMBOL(blk_rq_init); |
133 | 148 | ||
@@ -1776,7 +1791,7 @@ static void blk_account_io_completion(struct request *req, unsigned int bytes) | |||
1776 | int cpu; | 1791 | int cpu; |
1777 | 1792 | ||
1778 | cpu = part_stat_lock(); | 1793 | cpu = part_stat_lock(); |
1779 | part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); | 1794 | part = req->part; |
1780 | part_stat_add(cpu, part, sectors[rw], bytes >> 9); | 1795 | part_stat_add(cpu, part, sectors[rw], bytes >> 9); |
1781 | part_stat_unlock(); | 1796 | part_stat_unlock(); |
1782 | } | 1797 | } |
@@ -1796,13 +1811,14 @@ static void blk_account_io_done(struct request *req) | |||
1796 | int cpu; | 1811 | int cpu; |
1797 | 1812 | ||
1798 | cpu = part_stat_lock(); | 1813 | cpu = part_stat_lock(); |
1799 | part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); | 1814 | part = req->part; |
1800 | 1815 | ||
1801 | part_stat_inc(cpu, part, ios[rw]); | 1816 | part_stat_inc(cpu, part, ios[rw]); |
1802 | part_stat_add(cpu, part, ticks[rw], duration); | 1817 | part_stat_add(cpu, part, ticks[rw], duration); |
1803 | part_round_stats(cpu, part); | 1818 | part_round_stats(cpu, part); |
1804 | part_dec_in_flight(part, rw); | 1819 | part_dec_in_flight(part, rw); |
1805 | 1820 | ||
1821 | kref_put(&part->ref, __delete_partition); | ||
1806 | part_stat_unlock(); | 1822 | part_stat_unlock(); |
1807 | } | 1823 | } |
1808 | } | 1824 | } |
diff --git a/block/blk-merge.c b/block/blk-merge.c index 77b7c26df6b..b06b83b89d8 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c | |||
@@ -351,11 +351,12 @@ static void blk_account_io_merge(struct request *req) | |||
351 | int cpu; | 351 | int cpu; |
352 | 352 | ||
353 | cpu = part_stat_lock(); | 353 | cpu = part_stat_lock(); |
354 | part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); | 354 | part = req->part; |
355 | 355 | ||
356 | part_round_stats(cpu, part); | 356 | part_round_stats(cpu, part); |
357 | part_dec_in_flight(part, rq_data_dir(req)); | 357 | part_dec_in_flight(part, rq_data_dir(req)); |
358 | 358 | ||
359 | kref_put(&part->ref, __delete_partition); | ||
359 | part_stat_unlock(); | 360 | part_stat_unlock(); |
360 | } | 361 | } |
361 | } | 362 | } |
diff --git a/block/genhd.c b/block/genhd.c index 16ccc0d2d5d..85c15059883 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -1192,6 +1192,7 @@ struct gendisk *alloc_disk_node(int minors, int node_id) | |||
1192 | return NULL; | 1192 | return NULL; |
1193 | } | 1193 | } |
1194 | disk->part_tbl->part[0] = &disk->part0; | 1194 | disk->part_tbl->part[0] = &disk->part0; |
1195 | kref_init(&disk->part0.ref); | ||
1195 | 1196 | ||
1196 | disk->minors = minors; | 1197 | disk->minors = minors; |
1197 | rand_initialize_disk(disk); | 1198 | rand_initialize_disk(disk); |
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index bdf8d3cc95a..48209f58522 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -381,6 +381,13 @@ static void delete_partition_rcu_cb(struct rcu_head *head) | |||
381 | put_device(part_to_dev(part)); | 381 | put_device(part_to_dev(part)); |
382 | } | 382 | } |
383 | 383 | ||
384 | void __delete_partition(struct kref *ref) | ||
385 | { | ||
386 | struct hd_struct *part = container_of(ref, struct hd_struct, ref); | ||
387 | |||
388 | call_rcu(&part->rcu_head, delete_partition_rcu_cb); | ||
389 | } | ||
390 | |||
384 | void delete_partition(struct gendisk *disk, int partno) | 391 | void delete_partition(struct gendisk *disk, int partno) |
385 | { | 392 | { |
386 | struct disk_part_tbl *ptbl = disk->part_tbl; | 393 | struct disk_part_tbl *ptbl = disk->part_tbl; |
@@ -399,7 +406,7 @@ void delete_partition(struct gendisk *disk, int partno) | |||
399 | kobject_put(part->holder_dir); | 406 | kobject_put(part->holder_dir); |
400 | device_del(part_to_dev(part)); | 407 | device_del(part_to_dev(part)); |
401 | 408 | ||
402 | call_rcu(&part->rcu_head, delete_partition_rcu_cb); | 409 | kref_put(&part->ref, __delete_partition); |
403 | } | 410 | } |
404 | 411 | ||
405 | static ssize_t whole_disk_show(struct device *dev, | 412 | static ssize_t whole_disk_show(struct device *dev, |
@@ -498,6 +505,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, | |||
498 | if (!dev_get_uevent_suppress(ddev)) | 505 | if (!dev_get_uevent_suppress(ddev)) |
499 | kobject_uevent(&pdev->kobj, KOBJ_ADD); | 506 | kobject_uevent(&pdev->kobj, KOBJ_ADD); |
500 | 507 | ||
508 | kref_init(&p->ref); | ||
501 | return p; | 509 | return p; |
502 | 510 | ||
503 | out_free_info: | 511 | out_free_info: |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index aae86fd10c4..482a7fd4883 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -115,6 +115,7 @@ struct request { | |||
115 | void *elevator_private3; | 115 | void *elevator_private3; |
116 | 116 | ||
117 | struct gendisk *rq_disk; | 117 | struct gendisk *rq_disk; |
118 | struct hd_struct *part; | ||
118 | unsigned long start_time; | 119 | unsigned long start_time; |
119 | #ifdef CONFIG_BLK_CGROUP | 120 | #ifdef CONFIG_BLK_CGROUP |
120 | unsigned long long start_time_ns; | 121 | unsigned long long start_time_ns; |
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 7a7b9c1644e..2ba2792a3dd 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
@@ -116,6 +116,7 @@ struct hd_struct { | |||
116 | struct disk_stats dkstats; | 116 | struct disk_stats dkstats; |
117 | #endif | 117 | #endif |
118 | struct rcu_head rcu_head; | 118 | struct rcu_head rcu_head; |
119 | struct kref ref; | ||
119 | }; | 120 | }; |
120 | 121 | ||
121 | #define GENHD_FL_REMOVABLE 1 | 122 | #define GENHD_FL_REMOVABLE 1 |
@@ -583,6 +584,7 @@ extern struct hd_struct * __must_check add_partition(struct gendisk *disk, | |||
583 | sector_t len, int flags, | 584 | sector_t len, int flags, |
584 | struct partition_meta_info | 585 | struct partition_meta_info |
585 | *info); | 586 | *info); |
587 | extern void __delete_partition(struct kref *ref); | ||
586 | extern void delete_partition(struct gendisk *, int); | 588 | extern void delete_partition(struct gendisk *, int); |
587 | extern void printk_all_partitions(void); | 589 | extern void printk_all_partitions(void); |
588 | 590 | ||