xref: /openbmc/linux/block/blk-ioc.c (revision 27667c99)
186db1e29SJens Axboe /*
286db1e29SJens Axboe  * Functions related to io context handling
386db1e29SJens Axboe  */
486db1e29SJens Axboe #include <linux/kernel.h>
586db1e29SJens Axboe #include <linux/module.h>
686db1e29SJens Axboe #include <linux/init.h>
786db1e29SJens Axboe #include <linux/bio.h>
886db1e29SJens Axboe #include <linux/blkdev.h>
986db1e29SJens Axboe #include <linux/bootmem.h>	/* for max_pfn/max_low_pfn */
105a0e3ad6STejun Heo #include <linux/slab.h>
1186db1e29SJens Axboe 
1286db1e29SJens Axboe #include "blk.h"
1386db1e29SJens Axboe 
1486db1e29SJens Axboe /*
1586db1e29SJens Axboe  * For io context allocations
1686db1e29SJens Axboe  */
1786db1e29SJens Axboe static struct kmem_cache *iocontext_cachep;
1886db1e29SJens Axboe 
1986db1e29SJens Axboe static void cfq_dtor(struct io_context *ioc)
2086db1e29SJens Axboe {
21ffc4e759SJens Axboe 	if (!hlist_empty(&ioc->cic_list)) {
22ffc4e759SJens Axboe 		struct cfq_io_context *cic;
2386db1e29SJens Axboe 
24ffc4e759SJens Axboe 		cic = list_entry(ioc->cic_list.first, struct cfq_io_context,
25ffc4e759SJens Axboe 								cic_list);
26ffc4e759SJens Axboe 		cic->dtor(ioc);
27ffc4e759SJens Axboe 	}
2886db1e29SJens Axboe }
2986db1e29SJens Axboe 
3086db1e29SJens Axboe /*
3186db1e29SJens Axboe  * IO Context helper functions. put_io_context() returns 1 if there are no
3286db1e29SJens Axboe  * more users of this io context, 0 otherwise.
3386db1e29SJens Axboe  */
3486db1e29SJens Axboe int put_io_context(struct io_context *ioc)
3586db1e29SJens Axboe {
3686db1e29SJens Axboe 	if (ioc == NULL)
3786db1e29SJens Axboe 		return 1;
3886db1e29SJens Axboe 
39d9c7d394SNikanth Karthikesan 	BUG_ON(atomic_long_read(&ioc->refcount) == 0);
4086db1e29SJens Axboe 
41d9c7d394SNikanth Karthikesan 	if (atomic_long_dec_and_test(&ioc->refcount)) {
4286db1e29SJens Axboe 		rcu_read_lock();
4386db1e29SJens Axboe 		cfq_dtor(ioc);
4407416d29SJens Axboe 		rcu_read_unlock();
4586db1e29SJens Axboe 
4686db1e29SJens Axboe 		kmem_cache_free(iocontext_cachep, ioc);
4786db1e29SJens Axboe 		return 1;
4886db1e29SJens Axboe 	}
4986db1e29SJens Axboe 	return 0;
5086db1e29SJens Axboe }
5186db1e29SJens Axboe EXPORT_SYMBOL(put_io_context);
5286db1e29SJens Axboe 
5386db1e29SJens Axboe static void cfq_exit(struct io_context *ioc)
5486db1e29SJens Axboe {
5586db1e29SJens Axboe 	rcu_read_lock();
5686db1e29SJens Axboe 
57ffc4e759SJens Axboe 	if (!hlist_empty(&ioc->cic_list)) {
58ffc4e759SJens Axboe 		struct cfq_io_context *cic;
59ffc4e759SJens Axboe 
60ffc4e759SJens Axboe 		cic = list_entry(ioc->cic_list.first, struct cfq_io_context,
61ffc4e759SJens Axboe 								cic_list);
62ffc4e759SJens Axboe 		cic->exit(ioc);
63ffc4e759SJens Axboe 	}
64ffc4e759SJens Axboe 	rcu_read_unlock();
6586db1e29SJens Axboe }
6686db1e29SJens Axboe 
6727667c99SBart Van Assche /* Called by the exiting task */
68b69f2292SLouis Rilling void exit_io_context(struct task_struct *task)
6986db1e29SJens Axboe {
7086db1e29SJens Axboe 	struct io_context *ioc;
7186db1e29SJens Axboe 
72b69f2292SLouis Rilling 	task_lock(task);
73b69f2292SLouis Rilling 	ioc = task->io_context;
74b69f2292SLouis Rilling 	task->io_context = NULL;
75b69f2292SLouis Rilling 	task_unlock(task);
7686db1e29SJens Axboe 
7727667c99SBart Van Assche 	if (atomic_dec_and_test(&ioc->nr_tasks))
7886db1e29SJens Axboe 		cfq_exit(ioc);
7986db1e29SJens Axboe 
8061cc74fbSLouis Rilling 	put_io_context(ioc);
8186db1e29SJens Axboe }
8286db1e29SJens Axboe 
8386db1e29SJens Axboe struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
8486db1e29SJens Axboe {
8586db1e29SJens Axboe 	struct io_context *ret;
8686db1e29SJens Axboe 
8786db1e29SJens Axboe 	ret = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node);
8886db1e29SJens Axboe 	if (ret) {
89d9c7d394SNikanth Karthikesan 		atomic_long_set(&ret->refcount, 1);
9086db1e29SJens Axboe 		atomic_set(&ret->nr_tasks, 1);
9186db1e29SJens Axboe 		spin_lock_init(&ret->lock);
9286db1e29SJens Axboe 		ret->ioprio_changed = 0;
9386db1e29SJens Axboe 		ret->ioprio = 0;
944671a132SRichard Kennedy 		ret->last_waited = 0; /* doesn't matter... */
9586db1e29SJens Axboe 		ret->nr_batch_requests = 0; /* because this is 0 */
9686db1e29SJens Axboe 		INIT_RADIX_TREE(&ret->radix_root, GFP_ATOMIC | __GFP_HIGH);
97ffc4e759SJens Axboe 		INIT_HLIST_HEAD(&ret->cic_list);
9886db1e29SJens Axboe 		ret->ioc_data = NULL;
9986db1e29SJens Axboe 	}
10086db1e29SJens Axboe 
10186db1e29SJens Axboe 	return ret;
10286db1e29SJens Axboe }
10386db1e29SJens Axboe 
10486db1e29SJens Axboe /*
10586db1e29SJens Axboe  * If the current task has no IO context then create one and initialise it.
10686db1e29SJens Axboe  * Otherwise, return its existing IO context.
10786db1e29SJens Axboe  *
10886db1e29SJens Axboe  * This returned IO context doesn't have a specifically elevated refcount,
10986db1e29SJens Axboe  * but since the current task itself holds a reference, the context can be
11086db1e29SJens Axboe  * used in general code, so long as it stays within `current` context.
11186db1e29SJens Axboe  */
11286db1e29SJens Axboe struct io_context *current_io_context(gfp_t gfp_flags, int node)
11386db1e29SJens Axboe {
11486db1e29SJens Axboe 	struct task_struct *tsk = current;
11586db1e29SJens Axboe 	struct io_context *ret;
11686db1e29SJens Axboe 
11786db1e29SJens Axboe 	ret = tsk->io_context;
11886db1e29SJens Axboe 	if (likely(ret))
11986db1e29SJens Axboe 		return ret;
12086db1e29SJens Axboe 
12186db1e29SJens Axboe 	ret = alloc_io_context(gfp_flags, node);
12286db1e29SJens Axboe 	if (ret) {
12386db1e29SJens Axboe 		/* make sure set_task_ioprio() sees the settings above */
12486db1e29SJens Axboe 		smp_wmb();
12586db1e29SJens Axboe 		tsk->io_context = ret;
12686db1e29SJens Axboe 	}
12786db1e29SJens Axboe 
12886db1e29SJens Axboe 	return ret;
12986db1e29SJens Axboe }
13086db1e29SJens Axboe 
13186db1e29SJens Axboe /*
13286db1e29SJens Axboe  * If the current task has no IO context then create one and initialise it.
13386db1e29SJens Axboe  * If it does have a context, take a ref on it.
13486db1e29SJens Axboe  *
13586db1e29SJens Axboe  * This is always called in the context of the task which submitted the I/O.
13686db1e29SJens Axboe  */
13786db1e29SJens Axboe struct io_context *get_io_context(gfp_t gfp_flags, int node)
13886db1e29SJens Axboe {
13986db1e29SJens Axboe 	struct io_context *ret = NULL;
14086db1e29SJens Axboe 
14186db1e29SJens Axboe 	/*
14286db1e29SJens Axboe 	 * Check for unlikely race with exiting task. ioc ref count is
14386db1e29SJens Axboe 	 * zero when ioc is being detached.
14486db1e29SJens Axboe 	 */
14586db1e29SJens Axboe 	do {
14686db1e29SJens Axboe 		ret = current_io_context(gfp_flags, node);
14786db1e29SJens Axboe 		if (unlikely(!ret))
14886db1e29SJens Axboe 			break;
149d9c7d394SNikanth Karthikesan 	} while (!atomic_long_inc_not_zero(&ret->refcount));
15086db1e29SJens Axboe 
15186db1e29SJens Axboe 	return ret;
15286db1e29SJens Axboe }
15386db1e29SJens Axboe EXPORT_SYMBOL(get_io_context);
15486db1e29SJens Axboe 
15513341598SAdrian Bunk static int __init blk_ioc_init(void)
15686db1e29SJens Axboe {
15786db1e29SJens Axboe 	iocontext_cachep = kmem_cache_create("blkdev_ioc",
15886db1e29SJens Axboe 			sizeof(struct io_context), 0, SLAB_PANIC, NULL);
15986db1e29SJens Axboe 	return 0;
16086db1e29SJens Axboe }
16186db1e29SJens Axboe subsys_initcall(blk_ioc_init);
162