diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-core.c | 25 | ||||
-rw-r--r-- | block/blk-ioc.c | 62 | ||||
-rw-r--r-- | block/blk.h | 36 | ||||
-rw-r--r-- | block/cfq-iosched.c | 2 |
4 files changed, 71 insertions, 54 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index fd4749391e17..6804fdf27eff 100644 --- a/block/blk-core.c +++ b/block/blk-core.c | |||
@@ -771,9 +771,12 @@ static struct request *get_request(struct request_queue *q, int rw_flags, | |||
771 | { | 771 | { |
772 | struct request *rq = NULL; | 772 | struct request *rq = NULL; |
773 | struct request_list *rl = &q->rq; | 773 | struct request_list *rl = &q->rq; |
774 | struct io_context *ioc = NULL; | 774 | struct io_context *ioc; |
775 | const bool is_sync = rw_is_sync(rw_flags) != 0; | 775 | const bool is_sync = rw_is_sync(rw_flags) != 0; |
776 | bool retried = false; | ||
776 | int may_queue; | 777 | int may_queue; |
778 | retry: | ||
779 | ioc = current->io_context; | ||
777 | 780 | ||
778 | if (unlikely(blk_queue_dead(q))) | 781 | if (unlikely(blk_queue_dead(q))) |
779 | return NULL; | 782 | return NULL; |
@@ -784,7 +787,20 @@ static struct request *get_request(struct request_queue *q, int rw_flags, | |||
784 | 787 | ||
785 | if (rl->count[is_sync]+1 >= queue_congestion_on_threshold(q)) { | 788 | if (rl->count[is_sync]+1 >= queue_congestion_on_threshold(q)) { |
786 | if (rl->count[is_sync]+1 >= q->nr_requests) { | 789 | if (rl->count[is_sync]+1 >= q->nr_requests) { |
787 | ioc = current_io_context(GFP_ATOMIC, q->node); | 790 | /* |
791 | * We want ioc to record batching state. If it's | ||
792 | * not already there, creating a new one requires | ||
793 | * dropping queue_lock, which in turn requires | ||
794 | * retesting conditions to avoid queue hang. | ||
795 | */ | ||
796 | if (!ioc && !retried) { | ||
797 | spin_unlock_irq(q->queue_lock); | ||
798 | create_io_context(current, gfp_mask, q->node); | ||
799 | spin_lock_irq(q->queue_lock); | ||
800 | retried = true; | ||
801 | goto retry; | ||
802 | } | ||
803 | |||
788 | /* | 804 | /* |
789 | * The queue will fill after this allocation, so set | 805 | * The queue will fill after this allocation, so set |
790 | * it as full, and mark this process as "batching". | 806 | * it as full, and mark this process as "batching". |
@@ -892,7 +908,6 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags, | |||
892 | rq = get_request(q, rw_flags, bio, GFP_NOIO); | 908 | rq = get_request(q, rw_flags, bio, GFP_NOIO); |
893 | while (!rq) { | 909 | while (!rq) { |
894 | DEFINE_WAIT(wait); | 910 | DEFINE_WAIT(wait); |
895 | struct io_context *ioc; | ||
896 | struct request_list *rl = &q->rq; | 911 | struct request_list *rl = &q->rq; |
897 | 912 | ||
898 | if (unlikely(blk_queue_dead(q))) | 913 | if (unlikely(blk_queue_dead(q))) |
@@ -912,8 +927,8 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags, | |||
912 | * up to a big batch of them for a small period time. | 927 | * up to a big batch of them for a small period time. |
913 | * See ioc_batching, ioc_set_batching | 928 | * See ioc_batching, ioc_set_batching |
914 | */ | 929 | */ |
915 | ioc = current_io_context(GFP_NOIO, q->node); | 930 | create_io_context(current, GFP_NOIO, q->node); |
916 | ioc_set_batching(q, ioc); | 931 | ioc_set_batching(q, current->io_context); |
917 | 932 | ||
918 | spin_lock_irq(q->queue_lock); | 933 | spin_lock_irq(q->queue_lock); |
919 | finish_wait(&rl->wait[is_sync], &wait); | 934 | finish_wait(&rl->wait[is_sync], &wait); |
diff --git a/block/blk-ioc.c b/block/blk-ioc.c index fb23965595da..e23c797b4685 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c | |||
@@ -205,16 +205,15 @@ void exit_io_context(struct task_struct *task) | |||
205 | put_io_context(ioc, NULL); | 205 | put_io_context(ioc, NULL); |
206 | } | 206 | } |
207 | 207 | ||
208 | static struct io_context *create_task_io_context(struct task_struct *task, | 208 | void create_io_context_slowpath(struct task_struct *task, gfp_t gfp_flags, |
209 | gfp_t gfp_flags, int node, | 209 | int node) |
210 | bool take_ref) | ||
211 | { | 210 | { |
212 | struct io_context *ioc; | 211 | struct io_context *ioc; |
213 | 212 | ||
214 | ioc = kmem_cache_alloc_node(iocontext_cachep, gfp_flags | __GFP_ZERO, | 213 | ioc = kmem_cache_alloc_node(iocontext_cachep, gfp_flags | __GFP_ZERO, |
215 | node); | 214 | node); |
216 | if (unlikely(!ioc)) | 215 | if (unlikely(!ioc)) |
217 | return NULL; | 216 | return; |
218 | 217 | ||
219 | /* initialize */ | 218 | /* initialize */ |
220 | atomic_long_set(&ioc->refcount, 1); | 219 | atomic_long_set(&ioc->refcount, 1); |
@@ -226,42 +225,13 @@ static struct io_context *create_task_io_context(struct task_struct *task, | |||
226 | 225 | ||
227 | /* try to install, somebody might already have beaten us to it */ | 226 | /* try to install, somebody might already have beaten us to it */ |
228 | task_lock(task); | 227 | task_lock(task); |
229 | 228 | if (!task->io_context && !(task->flags & PF_EXITING)) | |
230 | if (!task->io_context && !(task->flags & PF_EXITING)) { | ||
231 | task->io_context = ioc; | 229 | task->io_context = ioc; |
232 | } else { | 230 | else |
233 | kmem_cache_free(iocontext_cachep, ioc); | 231 | kmem_cache_free(iocontext_cachep, ioc); |
234 | ioc = task->io_context; | ||
235 | } | ||
236 | |||
237 | if (ioc && take_ref) | ||
238 | get_io_context(ioc); | ||
239 | |||
240 | task_unlock(task); | 232 | task_unlock(task); |
241 | return ioc; | ||
242 | } | 233 | } |
243 | 234 | EXPORT_SYMBOL(create_io_context_slowpath); | |
244 | /** | ||
245 | * current_io_context - get io_context of %current | ||
246 | * @gfp_flags: allocation flags, used if allocation is necessary | ||
247 | * @node: allocation node, used if allocation is necessary | ||
248 | * | ||
249 | * Return io_context of %current. If it doesn't exist, it is created with | ||
250 | * @gfp_flags and @node. The returned io_context does NOT have its | ||
251 | * reference count incremented. Because io_context is exited only on task | ||
252 | * exit, %current can be sure that the returned io_context is valid and | ||
253 | * alive as long as it is executing. | ||
254 | */ | ||
255 | struct io_context *current_io_context(gfp_t gfp_flags, int node) | ||
256 | { | ||
257 | might_sleep_if(gfp_flags & __GFP_WAIT); | ||
258 | |||
259 | if (current->io_context) | ||
260 | return current->io_context; | ||
261 | |||
262 | return create_task_io_context(current, gfp_flags, node, false); | ||
263 | } | ||
264 | EXPORT_SYMBOL(current_io_context); | ||
265 | 235 | ||
266 | /** | 236 | /** |
267 | * get_task_io_context - get io_context of a task | 237 | * get_task_io_context - get io_context of a task |
@@ -274,7 +244,7 @@ EXPORT_SYMBOL(current_io_context); | |||
274 | * incremented. | 244 | * incremented. |
275 | * | 245 | * |
276 | * This function always goes through task_lock() and it's better to use | 246 | * This function always goes through task_lock() and it's better to use |
277 | * current_io_context() + get_io_context() for %current. | 247 | * %current->io_context + get_io_context() for %current. |
278 | */ | 248 | */ |
279 | struct io_context *get_task_io_context(struct task_struct *task, | 249 | struct io_context *get_task_io_context(struct task_struct *task, |
280 | gfp_t gfp_flags, int node) | 250 | gfp_t gfp_flags, int node) |
@@ -283,16 +253,18 @@ struct io_context *get_task_io_context(struct task_struct *task, | |||
283 | 253 | ||
284 | might_sleep_if(gfp_flags & __GFP_WAIT); | 254 | might_sleep_if(gfp_flags & __GFP_WAIT); |
285 | 255 | ||
286 | task_lock(task); | 256 | do { |
287 | ioc = task->io_context; | 257 | task_lock(task); |
288 | if (likely(ioc)) { | 258 | ioc = task->io_context; |
289 | get_io_context(ioc); | 259 | if (likely(ioc)) { |
260 | get_io_context(ioc); | ||
261 | task_unlock(task); | ||
262 | return ioc; | ||
263 | } | ||
290 | task_unlock(task); | 264 | task_unlock(task); |
291 | return ioc; | 265 | } while (create_io_context(task, gfp_flags, node)); |
292 | } | ||
293 | task_unlock(task); | ||
294 | 266 | ||
295 | return create_task_io_context(task, gfp_flags, node, true); | 267 | return NULL; |
296 | } | 268 | } |
297 | EXPORT_SYMBOL(get_task_io_context); | 269 | EXPORT_SYMBOL(get_task_io_context); |
298 | 270 | ||
diff --git a/block/blk.h b/block/blk.h index 8d421156fefb..5bca2668e1bf 100644 --- a/block/blk.h +++ b/block/blk.h | |||
@@ -127,9 +127,6 @@ static inline int blk_should_fake_timeout(struct request_queue *q) | |||
127 | } | 127 | } |
128 | #endif | 128 | #endif |
129 | 129 | ||
130 | void get_io_context(struct io_context *ioc); | ||
131 | struct io_context *current_io_context(gfp_t gfp_flags, int node); | ||
132 | |||
133 | int ll_back_merge_fn(struct request_queue *q, struct request *req, | 130 | int ll_back_merge_fn(struct request_queue *q, struct request *req, |
134 | struct bio *bio); | 131 | struct bio *bio); |
135 | int ll_front_merge_fn(struct request_queue *q, struct request *req, | 132 | int ll_front_merge_fn(struct request_queue *q, struct request *req, |
@@ -198,6 +195,39 @@ static inline int blk_do_io_stat(struct request *rq) | |||
198 | (rq->cmd_flags & REQ_DISCARD)); | 195 | (rq->cmd_flags & REQ_DISCARD)); |
199 | } | 196 | } |
200 | 197 | ||
198 | /* | ||
199 | * Internal io_context interface | ||
200 | */ | ||
201 | void get_io_context(struct io_context *ioc); | ||
202 | |||
203 | void create_io_context_slowpath(struct task_struct *task, gfp_t gfp_mask, | ||
204 | int node); | ||
205 | |||
206 | /** | ||
207 | * create_io_context - try to create task->io_context | ||
208 | * @task: target task | ||
209 | * @gfp_mask: allocation mask | ||
210 | * @node: allocation node | ||
211 | * | ||
212 | * If @task->io_context is %NULL, allocate a new io_context and install it. | ||
213 | * Returns the current @task->io_context which may be %NULL if allocation | ||
214 | * failed. | ||
215 | * | ||
216 | * Note that this function can't be called with IRQ disabled because | ||
217 | * task_lock which protects @task->io_context is IRQ-unsafe. | ||
218 | */ | ||
219 | static inline struct io_context *create_io_context(struct task_struct *task, | ||
220 | gfp_t gfp_mask, int node) | ||
221 | { | ||
222 | WARN_ON_ONCE(irqs_disabled()); | ||
223 | if (unlikely(!task->io_context)) | ||
224 | create_io_context_slowpath(task, gfp_mask, node); | ||
225 | return task->io_context; | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | * Internal throttling interface | ||
230 | */ | ||
201 | #ifdef CONFIG_BLK_DEV_THROTTLING | 231 | #ifdef CONFIG_BLK_DEV_THROTTLING |
202 | extern bool blk_throtl_bio(struct request_queue *q, struct bio *bio); | 232 | extern bool blk_throtl_bio(struct request_queue *q, struct bio *bio); |
203 | extern void blk_throtl_drain(struct request_queue *q); | 233 | extern void blk_throtl_drain(struct request_queue *q); |
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 3b07ce168780..5f7e4d161404 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -3012,7 +3012,7 @@ static int cfq_create_cic(struct cfq_data *cfqd, gfp_t gfp_mask) | |||
3012 | might_sleep_if(gfp_mask & __GFP_WAIT); | 3012 | might_sleep_if(gfp_mask & __GFP_WAIT); |
3013 | 3013 | ||
3014 | /* allocate stuff */ | 3014 | /* allocate stuff */ |
3015 | ioc = current_io_context(gfp_mask, q->node); | 3015 | ioc = create_io_context(current, gfp_mask, q->node); |
3016 | if (!ioc) | 3016 | if (!ioc) |
3017 | goto out; | 3017 | goto out; |
3018 | 3018 | ||