diff options
| -rw-r--r-- | block/cfq-iosched.c | 92 | ||||
| -rw-r--r-- | block/elevator.c | 16 | ||||
| -rw-r--r-- | include/linux/elevator.h | 1 |
3 files changed, 10 insertions, 99 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 6cc606560402..ff44435fad50 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
| @@ -2669,24 +2669,6 @@ static void cfq_put_queue(struct cfq_queue *cfqq) | |||
| 2669 | cfq_put_cfqg(cfqg); | 2669 | cfq_put_cfqg(cfqg); |
| 2670 | } | 2670 | } |
| 2671 | 2671 | ||
| 2672 | /* | ||
| 2673 | * Call func for each cic attached to this ioc. | ||
| 2674 | */ | ||
| 2675 | static void | ||
| 2676 | call_for_each_cic(struct io_context *ioc, | ||
| 2677 | void (*func)(struct io_context *, struct cfq_io_context *)) | ||
| 2678 | { | ||
| 2679 | struct cfq_io_context *cic; | ||
| 2680 | struct hlist_node *n; | ||
| 2681 | |||
| 2682 | rcu_read_lock(); | ||
| 2683 | |||
| 2684 | hlist_for_each_entry_rcu(cic, n, &ioc->cic_list, cic_list) | ||
| 2685 | func(ioc, cic); | ||
| 2686 | |||
| 2687 | rcu_read_unlock(); | ||
| 2688 | } | ||
| 2689 | |||
| 2690 | static void cfq_cic_free_rcu(struct rcu_head *head) | 2672 | static void cfq_cic_free_rcu(struct rcu_head *head) |
| 2691 | { | 2673 | { |
| 2692 | struct cfq_io_context *cic; | 2674 | struct cfq_io_context *cic; |
| @@ -2727,31 +2709,6 @@ static void cfq_release_cic(struct cfq_io_context *cic) | |||
| 2727 | cfq_cic_free(cic); | 2709 | cfq_cic_free(cic); |
| 2728 | } | 2710 | } |
| 2729 | 2711 | ||
| 2730 | static void cic_free_func(struct io_context *ioc, struct cfq_io_context *cic) | ||
| 2731 | { | ||
| 2732 | unsigned long flags; | ||
| 2733 | |||
| 2734 | spin_lock_irqsave(&ioc->lock, flags); | ||
| 2735 | cfq_release_cic(cic); | ||
| 2736 | spin_unlock_irqrestore(&ioc->lock, flags); | ||
| 2737 | } | ||
| 2738 | |||
| 2739 | /* | ||
| 2740 | * Must be called with rcu_read_lock() held or preemption otherwise disabled. | ||
| 2741 | * Only two callers of this - ->dtor() which is called with the rcu_read_lock(), | ||
| 2742 | * and ->trim() which is called with the task lock held | ||
| 2743 | */ | ||
| 2744 | static void cfq_free_io_context(struct io_context *ioc) | ||
| 2745 | { | ||
| 2746 | /* | ||
| 2747 | * ioc->refcount is zero here, or we are called from elv_unregister(), | ||
| 2748 | * so no more cic's are allowed to be linked into this ioc. So it | ||
| 2749 | * should be ok to iterate over the known list, we will see all cic's | ||
| 2750 | * since no new ones are added. | ||
| 2751 | */ | ||
| 2752 | call_for_each_cic(ioc, cic_free_func); | ||
| 2753 | } | ||
| 2754 | |||
| 2755 | static void cfq_put_cooperator(struct cfq_queue *cfqq) | 2712 | static void cfq_put_cooperator(struct cfq_queue *cfqq) |
| 2756 | { | 2713 | { |
| 2757 | struct cfq_queue *__cfqq, *next; | 2714 | struct cfq_queue *__cfqq, *next; |
| @@ -3037,30 +2994,6 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct io_context *ioc, | |||
| 3037 | return cfqq; | 2994 | return cfqq; |
| 3038 | } | 2995 | } |
| 3039 | 2996 | ||
| 3040 | /* | ||
| 3041 | * We drop cfq io contexts lazily, so we may find a dead one. | ||
| 3042 | */ | ||
| 3043 | static void | ||
| 3044 | cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc, | ||
| 3045 | struct cfq_io_context *cic) | ||
| 3046 | { | ||
| 3047 | unsigned long flags; | ||
| 3048 | |||
| 3049 | WARN_ON(!list_empty(&cic->queue_list)); | ||
| 3050 | BUG_ON(cic->key != cfqd_dead_key(cfqd)); | ||
| 3051 | |||
| 3052 | spin_lock_irqsave(&ioc->lock, flags); | ||
| 3053 | |||
| 3054 | BUG_ON(rcu_dereference_check(ioc->ioc_data, | ||
| 3055 | lockdep_is_held(&ioc->lock)) == cic); | ||
| 3056 | |||
| 3057 | radix_tree_delete(&ioc->radix_root, cfqd->queue->id); | ||
| 3058 | hlist_del_rcu(&cic->cic_list); | ||
| 3059 | spin_unlock_irqrestore(&ioc->lock, flags); | ||
| 3060 | |||
| 3061 | cfq_cic_free(cic); | ||
| 3062 | } | ||
| 3063 | |||
| 3064 | /** | 2997 | /** |
| 3065 | * cfq_cic_lookup - lookup cfq_io_context | 2998 | * cfq_cic_lookup - lookup cfq_io_context |
| 3066 | * @cfqd: the associated cfq_data | 2999 | * @cfqd: the associated cfq_data |
| @@ -3078,26 +3011,22 @@ cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc) | |||
| 3078 | if (unlikely(!ioc)) | 3011 | if (unlikely(!ioc)) |
| 3079 | return NULL; | 3012 | return NULL; |
| 3080 | 3013 | ||
| 3081 | rcu_read_lock(); | ||
| 3082 | |||
| 3083 | /* | 3014 | /* |
| 3084 | * we maintain a last-hit cache, to avoid browsing over the tree | 3015 | * cic's are indexed from @ioc using radix tree and hint pointer, |
| 3016 | * both of which are protected with RCU. All removals are done | ||
| 3017 | * holding both q and ioc locks, and we're holding q lock - if we | ||
| 3018 | * find a cic which points to us, it's guaranteed to be valid. | ||
| 3085 | */ | 3019 | */ |
| 3020 | rcu_read_lock(); | ||
| 3086 | cic = rcu_dereference(ioc->ioc_data); | 3021 | cic = rcu_dereference(ioc->ioc_data); |
| 3087 | if (cic && cic->key == cfqd) | 3022 | if (cic && cic->key == cfqd) |
| 3088 | goto out; | 3023 | goto out; |
| 3089 | 3024 | ||
| 3090 | do { | 3025 | cic = radix_tree_lookup(&ioc->radix_root, cfqd->queue->id); |
| 3091 | cic = radix_tree_lookup(&ioc->radix_root, cfqd->queue->id); | 3026 | if (cic && cic->key == cfqd) |
| 3092 | if (!cic) | 3027 | rcu_assign_pointer(ioc->ioc_data, cic); /* allowed to race */ |
| 3093 | break; | 3028 | else |
| 3094 | if (likely(cic->key == cfqd)) { | 3029 | cic = NULL; |
| 3095 | /* hint assignment itself can race safely */ | ||
| 3096 | rcu_assign_pointer(ioc->ioc_data, cic); | ||
| 3097 | break; | ||
| 3098 | } | ||
| 3099 | cfq_drop_dead_cic(cfqd, ioc, cic); | ||
| 3100 | } while (1); | ||
| 3101 | out: | 3030 | out: |
| 3102 | rcu_read_unlock(); | 3031 | rcu_read_unlock(); |
| 3103 | return cic; | 3032 | return cic; |
| @@ -4182,7 +4111,6 @@ static struct elevator_type iosched_cfq = { | |||
| 4182 | .elevator_may_queue_fn = cfq_may_queue, | 4111 | .elevator_may_queue_fn = cfq_may_queue, |
| 4183 | .elevator_init_fn = cfq_init_queue, | 4112 | .elevator_init_fn = cfq_init_queue, |
| 4184 | .elevator_exit_fn = cfq_exit_queue, | 4113 | .elevator_exit_fn = cfq_exit_queue, |
| 4185 | .trim = cfq_free_io_context, | ||
| 4186 | }, | 4114 | }, |
| 4187 | .elevator_attrs = cfq_attrs, | 4115 | .elevator_attrs = cfq_attrs, |
| 4188 | .elevator_name = "cfq", | 4116 | .elevator_name = "cfq", |
diff --git a/block/elevator.c b/block/elevator.c index 66343d6917d0..6a343e8f8319 100644 --- a/block/elevator.c +++ b/block/elevator.c | |||
| @@ -913,22 +913,6 @@ EXPORT_SYMBOL_GPL(elv_register); | |||
| 913 | 913 | ||
| 914 | void elv_unregister(struct elevator_type *e) | 914 | void elv_unregister(struct elevator_type *e) |
| 915 | { | 915 | { |
| 916 | struct task_struct *g, *p; | ||
| 917 | |||
| 918 | /* | ||
| 919 | * Iterate every thread in the process to remove the io contexts. | ||
| 920 | */ | ||
| 921 | if (e->ops.trim) { | ||
| 922 | read_lock(&tasklist_lock); | ||
| 923 | do_each_thread(g, p) { | ||
| 924 | task_lock(p); | ||
| 925 | if (p->io_context) | ||
| 926 | e->ops.trim(p->io_context); | ||
| 927 | task_unlock(p); | ||
| 928 | } while_each_thread(g, p); | ||
| 929 | read_unlock(&tasklist_lock); | ||
| 930 | } | ||
| 931 | |||
| 932 | spin_lock(&elv_list_lock); | 916 | spin_lock(&elv_list_lock); |
| 933 | list_del_init(&e->list); | 917 | list_del_init(&e->list); |
| 934 | spin_unlock(&elv_list_lock); | 918 | spin_unlock(&elv_list_lock); |
diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 1d0f7a2ff73b..581dd1bd3d3e 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h | |||
| @@ -63,7 +63,6 @@ struct elevator_ops | |||
| 63 | 63 | ||
| 64 | elevator_init_fn *elevator_init_fn; | 64 | elevator_init_fn *elevator_init_fn; |
| 65 | elevator_exit_fn *elevator_exit_fn; | 65 | elevator_exit_fn *elevator_exit_fn; |
| 66 | void (*trim)(struct io_context *); | ||
| 67 | }; | 66 | }; |
| 68 | 67 | ||
| 69 | #define ELV_NAME_MAX (16) | 68 | #define ELV_NAME_MAX (16) |
