diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-core.c | 46 | ||||
-rw-r--r-- | block/blk-ioc.c | 60 | ||||
-rw-r--r-- | block/blk.h | 1 | ||||
-rw-r--r-- | block/cfq-iosched.c | 135 |
4 files changed, 110 insertions, 132 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index 3c26c7f48703..8fbdac7010bb 100644 --- a/block/blk-core.c +++ b/block/blk-core.c | |||
@@ -640,13 +640,18 @@ EXPORT_SYMBOL(blk_get_queue); | |||
640 | 640 | ||
641 | static inline void blk_free_request(struct request_queue *q, struct request *rq) | 641 | static inline void blk_free_request(struct request_queue *q, struct request *rq) |
642 | { | 642 | { |
643 | if (rq->cmd_flags & REQ_ELVPRIV) | 643 | if (rq->cmd_flags & REQ_ELVPRIV) { |
644 | elv_put_request(q, rq); | 644 | elv_put_request(q, rq); |
645 | if (rq->elv.icq) | ||
646 | put_io_context(rq->elv.icq->ioc, q); | ||
647 | } | ||
648 | |||
645 | mempool_free(rq, q->rq.rq_pool); | 649 | mempool_free(rq, q->rq.rq_pool); |
646 | } | 650 | } |
647 | 651 | ||
648 | static struct request * | 652 | static struct request * |
649 | blk_alloc_request(struct request_queue *q, unsigned int flags, gfp_t gfp_mask) | 653 | blk_alloc_request(struct request_queue *q, struct io_cq *icq, |
654 | unsigned int flags, gfp_t gfp_mask) | ||
650 | { | 655 | { |
651 | struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask); | 656 | struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask); |
652 | 657 | ||
@@ -657,10 +662,15 @@ blk_alloc_request(struct request_queue *q, unsigned int flags, gfp_t gfp_mask) | |||
657 | 662 | ||
658 | rq->cmd_flags = flags | REQ_ALLOCED; | 663 | rq->cmd_flags = flags | REQ_ALLOCED; |
659 | 664 | ||
660 | if ((flags & REQ_ELVPRIV) && | 665 | if (flags & REQ_ELVPRIV) { |
661 | unlikely(elv_set_request(q, rq, gfp_mask))) { | 666 | rq->elv.icq = icq; |
662 | mempool_free(rq, q->rq.rq_pool); | 667 | if (unlikely(elv_set_request(q, rq, gfp_mask))) { |
663 | return NULL; | 668 | mempool_free(rq, q->rq.rq_pool); |
669 | return NULL; | ||
670 | } | ||
671 | /* @rq->elv.icq holds on to io_context until @rq is freed */ | ||
672 | if (icq) | ||
673 | get_io_context(icq->ioc); | ||
664 | } | 674 | } |
665 | 675 | ||
666 | return rq; | 676 | return rq; |
@@ -772,11 +782,14 @@ static struct request *get_request(struct request_queue *q, int rw_flags, | |||
772 | { | 782 | { |
773 | struct request *rq = NULL; | 783 | struct request *rq = NULL; |
774 | struct request_list *rl = &q->rq; | 784 | struct request_list *rl = &q->rq; |
785 | struct elevator_type *et; | ||
775 | struct io_context *ioc; | 786 | struct io_context *ioc; |
787 | struct io_cq *icq = NULL; | ||
776 | const bool is_sync = rw_is_sync(rw_flags) != 0; | 788 | const bool is_sync = rw_is_sync(rw_flags) != 0; |
777 | bool retried = false; | 789 | bool retried = false; |
778 | int may_queue; | 790 | int may_queue; |
779 | retry: | 791 | retry: |
792 | et = q->elevator->type; | ||
780 | ioc = current->io_context; | 793 | ioc = current->io_context; |
781 | 794 | ||
782 | if (unlikely(blk_queue_dead(q))) | 795 | if (unlikely(blk_queue_dead(q))) |
@@ -837,17 +850,36 @@ retry: | |||
837 | rl->count[is_sync]++; | 850 | rl->count[is_sync]++; |
838 | rl->starved[is_sync] = 0; | 851 | rl->starved[is_sync] = 0; |
839 | 852 | ||
853 | /* | ||
854 | * Decide whether the new request will be managed by elevator. If | ||
855 | * so, mark @rw_flags and increment elvpriv. Non-zero elvpriv will | ||
856 | * prevent the current elevator from being destroyed until the new | ||
857 | * request is freed. This guarantees icq's won't be destroyed and | ||
858 | * makes creating new ones safe. | ||
859 | * | ||
860 | * Also, lookup icq while holding queue_lock. If it doesn't exist, | ||
861 | * it will be created after releasing queue_lock. | ||
862 | */ | ||
840 | if (blk_rq_should_init_elevator(bio) && | 863 | if (blk_rq_should_init_elevator(bio) && |
841 | !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags)) { | 864 | !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags)) { |
842 | rw_flags |= REQ_ELVPRIV; | 865 | rw_flags |= REQ_ELVPRIV; |
843 | rl->elvpriv++; | 866 | rl->elvpriv++; |
867 | if (et->icq_cache && ioc) | ||
868 | icq = ioc_lookup_icq(ioc, q); | ||
844 | } | 869 | } |
845 | 870 | ||
846 | if (blk_queue_io_stat(q)) | 871 | if (blk_queue_io_stat(q)) |
847 | rw_flags |= REQ_IO_STAT; | 872 | rw_flags |= REQ_IO_STAT; |
848 | spin_unlock_irq(q->queue_lock); | 873 | spin_unlock_irq(q->queue_lock); |
849 | 874 | ||
850 | rq = blk_alloc_request(q, rw_flags, gfp_mask); | 875 | /* create icq if missing */ |
876 | if (unlikely(et->icq_cache && !icq)) | ||
877 | icq = ioc_create_icq(q, gfp_mask); | ||
878 | |||
879 | /* rqs are guaranteed to have icq on elv_set_request() if requested */ | ||
880 | if (likely(!et->icq_cache || icq)) | ||
881 | rq = blk_alloc_request(q, icq, rw_flags, gfp_mask); | ||
882 | |||
851 | if (unlikely(!rq)) { | 883 | if (unlikely(!rq)) { |
852 | /* | 884 | /* |
853 | * Allocation failed presumably due to memory. Undo anything | 885 | * Allocation failed presumably due to memory. Undo anything |
diff --git a/block/blk-ioc.c b/block/blk-ioc.c index 0910a5584d38..c04d16b02225 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c | |||
@@ -289,7 +289,6 @@ void create_io_context_slowpath(struct task_struct *task, gfp_t gfp_flags, | |||
289 | kmem_cache_free(iocontext_cachep, ioc); | 289 | kmem_cache_free(iocontext_cachep, ioc); |
290 | task_unlock(task); | 290 | task_unlock(task); |
291 | } | 291 | } |
292 | EXPORT_SYMBOL(create_io_context_slowpath); | ||
293 | 292 | ||
294 | /** | 293 | /** |
295 | * get_task_io_context - get io_context of a task | 294 | * get_task_io_context - get io_context of a task |
@@ -362,6 +361,65 @@ out: | |||
362 | } | 361 | } |
363 | EXPORT_SYMBOL(ioc_lookup_icq); | 362 | EXPORT_SYMBOL(ioc_lookup_icq); |
364 | 363 | ||
364 | /** | ||
365 | * ioc_create_icq - create and link io_cq | ||
366 | * @q: request_queue of interest | ||
367 | * @gfp_mask: allocation mask | ||
368 | * | ||
369 | * Make sure io_cq linking %current->io_context and @q exists. If either | ||
370 | * io_context and/or icq don't exist, they will be created using @gfp_mask. | ||
371 | * | ||
372 | * The caller is responsible for ensuring @ioc won't go away and @q is | ||
373 | * alive and will stay alive until this function returns. | ||
374 | */ | ||
375 | struct io_cq *ioc_create_icq(struct request_queue *q, gfp_t gfp_mask) | ||
376 | { | ||
377 | struct elevator_type *et = q->elevator->type; | ||
378 | struct io_context *ioc; | ||
379 | struct io_cq *icq; | ||
380 | |||
381 | /* allocate stuff */ | ||
382 | ioc = create_io_context(current, gfp_mask, q->node); | ||
383 | if (!ioc) | ||
384 | return NULL; | ||
385 | |||
386 | icq = kmem_cache_alloc_node(et->icq_cache, gfp_mask | __GFP_ZERO, | ||
387 | q->node); | ||
388 | if (!icq) | ||
389 | return NULL; | ||
390 | |||
391 | if (radix_tree_preload(gfp_mask) < 0) { | ||
392 | kmem_cache_free(et->icq_cache, icq); | ||
393 | return NULL; | ||
394 | } | ||
395 | |||
396 | icq->ioc = ioc; | ||
397 | icq->q = q; | ||
398 | INIT_LIST_HEAD(&icq->q_node); | ||
399 | INIT_HLIST_NODE(&icq->ioc_node); | ||
400 | |||
401 | /* lock both q and ioc and try to link @icq */ | ||
402 | spin_lock_irq(q->queue_lock); | ||
403 | spin_lock(&ioc->lock); | ||
404 | |||
405 | if (likely(!radix_tree_insert(&ioc->icq_tree, q->id, icq))) { | ||
406 | hlist_add_head(&icq->ioc_node, &ioc->icq_list); | ||
407 | list_add(&icq->q_node, &q->icq_list); | ||
408 | if (et->ops.elevator_init_icq_fn) | ||
409 | et->ops.elevator_init_icq_fn(icq); | ||
410 | } else { | ||
411 | kmem_cache_free(et->icq_cache, icq); | ||
412 | icq = ioc_lookup_icq(ioc, q); | ||
413 | if (!icq) | ||
414 | printk(KERN_ERR "cfq: icq link failed!\n"); | ||
415 | } | ||
416 | |||
417 | spin_unlock(&ioc->lock); | ||
418 | spin_unlock_irq(q->queue_lock); | ||
419 | radix_tree_preload_end(); | ||
420 | return icq; | ||
421 | } | ||
422 | |||
365 | void ioc_set_changed(struct io_context *ioc, int which) | 423 | void ioc_set_changed(struct io_context *ioc, int which) |
366 | { | 424 | { |
367 | struct io_cq *icq; | 425 | struct io_cq *icq; |
diff --git a/block/blk.h b/block/blk.h index ed4d9bf2ab16..7efd772336de 100644 --- a/block/blk.h +++ b/block/blk.h | |||
@@ -200,6 +200,7 @@ static inline int blk_do_io_stat(struct request *rq) | |||
200 | */ | 200 | */ |
201 | void get_io_context(struct io_context *ioc); | 201 | void get_io_context(struct io_context *ioc); |
202 | struct io_cq *ioc_lookup_icq(struct io_context *ioc, struct request_queue *q); | 202 | struct io_cq *ioc_lookup_icq(struct io_context *ioc, struct request_queue *q); |
203 | struct io_cq *ioc_create_icq(struct request_queue *q, gfp_t gfp_mask); | ||
203 | void ioc_clear_queue(struct request_queue *q); | 204 | void ioc_clear_queue(struct request_queue *q); |
204 | 205 | ||
205 | void create_io_context_slowpath(struct task_struct *task, gfp_t gfp_mask, | 206 | void create_io_context_slowpath(struct task_struct *task, gfp_t gfp_mask, |
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 11f49d036845..f3b44c394e6d 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -2935,117 +2935,6 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct io_context *ioc, | |||
2935 | return cfqq; | 2935 | return cfqq; |
2936 | } | 2936 | } |
2937 | 2937 | ||
2938 | /** | ||
2939 | * ioc_create_icq - create and link io_cq | ||
2940 | * @q: request_queue of interest | ||
2941 | * @gfp_mask: allocation mask | ||
2942 | * | ||
2943 | * Make sure io_cq linking %current->io_context and @q exists. If either | ||
2944 | * io_context and/or icq don't exist, they will be created using @gfp_mask. | ||
2945 | * | ||
2946 | * The caller is responsible for ensuring @ioc won't go away and @q is | ||
2947 | * alive and will stay alive until this function returns. | ||
2948 | */ | ||
2949 | static struct io_cq *ioc_create_icq(struct request_queue *q, gfp_t gfp_mask) | ||
2950 | { | ||
2951 | struct elevator_type *et = q->elevator->type; | ||
2952 | struct io_context *ioc; | ||
2953 | struct io_cq *icq; | ||
2954 | |||
2955 | /* allocate stuff */ | ||
2956 | ioc = create_io_context(current, gfp_mask, q->node); | ||
2957 | if (!ioc) | ||
2958 | return NULL; | ||
2959 | |||
2960 | icq = kmem_cache_alloc_node(et->icq_cache, gfp_mask | __GFP_ZERO, | ||
2961 | q->node); | ||
2962 | if (!icq) | ||
2963 | return NULL; | ||
2964 | |||
2965 | if (radix_tree_preload(gfp_mask) < 0) { | ||
2966 | kmem_cache_free(et->icq_cache, icq); | ||
2967 | return NULL; | ||
2968 | } | ||
2969 | |||
2970 | icq->ioc = ioc; | ||
2971 | icq->q = q; | ||
2972 | INIT_LIST_HEAD(&icq->q_node); | ||
2973 | INIT_HLIST_NODE(&icq->ioc_node); | ||
2974 | |||
2975 | /* lock both q and ioc and try to link @icq */ | ||
2976 | spin_lock_irq(q->queue_lock); | ||
2977 | spin_lock(&ioc->lock); | ||
2978 | |||
2979 | if (likely(!radix_tree_insert(&ioc->icq_tree, q->id, icq))) { | ||
2980 | hlist_add_head(&icq->ioc_node, &ioc->icq_list); | ||
2981 | list_add(&icq->q_node, &q->icq_list); | ||
2982 | if (et->ops.elevator_init_icq_fn) | ||
2983 | et->ops.elevator_init_icq_fn(icq); | ||
2984 | } else { | ||
2985 | kmem_cache_free(et->icq_cache, icq); | ||
2986 | icq = ioc_lookup_icq(ioc, q); | ||
2987 | if (!icq) | ||
2988 | printk(KERN_ERR "cfq: icq link failed!\n"); | ||
2989 | } | ||
2990 | |||
2991 | spin_unlock(&ioc->lock); | ||
2992 | spin_unlock_irq(q->queue_lock); | ||
2993 | radix_tree_preload_end(); | ||
2994 | return icq; | ||
2995 | } | ||
2996 | |||
2997 | /** | ||
2998 | * cfq_get_cic - acquire cfq_io_cq and bump refcnt on io_context | ||
2999 | * @cfqd: cfqd to setup cic for | ||
3000 | * @gfp_mask: allocation mask | ||
3001 | * | ||
3002 | * Return cfq_io_cq associating @cfqd and %current->io_context and | ||
3003 | * bump refcnt on io_context. If ioc or cic doesn't exist, they're created | ||
3004 | * using @gfp_mask. | ||
3005 | * | ||
3006 | * Must be called under queue_lock which may be released and re-acquired. | ||
3007 | * This function also may sleep depending on @gfp_mask. | ||
3008 | */ | ||
3009 | static struct cfq_io_cq *cfq_get_cic(struct cfq_data *cfqd, gfp_t gfp_mask) | ||
3010 | { | ||
3011 | struct request_queue *q = cfqd->queue; | ||
3012 | struct cfq_io_cq *cic = NULL; | ||
3013 | struct io_context *ioc; | ||
3014 | |||
3015 | lockdep_assert_held(q->queue_lock); | ||
3016 | |||
3017 | while (true) { | ||
3018 | /* fast path */ | ||
3019 | ioc = current->io_context; | ||
3020 | if (likely(ioc)) { | ||
3021 | cic = cfq_cic_lookup(cfqd, ioc); | ||
3022 | if (likely(cic)) | ||
3023 | break; | ||
3024 | } | ||
3025 | |||
3026 | /* slow path - unlock, create missing ones and retry */ | ||
3027 | spin_unlock_irq(q->queue_lock); | ||
3028 | cic = icq_to_cic(ioc_create_icq(q, gfp_mask)); | ||
3029 | spin_lock_irq(q->queue_lock); | ||
3030 | if (!cic) | ||
3031 | return NULL; | ||
3032 | } | ||
3033 | |||
3034 | /* bump @ioc's refcnt and handle changed notifications */ | ||
3035 | get_io_context(ioc); | ||
3036 | |||
3037 | if (unlikely(cic->icq.changed)) { | ||
3038 | if (test_and_clear_bit(ICQ_IOPRIO_CHANGED, &cic->icq.changed)) | ||
3039 | changed_ioprio(cic); | ||
3040 | #ifdef CONFIG_CFQ_GROUP_IOSCHED | ||
3041 | if (test_and_clear_bit(ICQ_CGROUP_CHANGED, &cic->icq.changed)) | ||
3042 | changed_cgroup(cic); | ||
3043 | #endif | ||
3044 | } | ||
3045 | |||
3046 | return cic; | ||
3047 | } | ||
3048 | |||
3049 | static void | 2938 | static void |
3050 | __cfq_update_io_thinktime(struct cfq_ttime *ttime, unsigned long slice_idle) | 2939 | __cfq_update_io_thinktime(struct cfq_ttime *ttime, unsigned long slice_idle) |
3051 | { | 2940 | { |
@@ -3524,8 +3413,6 @@ static void cfq_put_request(struct request *rq) | |||
3524 | BUG_ON(!cfqq->allocated[rw]); | 3413 | BUG_ON(!cfqq->allocated[rw]); |
3525 | cfqq->allocated[rw]--; | 3414 | cfqq->allocated[rw]--; |
3526 | 3415 | ||
3527 | put_io_context(RQ_CIC(rq)->icq.ioc, cfqq->cfqd->queue); | ||
3528 | |||
3529 | /* Put down rq reference on cfqg */ | 3416 | /* Put down rq reference on cfqg */ |
3530 | cfq_put_cfqg(RQ_CFQG(rq)); | 3417 | cfq_put_cfqg(RQ_CFQG(rq)); |
3531 | rq->elv.priv[0] = NULL; | 3418 | rq->elv.priv[0] = NULL; |
@@ -3574,7 +3461,7 @@ static int | |||
3574 | cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) | 3461 | cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) |
3575 | { | 3462 | { |
3576 | struct cfq_data *cfqd = q->elevator->elevator_data; | 3463 | struct cfq_data *cfqd = q->elevator->elevator_data; |
3577 | struct cfq_io_cq *cic; | 3464 | struct cfq_io_cq *cic = icq_to_cic(rq->elv.icq); |
3578 | const int rw = rq_data_dir(rq); | 3465 | const int rw = rq_data_dir(rq); |
3579 | const bool is_sync = rq_is_sync(rq); | 3466 | const bool is_sync = rq_is_sync(rq); |
3580 | struct cfq_queue *cfqq; | 3467 | struct cfq_queue *cfqq; |
@@ -3582,9 +3469,16 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) | |||
3582 | might_sleep_if(gfp_mask & __GFP_WAIT); | 3469 | might_sleep_if(gfp_mask & __GFP_WAIT); |
3583 | 3470 | ||
3584 | spin_lock_irq(q->queue_lock); | 3471 | spin_lock_irq(q->queue_lock); |
3585 | cic = cfq_get_cic(cfqd, gfp_mask); | 3472 | |
3586 | if (!cic) | 3473 | /* handle changed notifications */ |
3587 | goto queue_fail; | 3474 | if (unlikely(cic->icq.changed)) { |
3475 | if (test_and_clear_bit(ICQ_IOPRIO_CHANGED, &cic->icq.changed)) | ||
3476 | changed_ioprio(cic); | ||
3477 | #ifdef CONFIG_CFQ_GROUP_IOSCHED | ||
3478 | if (test_and_clear_bit(ICQ_CGROUP_CHANGED, &cic->icq.changed)) | ||
3479 | changed_cgroup(cic); | ||
3480 | #endif | ||
3481 | } | ||
3588 | 3482 | ||
3589 | new_queue: | 3483 | new_queue: |
3590 | cfqq = cic_to_cfqq(cic, is_sync); | 3484 | cfqq = cic_to_cfqq(cic, is_sync); |
@@ -3615,17 +3509,10 @@ new_queue: | |||
3615 | cfqq->allocated[rw]++; | 3509 | cfqq->allocated[rw]++; |
3616 | 3510 | ||
3617 | cfqq->ref++; | 3511 | cfqq->ref++; |
3618 | rq->elv.icq = &cic->icq; | ||
3619 | rq->elv.priv[0] = cfqq; | 3512 | rq->elv.priv[0] = cfqq; |
3620 | rq->elv.priv[1] = cfq_ref_get_cfqg(cfqq->cfqg); | 3513 | rq->elv.priv[1] = cfq_ref_get_cfqg(cfqq->cfqg); |
3621 | spin_unlock_irq(q->queue_lock); | 3514 | spin_unlock_irq(q->queue_lock); |
3622 | return 0; | 3515 | return 0; |
3623 | |||
3624 | queue_fail: | ||
3625 | cfq_schedule_dispatch(cfqd); | ||
3626 | spin_unlock_irq(q->queue_lock); | ||
3627 | cfq_log(cfqd, "set_request fail"); | ||
3628 | return 1; | ||
3629 | } | 3516 | } |
3630 | 3517 | ||
3631 | static void cfq_kick_queue(struct work_struct *work) | 3518 | static void cfq_kick_queue(struct work_struct *work) |