diff options
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r-- | block/cfq-iosched.c | 92 |
1 files changed, 10 insertions, 82 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 6cc60656040..ff44435fad5 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -2669,24 +2669,6 @@ static void cfq_put_queue(struct cfq_queue *cfqq) cfq_put_cfqg(cfqg); } -/* - * Call func for each cic attached to this ioc. - */ -static void -call_for_each_cic(struct io_context *ioc, - void (*func)(struct io_context *, struct cfq_io_context *)) -{ - struct cfq_io_context *cic; - struct hlist_node *n; - - rcu_read_lock(); - - hlist_for_each_entry_rcu(cic, n, &ioc->cic_list, cic_list) - func(ioc, cic); - - rcu_read_unlock(); -} - static void cfq_cic_free_rcu(struct rcu_head *head) { struct cfq_io_context *cic; @@ -2727,31 +2709,6 @@ static void cfq_release_cic(struct cfq_io_context *cic) cfq_cic_free(cic); } -static void cic_free_func(struct io_context *ioc, struct cfq_io_context *cic) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->lock, flags); - cfq_release_cic(cic); - spin_unlock_irqrestore(&ioc->lock, flags); -} - -/* - * Must be called with rcu_read_lock() held or preemption otherwise disabled. - * Only two callers of this - ->dtor() which is called with the rcu_read_lock(), - * and ->trim() which is called with the task lock held - */ -static void cfq_free_io_context(struct io_context *ioc) -{ - /* - * ioc->refcount is zero here, or we are called from elv_unregister(), - * so no more cic's are allowed to be linked into this ioc. So it - * should be ok to iterate over the known list, we will see all cic's - * since no new ones are added. - */ - call_for_each_cic(ioc, cic_free_func); -} - static void cfq_put_cooperator(struct cfq_queue *cfqq) { struct cfq_queue *__cfqq, *next; @@ -3037,30 +2994,6 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct io_context *ioc, return cfqq; } -/* - * We drop cfq io contexts lazily, so we may find a dead one. - */ -static void -cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc, - struct cfq_io_context *cic) -{ - unsigned long flags; - - WARN_ON(!list_empty(&cic->queue_list)); - BUG_ON(cic->key != cfqd_dead_key(cfqd)); - - spin_lock_irqsave(&ioc->lock, flags); - - BUG_ON(rcu_dereference_check(ioc->ioc_data, - lockdep_is_held(&ioc->lock)) == cic); - - radix_tree_delete(&ioc->radix_root, cfqd->queue->id); - hlist_del_rcu(&cic->cic_list); - spin_unlock_irqrestore(&ioc->lock, flags); - - cfq_cic_free(cic); -} - /** * cfq_cic_lookup - lookup cfq_io_context * @cfqd: the associated cfq_data @@ -3078,26 +3011,22 @@ cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc) if (unlikely(!ioc)) return NULL; - rcu_read_lock(); - /* - * we maintain a last-hit cache, to avoid browsing over the tree + * cic's are indexed from @ioc using radix tree and hint pointer, + * both of which are protected with RCU. All removals are done + * holding both q and ioc locks, and we're holding q lock - if we + * find a cic which points to us, it's guaranteed to be valid. */ + rcu_read_lock(); cic = rcu_dereference(ioc->ioc_data); if (cic && cic->key == cfqd) goto out; - do { - cic = radix_tree_lookup(&ioc->radix_root, cfqd->queue->id); - if (!cic) - break; - if (likely(cic->key == cfqd)) { - /* hint assignment itself can race safely */ - rcu_assign_pointer(ioc->ioc_data, cic); - break; - } - cfq_drop_dead_cic(cfqd, ioc, cic); - } while (1); + cic = radix_tree_lookup(&ioc->radix_root, cfqd->queue->id); + if (cic && cic->key == cfqd) + rcu_assign_pointer(ioc->ioc_data, cic); /* allowed to race */ + else + cic = NULL; out: rcu_read_unlock(); return cic; @@ -4182,7 +4111,6 @@ static struct elevator_type iosched_cfq = { .elevator_may_queue_fn = cfq_may_queue, .elevator_init_fn = cfq_init_queue, .elevator_exit_fn = cfq_exit_queue, - .trim = cfq_free_io_context, }, .elevator_attrs = cfq_attrs, .elevator_name = "cfq", |