diff options
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r-- | block/cfq-iosched.c | 101 |
1 files changed, 79 insertions, 22 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index ed897b5ef315..5ff4f4850e71 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -64,6 +64,9 @@ static DEFINE_PER_CPU(unsigned long, cfq_ioc_count); | |||
64 | static struct completion *ioc_gone; | 64 | static struct completion *ioc_gone; |
65 | static DEFINE_SPINLOCK(ioc_gone_lock); | 65 | static DEFINE_SPINLOCK(ioc_gone_lock); |
66 | 66 | ||
67 | static DEFINE_SPINLOCK(cic_index_lock); | ||
68 | static DEFINE_IDA(cic_index_ida); | ||
69 | |||
67 | #define CFQ_PRIO_LISTS IOPRIO_BE_NR | 70 | #define CFQ_PRIO_LISTS IOPRIO_BE_NR |
68 | #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) | 71 | #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) |
69 | #define cfq_class_rt(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_RT) | 72 | #define cfq_class_rt(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_RT) |
@@ -271,6 +274,7 @@ struct cfq_data { | |||
271 | unsigned int cfq_latency; | 274 | unsigned int cfq_latency; |
272 | unsigned int cfq_group_isolation; | 275 | unsigned int cfq_group_isolation; |
273 | 276 | ||
277 | unsigned int cic_index; | ||
274 | struct list_head cic_list; | 278 | struct list_head cic_list; |
275 | 279 | ||
276 | /* | 280 | /* |
@@ -430,6 +434,24 @@ static inline void cic_set_cfqq(struct cfq_io_context *cic, | |||
430 | cic->cfqq[is_sync] = cfqq; | 434 | cic->cfqq[is_sync] = cfqq; |
431 | } | 435 | } |
432 | 436 | ||
437 | #define CIC_DEAD_KEY 1ul | ||
438 | #define CIC_DEAD_INDEX_SHIFT 1 | ||
439 | |||
440 | static inline void *cfqd_dead_key(struct cfq_data *cfqd) | ||
441 | { | ||
442 | return (void *)(cfqd->cic_index << CIC_DEAD_INDEX_SHIFT | CIC_DEAD_KEY); | ||
443 | } | ||
444 | |||
445 | static inline struct cfq_data *cic_to_cfqd(struct cfq_io_context *cic) | ||
446 | { | ||
447 | struct cfq_data *cfqd = cic->key; | ||
448 | |||
449 | if (unlikely((unsigned long) cfqd & CIC_DEAD_KEY)) | ||
450 | return NULL; | ||
451 | |||
452 | return cfqd; | ||
453 | } | ||
454 | |||
433 | /* | 455 | /* |
434 | * We regard a request as SYNC, if it's either a read or has the SYNC bit | 456 | * We regard a request as SYNC, if it's either a read or has the SYNC bit |
435 | * set (in which case it could also be direct WRITE). | 457 | * set (in which case it could also be direct WRITE). |
@@ -2510,11 +2532,12 @@ static void cfq_cic_free(struct cfq_io_context *cic) | |||
2510 | static void cic_free_func(struct io_context *ioc, struct cfq_io_context *cic) | 2532 | static void cic_free_func(struct io_context *ioc, struct cfq_io_context *cic) |
2511 | { | 2533 | { |
2512 | unsigned long flags; | 2534 | unsigned long flags; |
2535 | unsigned long dead_key = (unsigned long) cic->key; | ||
2513 | 2536 | ||
2514 | BUG_ON(!cic->dead_key); | 2537 | BUG_ON(!(dead_key & CIC_DEAD_KEY)); |
2515 | 2538 | ||
2516 | spin_lock_irqsave(&ioc->lock, flags); | 2539 | spin_lock_irqsave(&ioc->lock, flags); |
2517 | radix_tree_delete(&ioc->radix_root, cic->dead_key); | 2540 | radix_tree_delete(&ioc->radix_root, dead_key >> CIC_DEAD_INDEX_SHIFT); |
2518 | hlist_del_rcu(&cic->cic_list); | 2541 | hlist_del_rcu(&cic->cic_list); |
2519 | spin_unlock_irqrestore(&ioc->lock, flags); | 2542 | spin_unlock_irqrestore(&ioc->lock, flags); |
2520 | 2543 | ||
@@ -2537,15 +2560,10 @@ static void cfq_free_io_context(struct io_context *ioc) | |||
2537 | __call_for_each_cic(ioc, cic_free_func); | 2560 | __call_for_each_cic(ioc, cic_free_func); |
2538 | } | 2561 | } |
2539 | 2562 | ||
2540 | static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) | 2563 | static void cfq_put_cooperator(struct cfq_queue *cfqq) |
2541 | { | 2564 | { |
2542 | struct cfq_queue *__cfqq, *next; | 2565 | struct cfq_queue *__cfqq, *next; |
2543 | 2566 | ||
2544 | if (unlikely(cfqq == cfqd->active_queue)) { | ||
2545 | __cfq_slice_expired(cfqd, cfqq, 0); | ||
2546 | cfq_schedule_dispatch(cfqd); | ||
2547 | } | ||
2548 | |||
2549 | /* | 2567 | /* |
2550 | * If this queue was scheduled to merge with another queue, be | 2568 | * If this queue was scheduled to merge with another queue, be |
2551 | * sure to drop the reference taken on that queue (and others in | 2569 | * sure to drop the reference taken on that queue (and others in |
@@ -2561,6 +2579,16 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
2561 | cfq_put_queue(__cfqq); | 2579 | cfq_put_queue(__cfqq); |
2562 | __cfqq = next; | 2580 | __cfqq = next; |
2563 | } | 2581 | } |
2582 | } | ||
2583 | |||
2584 | static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) | ||
2585 | { | ||
2586 | if (unlikely(cfqq == cfqd->active_queue)) { | ||
2587 | __cfq_slice_expired(cfqd, cfqq, 0); | ||
2588 | cfq_schedule_dispatch(cfqd); | ||
2589 | } | ||
2590 | |||
2591 | cfq_put_cooperator(cfqq); | ||
2564 | 2592 | ||
2565 | cfq_put_queue(cfqq); | 2593 | cfq_put_queue(cfqq); |
2566 | } | 2594 | } |
@@ -2573,11 +2601,10 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd, | |||
2573 | list_del_init(&cic->queue_list); | 2601 | list_del_init(&cic->queue_list); |
2574 | 2602 | ||
2575 | /* | 2603 | /* |
2576 | * Make sure key == NULL is seen for dead queues | 2604 | * Make sure dead mark is seen for dead queues |
2577 | */ | 2605 | */ |
2578 | smp_wmb(); | 2606 | smp_wmb(); |
2579 | cic->dead_key = (unsigned long) cic->key; | 2607 | cic->key = cfqd_dead_key(cfqd); |
2580 | cic->key = NULL; | ||
2581 | 2608 | ||
2582 | if (ioc->ioc_data == cic) | 2609 | if (ioc->ioc_data == cic) |
2583 | rcu_assign_pointer(ioc->ioc_data, NULL); | 2610 | rcu_assign_pointer(ioc->ioc_data, NULL); |
@@ -2596,7 +2623,7 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd, | |||
2596 | static void cfq_exit_single_io_context(struct io_context *ioc, | 2623 | static void cfq_exit_single_io_context(struct io_context *ioc, |
2597 | struct cfq_io_context *cic) | 2624 | struct cfq_io_context *cic) |
2598 | { | 2625 | { |
2599 | struct cfq_data *cfqd = cic->key; | 2626 | struct cfq_data *cfqd = cic_to_cfqd(cic); |
2600 | 2627 | ||
2601 | if (cfqd) { | 2628 | if (cfqd) { |
2602 | struct request_queue *q = cfqd->queue; | 2629 | struct request_queue *q = cfqd->queue; |
@@ -2609,7 +2636,7 @@ static void cfq_exit_single_io_context(struct io_context *ioc, | |||
2609 | * race between exiting task and queue | 2636 | * race between exiting task and queue |
2610 | */ | 2637 | */ |
2611 | smp_read_barrier_depends(); | 2638 | smp_read_barrier_depends(); |
2612 | if (cic->key) | 2639 | if (cic->key == cfqd) |
2613 | __cfq_exit_single_io_context(cfqd, cic); | 2640 | __cfq_exit_single_io_context(cfqd, cic); |
2614 | 2641 | ||
2615 | spin_unlock_irqrestore(q->queue_lock, flags); | 2642 | spin_unlock_irqrestore(q->queue_lock, flags); |
@@ -2689,7 +2716,7 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc) | |||
2689 | 2716 | ||
2690 | static void changed_ioprio(struct io_context *ioc, struct cfq_io_context *cic) | 2717 | static void changed_ioprio(struct io_context *ioc, struct cfq_io_context *cic) |
2691 | { | 2718 | { |
2692 | struct cfq_data *cfqd = cic->key; | 2719 | struct cfq_data *cfqd = cic_to_cfqd(cic); |
2693 | struct cfq_queue *cfqq; | 2720 | struct cfq_queue *cfqq; |
2694 | unsigned long flags; | 2721 | unsigned long flags; |
2695 | 2722 | ||
@@ -2746,7 +2773,7 @@ static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
2746 | static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic) | 2773 | static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic) |
2747 | { | 2774 | { |
2748 | struct cfq_queue *sync_cfqq = cic_to_cfqq(cic, 1); | 2775 | struct cfq_queue *sync_cfqq = cic_to_cfqq(cic, 1); |
2749 | struct cfq_data *cfqd = cic->key; | 2776 | struct cfq_data *cfqd = cic_to_cfqd(cic); |
2750 | unsigned long flags; | 2777 | unsigned long flags; |
2751 | struct request_queue *q; | 2778 | struct request_queue *q; |
2752 | 2779 | ||
@@ -2883,12 +2910,13 @@ cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc, | |||
2883 | unsigned long flags; | 2910 | unsigned long flags; |
2884 | 2911 | ||
2885 | WARN_ON(!list_empty(&cic->queue_list)); | 2912 | WARN_ON(!list_empty(&cic->queue_list)); |
2913 | BUG_ON(cic->key != cfqd_dead_key(cfqd)); | ||
2886 | 2914 | ||
2887 | spin_lock_irqsave(&ioc->lock, flags); | 2915 | spin_lock_irqsave(&ioc->lock, flags); |
2888 | 2916 | ||
2889 | BUG_ON(ioc->ioc_data == cic); | 2917 | BUG_ON(ioc->ioc_data == cic); |
2890 | 2918 | ||
2891 | radix_tree_delete(&ioc->radix_root, (unsigned long) cfqd); | 2919 | radix_tree_delete(&ioc->radix_root, cfqd->cic_index); |
2892 | hlist_del_rcu(&cic->cic_list); | 2920 | hlist_del_rcu(&cic->cic_list); |
2893 | spin_unlock_irqrestore(&ioc->lock, flags); | 2921 | spin_unlock_irqrestore(&ioc->lock, flags); |
2894 | 2922 | ||
@@ -2900,7 +2928,6 @@ cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc) | |||
2900 | { | 2928 | { |
2901 | struct cfq_io_context *cic; | 2929 | struct cfq_io_context *cic; |
2902 | unsigned long flags; | 2930 | unsigned long flags; |
2903 | void *k; | ||
2904 | 2931 | ||
2905 | if (unlikely(!ioc)) | 2932 | if (unlikely(!ioc)) |
2906 | return NULL; | 2933 | return NULL; |
@@ -2917,13 +2944,11 @@ cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc) | |||
2917 | } | 2944 | } |
2918 | 2945 | ||
2919 | do { | 2946 | do { |
2920 | cic = radix_tree_lookup(&ioc->radix_root, (unsigned long) cfqd); | 2947 | cic = radix_tree_lookup(&ioc->radix_root, cfqd->cic_index); |
2921 | rcu_read_unlock(); | 2948 | rcu_read_unlock(); |
2922 | if (!cic) | 2949 | if (!cic) |
2923 | break; | 2950 | break; |
2924 | /* ->key must be copied to avoid race with cfq_exit_queue() */ | 2951 | if (unlikely(cic->key != cfqd)) { |
2925 | k = cic->key; | ||
2926 | if (unlikely(!k)) { | ||
2927 | cfq_drop_dead_cic(cfqd, ioc, cic); | 2952 | cfq_drop_dead_cic(cfqd, ioc, cic); |
2928 | rcu_read_lock(); | 2953 | rcu_read_lock(); |
2929 | continue; | 2954 | continue; |
@@ -2956,7 +2981,7 @@ static int cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc, | |||
2956 | 2981 | ||
2957 | spin_lock_irqsave(&ioc->lock, flags); | 2982 | spin_lock_irqsave(&ioc->lock, flags); |
2958 | ret = radix_tree_insert(&ioc->radix_root, | 2983 | ret = radix_tree_insert(&ioc->radix_root, |
2959 | (unsigned long) cfqd, cic); | 2984 | cfqd->cic_index, cic); |
2960 | if (!ret) | 2985 | if (!ret) |
2961 | hlist_add_head_rcu(&cic->cic_list, &ioc->cic_list); | 2986 | hlist_add_head_rcu(&cic->cic_list, &ioc->cic_list); |
2962 | spin_unlock_irqrestore(&ioc->lock, flags); | 2987 | spin_unlock_irqrestore(&ioc->lock, flags); |
@@ -3516,6 +3541,9 @@ split_cfqq(struct cfq_io_context *cic, struct cfq_queue *cfqq) | |||
3516 | } | 3541 | } |
3517 | 3542 | ||
3518 | cic_set_cfqq(cic, NULL, 1); | 3543 | cic_set_cfqq(cic, NULL, 1); |
3544 | |||
3545 | cfq_put_cooperator(cfqq); | ||
3546 | |||
3519 | cfq_put_queue(cfqq); | 3547 | cfq_put_queue(cfqq); |
3520 | return NULL; | 3548 | return NULL; |
3521 | } | 3549 | } |
@@ -3708,10 +3736,32 @@ static void cfq_exit_queue(struct elevator_queue *e) | |||
3708 | 3736 | ||
3709 | cfq_shutdown_timer_wq(cfqd); | 3737 | cfq_shutdown_timer_wq(cfqd); |
3710 | 3738 | ||
3739 | spin_lock(&cic_index_lock); | ||
3740 | ida_remove(&cic_index_ida, cfqd->cic_index); | ||
3741 | spin_unlock(&cic_index_lock); | ||
3742 | |||
3711 | /* Wait for cfqg->blkg->key accessors to exit their grace periods. */ | 3743 | /* Wait for cfqg->blkg->key accessors to exit their grace periods. */ |
3712 | call_rcu(&cfqd->rcu, cfq_cfqd_free); | 3744 | call_rcu(&cfqd->rcu, cfq_cfqd_free); |
3713 | } | 3745 | } |
3714 | 3746 | ||
3747 | static int cfq_alloc_cic_index(void) | ||
3748 | { | ||
3749 | int index, error; | ||
3750 | |||
3751 | do { | ||
3752 | if (!ida_pre_get(&cic_index_ida, GFP_KERNEL)) | ||
3753 | return -ENOMEM; | ||
3754 | |||
3755 | spin_lock(&cic_index_lock); | ||
3756 | error = ida_get_new(&cic_index_ida, &index); | ||
3757 | spin_unlock(&cic_index_lock); | ||
3758 | if (error && error != -EAGAIN) | ||
3759 | return error; | ||
3760 | } while (error); | ||
3761 | |||
3762 | return index; | ||
3763 | } | ||
3764 | |||
3715 | static void *cfq_init_queue(struct request_queue *q) | 3765 | static void *cfq_init_queue(struct request_queue *q) |
3716 | { | 3766 | { |
3717 | struct cfq_data *cfqd; | 3767 | struct cfq_data *cfqd; |
@@ -3719,10 +3769,16 @@ static void *cfq_init_queue(struct request_queue *q) | |||
3719 | struct cfq_group *cfqg; | 3769 | struct cfq_group *cfqg; |
3720 | struct cfq_rb_root *st; | 3770 | struct cfq_rb_root *st; |
3721 | 3771 | ||
3772 | i = cfq_alloc_cic_index(); | ||
3773 | if (i < 0) | ||
3774 | return NULL; | ||
3775 | |||
3722 | cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node); | 3776 | cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node); |
3723 | if (!cfqd) | 3777 | if (!cfqd) |
3724 | return NULL; | 3778 | return NULL; |
3725 | 3779 | ||
3780 | cfqd->cic_index = i; | ||
3781 | |||
3726 | /* Init root service tree */ | 3782 | /* Init root service tree */ |
3727 | cfqd->grp_service_tree = CFQ_RB_ROOT; | 3783 | cfqd->grp_service_tree = CFQ_RB_ROOT; |
3728 | 3784 | ||
@@ -3984,6 +4040,7 @@ static void __exit cfq_exit(void) | |||
3984 | */ | 4040 | */ |
3985 | if (elv_ioc_count_read(cfq_ioc_count)) | 4041 | if (elv_ioc_count_read(cfq_ioc_count)) |
3986 | wait_for_completion(&all_gone); | 4042 | wait_for_completion(&all_gone); |
4043 | ida_destroy(&cic_index_ida); | ||
3987 | cfq_slab_kill(); | 4044 | cfq_slab_kill(); |
3988 | } | 4045 | } |
3989 | 4046 | ||