diff options
-rw-r--r-- | block/blk-core.c | 30 | ||||
-rw-r--r-- | block/blk-ioc.c | 5 | ||||
-rw-r--r-- | block/blk-merge.c | 3 | ||||
-rw-r--r-- | block/cfq-iosched.c | 56 | ||||
-rw-r--r-- | block/genhd.c | 6 | ||||
-rw-r--r-- | drivers/block/loop.c | 6 | ||||
-rw-r--r-- | drivers/md/dm.c | 2 | ||||
-rw-r--r-- | fs/bio-integrity.c | 7 | ||||
-rw-r--r-- | fs/char_dev.c | 2 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 5 | ||||
-rw-r--r-- | fs/partitions/check.c | 8 | ||||
-rw-r--r-- | fs/splice.c | 43 | ||||
-rw-r--r-- | include/linux/blkdev.h | 1 | ||||
-rw-r--r-- | include/linux/genhd.h | 25 | ||||
-rw-r--r-- | include/trace/events/block.h | 6 | ||||
-rw-r--r-- | kernel/trace/blktrace.c | 25 |
16 files changed, 135 insertions, 95 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index 151070541e21..2f4002f79a24 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 (!hd_struct_try_get(part)) { | ||
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 | hd_struct_get(part); | ||
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 | hd_struct_put(part); | ||
1806 | part_stat_unlock(); | 1822 | part_stat_unlock(); |
1807 | } | 1823 | } |
1808 | } | 1824 | } |
@@ -2606,7 +2622,9 @@ int __init blk_dev_init(void) | |||
2606 | BUILD_BUG_ON(__REQ_NR_BITS > 8 * | 2622 | BUILD_BUG_ON(__REQ_NR_BITS > 8 * |
2607 | sizeof(((struct request *)0)->cmd_flags)); | 2623 | sizeof(((struct request *)0)->cmd_flags)); |
2608 | 2624 | ||
2609 | kblockd_workqueue = create_workqueue("kblockd"); | 2625 | /* used for unplugging and affects IO latency/throughput - HIGHPRI */ |
2626 | kblockd_workqueue = alloc_workqueue("kblockd", | ||
2627 | WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); | ||
2610 | if (!kblockd_workqueue) | 2628 | if (!kblockd_workqueue) |
2611 | panic("Failed to create kblockd\n"); | 2629 | panic("Failed to create kblockd\n"); |
2612 | 2630 | ||
diff --git a/block/blk-ioc.c b/block/blk-ioc.c index 3c7a339fe381..b791022beef3 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c | |||
@@ -64,7 +64,7 @@ static void cfq_exit(struct io_context *ioc) | |||
64 | rcu_read_unlock(); | 64 | rcu_read_unlock(); |
65 | } | 65 | } |
66 | 66 | ||
67 | /* Called by the exitting task */ | 67 | /* Called by the exiting task */ |
68 | void exit_io_context(struct task_struct *task) | 68 | void exit_io_context(struct task_struct *task) |
69 | { | 69 | { |
70 | struct io_context *ioc; | 70 | struct io_context *ioc; |
@@ -74,10 +74,9 @@ void exit_io_context(struct task_struct *task) | |||
74 | task->io_context = NULL; | 74 | task->io_context = NULL; |
75 | task_unlock(task); | 75 | task_unlock(task); |
76 | 76 | ||
77 | if (atomic_dec_and_test(&ioc->nr_tasks)) { | 77 | if (atomic_dec_and_test(&ioc->nr_tasks)) |
78 | cfq_exit(ioc); | 78 | cfq_exit(ioc); |
79 | 79 | ||
80 | } | ||
81 | put_io_context(ioc); | 80 | put_io_context(ioc); |
82 | } | 81 | } |
83 | 82 | ||
diff --git a/block/blk-merge.c b/block/blk-merge.c index 77b7c26df6b5..00b7d31b38a2 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 | hd_struct_put(part); | ||
359 | part_stat_unlock(); | 360 | part_stat_unlock(); |
360 | } | 361 | } |
361 | } | 362 | } |
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 9b186fd6bf47..f083bda30546 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -96,7 +96,7 @@ struct cfq_rb_root { | |||
96 | */ | 96 | */ |
97 | struct cfq_queue { | 97 | struct cfq_queue { |
98 | /* reference count */ | 98 | /* reference count */ |
99 | atomic_t ref; | 99 | int ref; |
100 | /* various state flags, see below */ | 100 | /* various state flags, see below */ |
101 | unsigned int flags; | 101 | unsigned int flags; |
102 | /* parent cfq_data */ | 102 | /* parent cfq_data */ |
@@ -207,7 +207,7 @@ struct cfq_group { | |||
207 | struct blkio_group blkg; | 207 | struct blkio_group blkg; |
208 | #ifdef CONFIG_CFQ_GROUP_IOSCHED | 208 | #ifdef CONFIG_CFQ_GROUP_IOSCHED |
209 | struct hlist_node cfqd_node; | 209 | struct hlist_node cfqd_node; |
210 | atomic_t ref; | 210 | int ref; |
211 | #endif | 211 | #endif |
212 | /* number of requests that are on the dispatch list or inside driver */ | 212 | /* number of requests that are on the dispatch list or inside driver */ |
213 | int dispatched; | 213 | int dispatched; |
@@ -1014,7 +1014,7 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create) | |||
1014 | * elevator which will be dropped by either elevator exit | 1014 | * elevator which will be dropped by either elevator exit |
1015 | * or cgroup deletion path depending on who is exiting first. | 1015 | * or cgroup deletion path depending on who is exiting first. |
1016 | */ | 1016 | */ |
1017 | atomic_set(&cfqg->ref, 1); | 1017 | cfqg->ref = 1; |
1018 | 1018 | ||
1019 | /* | 1019 | /* |
1020 | * Add group onto cgroup list. It might happen that bdi->dev is | 1020 | * Add group onto cgroup list. It might happen that bdi->dev is |
@@ -1059,7 +1059,7 @@ static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create) | |||
1059 | 1059 | ||
1060 | static inline struct cfq_group *cfq_ref_get_cfqg(struct cfq_group *cfqg) | 1060 | static inline struct cfq_group *cfq_ref_get_cfqg(struct cfq_group *cfqg) |
1061 | { | 1061 | { |
1062 | atomic_inc(&cfqg->ref); | 1062 | cfqg->ref++; |
1063 | return cfqg; | 1063 | return cfqg; |
1064 | } | 1064 | } |
1065 | 1065 | ||
@@ -1071,7 +1071,7 @@ static void cfq_link_cfqq_cfqg(struct cfq_queue *cfqq, struct cfq_group *cfqg) | |||
1071 | 1071 | ||
1072 | cfqq->cfqg = cfqg; | 1072 | cfqq->cfqg = cfqg; |
1073 | /* cfqq reference on cfqg */ | 1073 | /* cfqq reference on cfqg */ |
1074 | atomic_inc(&cfqq->cfqg->ref); | 1074 | cfqq->cfqg->ref++; |
1075 | } | 1075 | } |
1076 | 1076 | ||
1077 | static void cfq_put_cfqg(struct cfq_group *cfqg) | 1077 | static void cfq_put_cfqg(struct cfq_group *cfqg) |
@@ -1079,8 +1079,9 @@ static void cfq_put_cfqg(struct cfq_group *cfqg) | |||
1079 | struct cfq_rb_root *st; | 1079 | struct cfq_rb_root *st; |
1080 | int i, j; | 1080 | int i, j; |
1081 | 1081 | ||
1082 | BUG_ON(atomic_read(&cfqg->ref) <= 0); | 1082 | BUG_ON(cfqg->ref <= 0); |
1083 | if (!atomic_dec_and_test(&cfqg->ref)) | 1083 | cfqg->ref--; |
1084 | if (cfqg->ref) | ||
1084 | return; | 1085 | return; |
1085 | for_each_cfqg_st(cfqg, i, j, st) | 1086 | for_each_cfqg_st(cfqg, i, j, st) |
1086 | BUG_ON(!RB_EMPTY_ROOT(&st->rb)); | 1087 | BUG_ON(!RB_EMPTY_ROOT(&st->rb)); |
@@ -1188,7 +1189,7 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1188 | cfq_group_service_tree_del(cfqd, cfqq->cfqg); | 1189 | cfq_group_service_tree_del(cfqd, cfqq->cfqg); |
1189 | cfqq->orig_cfqg = cfqq->cfqg; | 1190 | cfqq->orig_cfqg = cfqq->cfqg; |
1190 | cfqq->cfqg = &cfqd->root_group; | 1191 | cfqq->cfqg = &cfqd->root_group; |
1191 | atomic_inc(&cfqd->root_group.ref); | 1192 | cfqd->root_group.ref++; |
1192 | group_changed = 1; | 1193 | group_changed = 1; |
1193 | } else if (!cfqd->cfq_group_isolation | 1194 | } else if (!cfqd->cfq_group_isolation |
1194 | && cfqq_type(cfqq) == SYNC_WORKLOAD && cfqq->orig_cfqg) { | 1195 | && cfqq_type(cfqq) == SYNC_WORKLOAD && cfqq->orig_cfqg) { |
@@ -2025,7 +2026,7 @@ static int cfqq_process_refs(struct cfq_queue *cfqq) | |||
2025 | int process_refs, io_refs; | 2026 | int process_refs, io_refs; |
2026 | 2027 | ||
2027 | io_refs = cfqq->allocated[READ] + cfqq->allocated[WRITE]; | 2028 | io_refs = cfqq->allocated[READ] + cfqq->allocated[WRITE]; |
2028 | process_refs = atomic_read(&cfqq->ref) - io_refs; | 2029 | process_refs = cfqq->ref - io_refs; |
2029 | BUG_ON(process_refs < 0); | 2030 | BUG_ON(process_refs < 0); |
2030 | return process_refs; | 2031 | return process_refs; |
2031 | } | 2032 | } |
@@ -2065,10 +2066,10 @@ static void cfq_setup_merge(struct cfq_queue *cfqq, struct cfq_queue *new_cfqq) | |||
2065 | */ | 2066 | */ |
2066 | if (new_process_refs >= process_refs) { | 2067 | if (new_process_refs >= process_refs) { |
2067 | cfqq->new_cfqq = new_cfqq; | 2068 | cfqq->new_cfqq = new_cfqq; |
2068 | atomic_add(process_refs, &new_cfqq->ref); | 2069 | new_cfqq->ref += process_refs; |
2069 | } else { | 2070 | } else { |
2070 | new_cfqq->new_cfqq = cfqq; | 2071 | new_cfqq->new_cfqq = cfqq; |
2071 | atomic_add(new_process_refs, &cfqq->ref); | 2072 | cfqq->ref += new_process_refs; |
2072 | } | 2073 | } |
2073 | } | 2074 | } |
2074 | 2075 | ||
@@ -2103,12 +2104,6 @@ static void choose_service_tree(struct cfq_data *cfqd, struct cfq_group *cfqg) | |||
2103 | unsigned group_slice; | 2104 | unsigned group_slice; |
2104 | enum wl_prio_t original_prio = cfqd->serving_prio; | 2105 | enum wl_prio_t original_prio = cfqd->serving_prio; |
2105 | 2106 | ||
2106 | if (!cfqg) { | ||
2107 | cfqd->serving_prio = IDLE_WORKLOAD; | ||
2108 | cfqd->workload_expires = jiffies + 1; | ||
2109 | return; | ||
2110 | } | ||
2111 | |||
2112 | /* Choose next priority. RT > BE > IDLE */ | 2107 | /* Choose next priority. RT > BE > IDLE */ |
2113 | if (cfq_group_busy_queues_wl(RT_WORKLOAD, cfqd, cfqg)) | 2108 | if (cfq_group_busy_queues_wl(RT_WORKLOAD, cfqd, cfqg)) |
2114 | cfqd->serving_prio = RT_WORKLOAD; | 2109 | cfqd->serving_prio = RT_WORKLOAD; |
@@ -2538,9 +2533,10 @@ static void cfq_put_queue(struct cfq_queue *cfqq) | |||
2538 | struct cfq_data *cfqd = cfqq->cfqd; | 2533 | struct cfq_data *cfqd = cfqq->cfqd; |
2539 | struct cfq_group *cfqg, *orig_cfqg; | 2534 | struct cfq_group *cfqg, *orig_cfqg; |
2540 | 2535 | ||
2541 | BUG_ON(atomic_read(&cfqq->ref) <= 0); | 2536 | BUG_ON(cfqq->ref <= 0); |
2542 | 2537 | ||
2543 | if (!atomic_dec_and_test(&cfqq->ref)) | 2538 | cfqq->ref--; |
2539 | if (cfqq->ref) | ||
2544 | return; | 2540 | return; |
2545 | 2541 | ||
2546 | cfq_log_cfqq(cfqd, cfqq, "put_queue"); | 2542 | cfq_log_cfqq(cfqd, cfqq, "put_queue"); |
@@ -2843,7 +2839,7 @@ static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
2843 | RB_CLEAR_NODE(&cfqq->p_node); | 2839 | RB_CLEAR_NODE(&cfqq->p_node); |
2844 | INIT_LIST_HEAD(&cfqq->fifo); | 2840 | INIT_LIST_HEAD(&cfqq->fifo); |
2845 | 2841 | ||
2846 | atomic_set(&cfqq->ref, 0); | 2842 | cfqq->ref = 0; |
2847 | cfqq->cfqd = cfqd; | 2843 | cfqq->cfqd = cfqd; |
2848 | 2844 | ||
2849 | cfq_mark_cfqq_prio_changed(cfqq); | 2845 | cfq_mark_cfqq_prio_changed(cfqq); |
@@ -2979,11 +2975,11 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct io_context *ioc, | |||
2979 | * pin the queue now that it's allocated, scheduler exit will prune it | 2975 | * pin the queue now that it's allocated, scheduler exit will prune it |
2980 | */ | 2976 | */ |
2981 | if (!is_sync && !(*async_cfqq)) { | 2977 | if (!is_sync && !(*async_cfqq)) { |
2982 | atomic_inc(&cfqq->ref); | 2978 | cfqq->ref++; |
2983 | *async_cfqq = cfqq; | 2979 | *async_cfqq = cfqq; |
2984 | } | 2980 | } |
2985 | 2981 | ||
2986 | atomic_inc(&cfqq->ref); | 2982 | cfqq->ref++; |
2987 | return cfqq; | 2983 | return cfqq; |
2988 | } | 2984 | } |
2989 | 2985 | ||
@@ -3685,13 +3681,13 @@ new_queue: | |||
3685 | } | 3681 | } |
3686 | 3682 | ||
3687 | cfqq->allocated[rw]++; | 3683 | cfqq->allocated[rw]++; |
3688 | atomic_inc(&cfqq->ref); | 3684 | cfqq->ref++; |
3689 | |||
3690 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
3691 | |||
3692 | rq->elevator_private = cic; | 3685 | rq->elevator_private = cic; |
3693 | rq->elevator_private2 = cfqq; | 3686 | rq->elevator_private2 = cfqq; |
3694 | rq->elevator_private3 = cfq_ref_get_cfqg(cfqq->cfqg); | 3687 | rq->elevator_private3 = cfq_ref_get_cfqg(cfqq->cfqg); |
3688 | |||
3689 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
3690 | |||
3695 | return 0; | 3691 | return 0; |
3696 | 3692 | ||
3697 | queue_fail: | 3693 | queue_fail: |
@@ -3866,6 +3862,10 @@ static void *cfq_init_queue(struct request_queue *q) | |||
3866 | if (!cfqd) | 3862 | if (!cfqd) |
3867 | return NULL; | 3863 | return NULL; |
3868 | 3864 | ||
3865 | /* | ||
3866 | * Don't need take queue_lock in the routine, since we are | ||
3867 | * initializing the ioscheduler, and nobody is using cfqd | ||
3868 | */ | ||
3869 | cfqd->cic_index = i; | 3869 | cfqd->cic_index = i; |
3870 | 3870 | ||
3871 | /* Init root service tree */ | 3871 | /* Init root service tree */ |
@@ -3885,7 +3885,7 @@ static void *cfq_init_queue(struct request_queue *q) | |||
3885 | * Take a reference to root group which we never drop. This is just | 3885 | * Take a reference to root group which we never drop. This is just |
3886 | * to make sure that cfq_put_cfqg() does not try to kfree root group | 3886 | * to make sure that cfq_put_cfqg() does not try to kfree root group |
3887 | */ | 3887 | */ |
3888 | atomic_set(&cfqg->ref, 1); | 3888 | cfqg->ref = 1; |
3889 | rcu_read_lock(); | 3889 | rcu_read_lock(); |
3890 | cfq_blkiocg_add_blkio_group(&blkio_root_cgroup, &cfqg->blkg, | 3890 | cfq_blkiocg_add_blkio_group(&blkio_root_cgroup, &cfqg->blkg, |
3891 | (void *)cfqd, 0); | 3891 | (void *)cfqd, 0); |
@@ -3905,7 +3905,7 @@ static void *cfq_init_queue(struct request_queue *q) | |||
3905 | * will not attempt to free it. | 3905 | * will not attempt to free it. |
3906 | */ | 3906 | */ |
3907 | cfq_init_cfqq(cfqd, &cfqd->oom_cfqq, 1, 0); | 3907 | cfq_init_cfqq(cfqd, &cfqd->oom_cfqq, 1, 0); |
3908 | atomic_inc(&cfqd->oom_cfqq.ref); | 3908 | cfqd->oom_cfqq.ref++; |
3909 | cfq_link_cfqq_cfqg(&cfqd->oom_cfqq, &cfqd->root_group); | 3909 | cfq_link_cfqq_cfqg(&cfqd->oom_cfqq, &cfqd->root_group); |
3910 | 3910 | ||
3911 | INIT_LIST_HEAD(&cfqd->cic_list); | 3911 | INIT_LIST_HEAD(&cfqd->cic_list); |
diff --git a/block/genhd.c b/block/genhd.c index 5465a824d489..6a5b772aa201 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -244,7 +244,7 @@ static struct blk_major_name { | |||
244 | } *major_names[BLKDEV_MAJOR_HASH_SIZE]; | 244 | } *major_names[BLKDEV_MAJOR_HASH_SIZE]; |
245 | 245 | ||
246 | /* index in the above - for now: assume no multimajor ranges */ | 246 | /* index in the above - for now: assume no multimajor ranges */ |
247 | static inline int major_to_index(int major) | 247 | static inline int major_to_index(unsigned major) |
248 | { | 248 | { |
249 | return major % BLKDEV_MAJOR_HASH_SIZE; | 249 | return major % BLKDEV_MAJOR_HASH_SIZE; |
250 | } | 250 | } |
@@ -828,7 +828,7 @@ static void *show_partition_start(struct seq_file *seqf, loff_t *pos) | |||
828 | static void *p; | 828 | static void *p; |
829 | 829 | ||
830 | p = disk_seqf_start(seqf, pos); | 830 | p = disk_seqf_start(seqf, pos); |
831 | if (!IS_ERR(p) && p && !*pos) | 831 | if (!IS_ERR_OR_NULL(p) && !*pos) |
832 | seq_puts(seqf, "major minor #blocks name\n\n"); | 832 | seq_puts(seqf, "major minor #blocks name\n\n"); |
833 | return p; | 833 | return p; |
834 | } | 834 | } |
@@ -1264,6 +1264,8 @@ struct gendisk *alloc_disk_node(int minors, int node_id) | |||
1264 | } | 1264 | } |
1265 | disk->part_tbl->part[0] = &disk->part0; | 1265 | disk->part_tbl->part[0] = &disk->part0; |
1266 | 1266 | ||
1267 | hd_ref_init(&disk->part0); | ||
1268 | |||
1267 | disk->minors = minors; | 1269 | disk->minors = minors; |
1268 | rand_initialize_disk(disk); | 1270 | rand_initialize_disk(disk); |
1269 | disk_to_dev(disk)->class = &block_class; | 1271 | disk_to_dev(disk)->class = &block_class; |
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 7ea0bea2f7e3..44e18c073c44 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
@@ -395,11 +395,7 @@ lo_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
395 | struct loop_device *lo = p->lo; | 395 | struct loop_device *lo = p->lo; |
396 | struct page *page = buf->page; | 396 | struct page *page = buf->page; |
397 | sector_t IV; | 397 | sector_t IV; |
398 | int size, ret; | 398 | int size; |
399 | |||
400 | ret = buf->ops->confirm(pipe, buf); | ||
401 | if (unlikely(ret)) | ||
402 | return ret; | ||
403 | 399 | ||
404 | IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9)) + | 400 | IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9)) + |
405 | (buf->offset >> 9); | 401 | (buf->offset >> 9); |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 0a2b5516bc21..f48a2f359ac4 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -630,7 +630,7 @@ static void dec_pending(struct dm_io *io, int error) | |||
630 | queue_io(md, bio); | 630 | queue_io(md, bio); |
631 | } else { | 631 | } else { |
632 | /* done with normal IO or empty flush */ | 632 | /* done with normal IO or empty flush */ |
633 | trace_block_bio_complete(md->queue, bio); | 633 | trace_block_bio_complete(md->queue, bio, io_error); |
634 | bio_endio(bio, io_error); | 634 | bio_endio(bio, io_error); |
635 | } | 635 | } |
636 | } | 636 | } |
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index 4d0ff5ee27b8..e49cce234c65 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c | |||
@@ -782,7 +782,12 @@ void __init bio_integrity_init(void) | |||
782 | { | 782 | { |
783 | unsigned int i; | 783 | unsigned int i; |
784 | 784 | ||
785 | kintegrityd_wq = create_workqueue("kintegrityd"); | 785 | /* |
786 | * kintegrityd won't block much but may burn a lot of CPU cycles. | ||
787 | * Make it highpri CPU intensive wq with max concurrency of 1. | ||
788 | */ | ||
789 | kintegrityd_wq = alloc_workqueue("kintegrityd", WQ_MEM_RECLAIM | | ||
790 | WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1); | ||
786 | if (!kintegrityd_wq) | 791 | if (!kintegrityd_wq) |
787 | panic("Failed to create kintegrityd\n"); | 792 | panic("Failed to create kintegrityd\n"); |
788 | 793 | ||
diff --git a/fs/char_dev.c b/fs/char_dev.c index e5b9df993b93..143f0207c7eb 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c | |||
@@ -59,7 +59,7 @@ static struct char_device_struct { | |||
59 | } *chrdevs[CHRDEV_MAJOR_HASH_SIZE]; | 59 | } *chrdevs[CHRDEV_MAJOR_HASH_SIZE]; |
60 | 60 | ||
61 | /* index in the above */ | 61 | /* index in the above */ |
62 | static inline int major_to_index(int major) | 62 | static inline int major_to_index(unsigned major) |
63 | { | 63 | { |
64 | return major % CHRDEV_MAJOR_HASH_SIZE; | 64 | return major % CHRDEV_MAJOR_HASH_SIZE; |
65 | } | 65 | } |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 184938fcff04..106ed482f119 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -845,11 +845,6 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
845 | struct page **pp = rqstp->rq_respages + rqstp->rq_resused; | 845 | struct page **pp = rqstp->rq_respages + rqstp->rq_resused; |
846 | struct page *page = buf->page; | 846 | struct page *page = buf->page; |
847 | size_t size; | 847 | size_t size; |
848 | int ret; | ||
849 | |||
850 | ret = buf->ops->confirm(pipe, buf); | ||
851 | if (unlikely(ret)) | ||
852 | return ret; | ||
853 | 848 | ||
854 | size = sd->len; | 849 | size = sd->len; |
855 | 850 | ||
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 9a48d65d9855..9c21119512b9 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -381,6 +381,11 @@ 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 hd_struct *part) | ||
385 | { | ||
386 | call_rcu(&part->rcu_head, delete_partition_rcu_cb); | ||
387 | } | ||
388 | |||
384 | void delete_partition(struct gendisk *disk, int partno) | 389 | void delete_partition(struct gendisk *disk, int partno) |
385 | { | 390 | { |
386 | struct disk_part_tbl *ptbl = disk->part_tbl; | 391 | struct disk_part_tbl *ptbl = disk->part_tbl; |
@@ -399,7 +404,7 @@ void delete_partition(struct gendisk *disk, int partno) | |||
399 | kobject_put(part->holder_dir); | 404 | kobject_put(part->holder_dir); |
400 | device_del(part_to_dev(part)); | 405 | device_del(part_to_dev(part)); |
401 | 406 | ||
402 | call_rcu(&part->rcu_head, delete_partition_rcu_cb); | 407 | hd_struct_put(part); |
403 | } | 408 | } |
404 | 409 | ||
405 | static ssize_t whole_disk_show(struct device *dev, | 410 | static ssize_t whole_disk_show(struct device *dev, |
@@ -498,6 +503,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, | |||
498 | if (!dev_get_uevent_suppress(ddev)) | 503 | if (!dev_get_uevent_suppress(ddev)) |
499 | kobject_uevent(&pdev->kobj, KOBJ_ADD); | 504 | kobject_uevent(&pdev->kobj, KOBJ_ADD); |
500 | 505 | ||
506 | hd_ref_init(p); | ||
501 | return p; | 507 | return p; |
502 | 508 | ||
503 | out_free_info: | 509 | out_free_info: |
diff --git a/fs/splice.c b/fs/splice.c index 8f1dfaecc8f0..d2026382ac3e 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -682,19 +682,14 @@ static int pipe_to_sendpage(struct pipe_inode_info *pipe, | |||
682 | { | 682 | { |
683 | struct file *file = sd->u.file; | 683 | struct file *file = sd->u.file; |
684 | loff_t pos = sd->pos; | 684 | loff_t pos = sd->pos; |
685 | int ret, more; | 685 | int more; |
686 | |||
687 | ret = buf->ops->confirm(pipe, buf); | ||
688 | if (!ret) { | ||
689 | more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len; | ||
690 | if (file->f_op && file->f_op->sendpage) | ||
691 | ret = file->f_op->sendpage(file, buf->page, buf->offset, | ||
692 | sd->len, &pos, more); | ||
693 | else | ||
694 | ret = -EINVAL; | ||
695 | } | ||
696 | 686 | ||
697 | return ret; | 687 | if (!likely(file->f_op && file->f_op->sendpage)) |
688 | return -EINVAL; | ||
689 | |||
690 | more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len; | ||
691 | return file->f_op->sendpage(file, buf->page, buf->offset, | ||
692 | sd->len, &pos, more); | ||
698 | } | 693 | } |
699 | 694 | ||
700 | /* | 695 | /* |
@@ -727,13 +722,6 @@ int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
727 | void *fsdata; | 722 | void *fsdata; |
728 | int ret; | 723 | int ret; |
729 | 724 | ||
730 | /* | ||
731 | * make sure the data in this buffer is uptodate | ||
732 | */ | ||
733 | ret = buf->ops->confirm(pipe, buf); | ||
734 | if (unlikely(ret)) | ||
735 | return ret; | ||
736 | |||
737 | offset = sd->pos & ~PAGE_CACHE_MASK; | 725 | offset = sd->pos & ~PAGE_CACHE_MASK; |
738 | 726 | ||
739 | this_len = sd->len; | 727 | this_len = sd->len; |
@@ -805,12 +793,17 @@ int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd, | |||
805 | if (sd->len > sd->total_len) | 793 | if (sd->len > sd->total_len) |
806 | sd->len = sd->total_len; | 794 | sd->len = sd->total_len; |
807 | 795 | ||
808 | ret = actor(pipe, buf, sd); | 796 | ret = buf->ops->confirm(pipe, buf); |
809 | if (ret <= 0) { | 797 | if (unlikely(ret)) { |
810 | if (ret == -ENODATA) | 798 | if (ret == -ENODATA) |
811 | ret = 0; | 799 | ret = 0; |
812 | return ret; | 800 | return ret; |
813 | } | 801 | } |
802 | |||
803 | ret = actor(pipe, buf, sd); | ||
804 | if (ret <= 0) | ||
805 | return ret; | ||
806 | |||
814 | buf->offset += ret; | 807 | buf->offset += ret; |
815 | buf->len -= ret; | 808 | buf->len -= ret; |
816 | 809 | ||
@@ -1044,10 +1037,6 @@ static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
1044 | int ret; | 1037 | int ret; |
1045 | void *data; | 1038 | void *data; |
1046 | 1039 | ||
1047 | ret = buf->ops->confirm(pipe, buf); | ||
1048 | if (ret) | ||
1049 | return ret; | ||
1050 | |||
1051 | data = buf->ops->map(pipe, buf, 0); | 1040 | data = buf->ops->map(pipe, buf, 0); |
1052 | ret = kernel_write(sd->u.file, data + buf->offset, sd->len, sd->pos); | 1041 | ret = kernel_write(sd->u.file, data + buf->offset, sd->len, sd->pos); |
1053 | buf->ops->unmap(pipe, buf, data); | 1042 | buf->ops->unmap(pipe, buf, data); |
@@ -1507,10 +1496,6 @@ static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
1507 | char *src; | 1496 | char *src; |
1508 | int ret; | 1497 | int ret; |
1509 | 1498 | ||
1510 | ret = buf->ops->confirm(pipe, buf); | ||
1511 | if (unlikely(ret)) | ||
1512 | return ret; | ||
1513 | |||
1514 | /* | 1499 | /* |
1515 | * See if we can use the atomic maps, by prefaulting in the | 1500 | * See if we can use the atomic maps, by prefaulting in the |
1516 | * pages and doing an atomic copy | 1501 | * pages and doing an atomic copy |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 05667e6989f1..5730043eb15a 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 13893aa2ac9d..c0d5f6945c1e 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
@@ -115,6 +115,7 @@ struct hd_struct { | |||
115 | #else | 115 | #else |
116 | struct disk_stats dkstats; | 116 | struct disk_stats dkstats; |
117 | #endif | 117 | #endif |
118 | atomic_t ref; | ||
118 | struct rcu_head rcu_head; | 119 | struct rcu_head rcu_head; |
119 | }; | 120 | }; |
120 | 121 | ||
@@ -597,6 +598,7 @@ extern struct hd_struct * __must_check add_partition(struct gendisk *disk, | |||
597 | sector_t len, int flags, | 598 | sector_t len, int flags, |
598 | struct partition_meta_info | 599 | struct partition_meta_info |
599 | *info); | 600 | *info); |
601 | extern void __delete_partition(struct hd_struct *); | ||
600 | extern void delete_partition(struct gendisk *, int); | 602 | extern void delete_partition(struct gendisk *, int); |
601 | extern void printk_all_partitions(void); | 603 | extern void printk_all_partitions(void); |
602 | 604 | ||
@@ -625,6 +627,29 @@ extern ssize_t part_fail_store(struct device *dev, | |||
625 | const char *buf, size_t count); | 627 | const char *buf, size_t count); |
626 | #endif /* CONFIG_FAIL_MAKE_REQUEST */ | 628 | #endif /* CONFIG_FAIL_MAKE_REQUEST */ |
627 | 629 | ||
630 | static inline void hd_ref_init(struct hd_struct *part) | ||
631 | { | ||
632 | atomic_set(&part->ref, 1); | ||
633 | smp_mb(); | ||
634 | } | ||
635 | |||
636 | static inline void hd_struct_get(struct hd_struct *part) | ||
637 | { | ||
638 | atomic_inc(&part->ref); | ||
639 | smp_mb__after_atomic_inc(); | ||
640 | } | ||
641 | |||
642 | static inline int hd_struct_try_get(struct hd_struct *part) | ||
643 | { | ||
644 | return atomic_inc_not_zero(&part->ref); | ||
645 | } | ||
646 | |||
647 | static inline void hd_struct_put(struct hd_struct *part) | ||
648 | { | ||
649 | if (atomic_dec_and_test(&part->ref)) | ||
650 | __delete_partition(part); | ||
651 | } | ||
652 | |||
628 | #else /* CONFIG_BLOCK */ | 653 | #else /* CONFIG_BLOCK */ |
629 | 654 | ||
630 | static inline void printk_all_partitions(void) { } | 655 | static inline void printk_all_partitions(void) { } |
diff --git a/include/trace/events/block.h b/include/trace/events/block.h index b56c65dc105d..aba421d68f6f 100644 --- a/include/trace/events/block.h +++ b/include/trace/events/block.h | |||
@@ -206,15 +206,16 @@ TRACE_EVENT(block_bio_bounce, | |||
206 | * block_bio_complete - completed all work on the block operation | 206 | * block_bio_complete - completed all work on the block operation |
207 | * @q: queue holding the block operation | 207 | * @q: queue holding the block operation |
208 | * @bio: block operation completed | 208 | * @bio: block operation completed |
209 | * @error: io error value | ||
209 | * | 210 | * |
210 | * This tracepoint indicates there is no further work to do on this | 211 | * This tracepoint indicates there is no further work to do on this |
211 | * block IO operation @bio. | 212 | * block IO operation @bio. |
212 | */ | 213 | */ |
213 | TRACE_EVENT(block_bio_complete, | 214 | TRACE_EVENT(block_bio_complete, |
214 | 215 | ||
215 | TP_PROTO(struct request_queue *q, struct bio *bio), | 216 | TP_PROTO(struct request_queue *q, struct bio *bio, int error), |
216 | 217 | ||
217 | TP_ARGS(q, bio), | 218 | TP_ARGS(q, bio, error), |
218 | 219 | ||
219 | TP_STRUCT__entry( | 220 | TP_STRUCT__entry( |
220 | __field( dev_t, dev ) | 221 | __field( dev_t, dev ) |
@@ -228,6 +229,7 @@ TRACE_EVENT(block_bio_complete, | |||
228 | __entry->dev = bio->bi_bdev->bd_dev; | 229 | __entry->dev = bio->bi_bdev->bd_dev; |
229 | __entry->sector = bio->bi_sector; | 230 | __entry->sector = bio->bi_sector; |
230 | __entry->nr_sector = bio->bi_size >> 9; | 231 | __entry->nr_sector = bio->bi_size >> 9; |
232 | __entry->error = error; | ||
231 | blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); | 233 | blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); |
232 | ), | 234 | ), |
233 | 235 | ||
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 2b8e2ee7c0ef..153562d0b93c 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c | |||
@@ -758,53 +758,58 @@ static void blk_add_trace_rq_complete(void *ignore, | |||
758 | * @q: queue the io is for | 758 | * @q: queue the io is for |
759 | * @bio: the source bio | 759 | * @bio: the source bio |
760 | * @what: the action | 760 | * @what: the action |
761 | * @error: error, if any | ||
761 | * | 762 | * |
762 | * Description: | 763 | * Description: |
763 | * Records an action against a bio. Will log the bio offset + size. | 764 | * Records an action against a bio. Will log the bio offset + size. |
764 | * | 765 | * |
765 | **/ | 766 | **/ |
766 | static void blk_add_trace_bio(struct request_queue *q, struct bio *bio, | 767 | static void blk_add_trace_bio(struct request_queue *q, struct bio *bio, |
767 | u32 what) | 768 | u32 what, int error) |
768 | { | 769 | { |
769 | struct blk_trace *bt = q->blk_trace; | 770 | struct blk_trace *bt = q->blk_trace; |
770 | 771 | ||
771 | if (likely(!bt)) | 772 | if (likely(!bt)) |
772 | return; | 773 | return; |
773 | 774 | ||
775 | if (!error && !bio_flagged(bio, BIO_UPTODATE)) | ||
776 | error = EIO; | ||
777 | |||
774 | __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what, | 778 | __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what, |
775 | !bio_flagged(bio, BIO_UPTODATE), 0, NULL); | 779 | error, 0, NULL); |
776 | } | 780 | } |
777 | 781 | ||
778 | static void blk_add_trace_bio_bounce(void *ignore, | 782 | static void blk_add_trace_bio_bounce(void *ignore, |
779 | struct request_queue *q, struct bio *bio) | 783 | struct request_queue *q, struct bio *bio) |
780 | { | 784 | { |
781 | blk_add_trace_bio(q, bio, BLK_TA_BOUNCE); | 785 | blk_add_trace_bio(q, bio, BLK_TA_BOUNCE, 0); |
782 | } | 786 | } |
783 | 787 | ||
784 | static void blk_add_trace_bio_complete(void *ignore, | 788 | static void blk_add_trace_bio_complete(void *ignore, |
785 | struct request_queue *q, struct bio *bio) | 789 | struct request_queue *q, struct bio *bio, |
790 | int error) | ||
786 | { | 791 | { |
787 | blk_add_trace_bio(q, bio, BLK_TA_COMPLETE); | 792 | blk_add_trace_bio(q, bio, BLK_TA_COMPLETE, error); |
788 | } | 793 | } |
789 | 794 | ||
790 | static void blk_add_trace_bio_backmerge(void *ignore, | 795 | static void blk_add_trace_bio_backmerge(void *ignore, |
791 | struct request_queue *q, | 796 | struct request_queue *q, |
792 | struct bio *bio) | 797 | struct bio *bio) |
793 | { | 798 | { |
794 | blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE); | 799 | blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE, 0); |
795 | } | 800 | } |
796 | 801 | ||
797 | static void blk_add_trace_bio_frontmerge(void *ignore, | 802 | static void blk_add_trace_bio_frontmerge(void *ignore, |
798 | struct request_queue *q, | 803 | struct request_queue *q, |
799 | struct bio *bio) | 804 | struct bio *bio) |
800 | { | 805 | { |
801 | blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE); | 806 | blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE, 0); |
802 | } | 807 | } |
803 | 808 | ||
804 | static void blk_add_trace_bio_queue(void *ignore, | 809 | static void blk_add_trace_bio_queue(void *ignore, |
805 | struct request_queue *q, struct bio *bio) | 810 | struct request_queue *q, struct bio *bio) |
806 | { | 811 | { |
807 | blk_add_trace_bio(q, bio, BLK_TA_QUEUE); | 812 | blk_add_trace_bio(q, bio, BLK_TA_QUEUE, 0); |
808 | } | 813 | } |
809 | 814 | ||
810 | static void blk_add_trace_getrq(void *ignore, | 815 | static void blk_add_trace_getrq(void *ignore, |
@@ -812,7 +817,7 @@ static void blk_add_trace_getrq(void *ignore, | |||
812 | struct bio *bio, int rw) | 817 | struct bio *bio, int rw) |
813 | { | 818 | { |
814 | if (bio) | 819 | if (bio) |
815 | blk_add_trace_bio(q, bio, BLK_TA_GETRQ); | 820 | blk_add_trace_bio(q, bio, BLK_TA_GETRQ, 0); |
816 | else { | 821 | else { |
817 | struct blk_trace *bt = q->blk_trace; | 822 | struct blk_trace *bt = q->blk_trace; |
818 | 823 | ||
@@ -827,7 +832,7 @@ static void blk_add_trace_sleeprq(void *ignore, | |||
827 | struct bio *bio, int rw) | 832 | struct bio *bio, int rw) |
828 | { | 833 | { |
829 | if (bio) | 834 | if (bio) |
830 | blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ); | 835 | blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ, 0); |
831 | else { | 836 | else { |
832 | struct blk_trace *bt = q->blk_trace; | 837 | struct blk_trace *bt = q->blk_trace; |
833 | 838 | ||