xref: /openbmc/linux/block/blk-ioc.c (revision b69f2292)
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 */
1086db1e29SJens Axboe 
1186db1e29SJens Axboe #include "blk.h"
1286db1e29SJens Axboe 
1386db1e29SJens Axboe /*
1486db1e29SJens Axboe  * For io context allocations
1586db1e29SJens Axboe  */
1686db1e29SJens Axboe static struct kmem_cache *iocontext_cachep;
1786db1e29SJens Axboe 
1886db1e29SJens Axboe static void cfq_dtor(struct io_context *ioc)
1986db1e29SJens Axboe {
20ffc4e759SJens Axboe 	if (!hlist_empty(&ioc->cic_list)) {
21ffc4e759SJens Axboe 		struct cfq_io_context *cic;
2286db1e29SJens Axboe 
23ffc4e759SJens Axboe 		cic = list_entry(ioc->cic_list.first, struct cfq_io_context,
24ffc4e759SJens Axboe 								cic_list);
25ffc4e759SJens Axboe 		cic->dtor(ioc);
26ffc4e759SJens Axboe 	}
2786db1e29SJens Axboe }
2886db1e29SJens Axboe 
2986db1e29SJens Axboe /*
3086db1e29SJens Axboe  * IO Context helper functions. put_io_context() returns 1 if there are no
3186db1e29SJens Axboe  * more users of this io context, 0 otherwise.
3286db1e29SJens Axboe  */
3386db1e29SJens Axboe int put_io_context(struct io_context *ioc)
3486db1e29SJens Axboe {
3586db1e29SJens Axboe 	if (ioc == NULL)
3686db1e29SJens Axboe 		return 1;
3786db1e29SJens Axboe 
38d9c7d394SNikanth Karthikesan 	BUG_ON(atomic_long_read(&ioc->refcount) == 0);
3986db1e29SJens Axboe 
40d9c7d394SNikanth Karthikesan 	if (atomic_long_dec_and_test(&ioc->refcount)) {
4186db1e29SJens Axboe 		rcu_read_lock();
4286db1e29SJens Axboe 		if (ioc->aic && ioc->aic->dtor)
4386db1e29SJens Axboe 			ioc->aic->dtor(ioc->aic);
4486db1e29SJens Axboe 		cfq_dtor(ioc);
4507416d29SJens Axboe 		rcu_read_unlock();
4686db1e29SJens Axboe 
4786db1e29SJens Axboe 		kmem_cache_free(iocontext_cachep, ioc);
4886db1e29SJens Axboe 		return 1;
4986db1e29SJens Axboe 	}
5086db1e29SJens Axboe 	return 0;
5186db1e29SJens Axboe }
5286db1e29SJens Axboe EXPORT_SYMBOL(put_io_context);
5386db1e29SJens Axboe 
5486db1e29SJens Axboe static void cfq_exit(struct io_context *ioc)
5586db1e29SJens Axboe {
5686db1e29SJens Axboe 	rcu_read_lock();
5786db1e29SJens Axboe 
58ffc4e759SJens Axboe 	if (!hlist_empty(&ioc->cic_list)) {
59ffc4e759SJens Axboe 		struct cfq_io_context *cic;
60ffc4e759SJens Axboe 
61ffc4e759SJens Axboe 		cic = list_entry(ioc->cic_list.first, struct cfq_io_context,
62ffc4e759SJens Axboe 								cic_list);
63ffc4e759SJens Axboe 		cic->exit(ioc);
64ffc4e759SJens Axboe 	}
65ffc4e759SJens Axboe 	rcu_read_unlock();
6686db1e29SJens Axboe }
6786db1e29SJens Axboe 
6886db1e29SJens Axboe /* Called by the exitting task */
69b69f2292SLouis Rilling void exit_io_context(struct task_struct *task)
7086db1e29SJens Axboe {
7186db1e29SJens Axboe 	struct io_context *ioc;
7286db1e29SJens Axboe 
73b69f2292SLouis Rilling 	task_lock(task);
74b69f2292SLouis Rilling 	ioc = task->io_context;
75b69f2292SLouis Rilling 	task->io_context = NULL;
76b69f2292SLouis Rilling 	task_unlock(task);
7786db1e29SJens Axboe 
7886db1e29SJens Axboe 	if (atomic_dec_and_test(&ioc->nr_tasks)) {
7986db1e29SJens Axboe 		if (ioc->aic && ioc->aic->exit)
8086db1e29SJens Axboe 			ioc->aic->exit(ioc->aic);
8186db1e29SJens Axboe 		cfq_exit(ioc);
8286db1e29SJens Axboe 
8386db1e29SJens Axboe 	}
8461cc74fbSLouis Rilling 	put_io_context(ioc);
8586db1e29SJens Axboe }
8686db1e29SJens Axboe 
8786db1e29SJens Axboe struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
8886db1e29SJens Axboe {
8986db1e29SJens Axboe 	struct io_context *ret;
9086db1e29SJens Axboe 
9186db1e29SJens Axboe 	ret = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node);
9286db1e29SJens Axboe 	if (ret) {
93d9c7d394SNikanth Karthikesan 		atomic_long_set(&ret->refcount, 1);
9486db1e29SJens Axboe 		atomic_set(&ret->nr_tasks, 1);
9586db1e29SJens Axboe 		spin_lock_init(&ret->lock);
9686db1e29SJens Axboe 		ret->ioprio_changed = 0;
9786db1e29SJens Axboe 		ret->ioprio = 0;
9886db1e29SJens Axboe 		ret->last_waited = jiffies; /* doesn't matter... */
9986db1e29SJens Axboe 		ret->nr_batch_requests = 0; /* because this is 0 */
10086db1e29SJens Axboe 		ret->aic = NULL;
10186db1e29SJens Axboe 		INIT_RADIX_TREE(&ret->radix_root, GFP_ATOMIC | __GFP_HIGH);
102ffc4e759SJens Axboe 		INIT_HLIST_HEAD(&ret->cic_list);
10386db1e29SJens Axboe 		ret->ioc_data = NULL;
10486db1e29SJens Axboe 	}
10586db1e29SJens Axboe 
10686db1e29SJens Axboe 	return ret;
10786db1e29SJens Axboe }
10886db1e29SJens Axboe 
10986db1e29SJens Axboe /*
11086db1e29SJens Axboe  * If the current task has no IO context then create one and initialise it.
11186db1e29SJens Axboe  * Otherwise, return its existing IO context.
11286db1e29SJens Axboe  *
11386db1e29SJens Axboe  * This returned IO context doesn't have a specifically elevated refcount,
11486db1e29SJens Axboe  * but since the current task itself holds a reference, the context can be
11586db1e29SJens Axboe  * used in general code, so long as it stays within `current` context.
11686db1e29SJens Axboe  */
11786db1e29SJens Axboe struct io_context *current_io_context(gfp_t gfp_flags, int node)
11886db1e29SJens Axboe {
11986db1e29SJens Axboe 	struct task_struct *tsk = current;
12086db1e29SJens Axboe 	struct io_context *ret;
12186db1e29SJens Axboe 
12286db1e29SJens Axboe 	ret = tsk->io_context;
12386db1e29SJens Axboe 	if (likely(ret))
12486db1e29SJens Axboe 		return ret;
12586db1e29SJens Axboe 
12686db1e29SJens Axboe 	ret = alloc_io_context(gfp_flags, node);
12786db1e29SJens Axboe 	if (ret) {
12886db1e29SJens Axboe 		/* make sure set_task_ioprio() sees the settings above */
12986db1e29SJens Axboe 		smp_wmb();
13086db1e29SJens Axboe 		tsk->io_context = ret;
13186db1e29SJens Axboe 	}
13286db1e29SJens Axboe 
13386db1e29SJens Axboe 	return ret;
13486db1e29SJens Axboe }
13586db1e29SJens Axboe 
13686db1e29SJens Axboe /*
13786db1e29SJens Axboe  * If the current task has no IO context then create one and initialise it.
13886db1e29SJens Axboe  * If it does have a context, take a ref on it.
13986db1e29SJens Axboe  *
14086db1e29SJens Axboe  * This is always called in the context of the task which submitted the I/O.
14186db1e29SJens Axboe  */
14286db1e29SJens Axboe struct io_context *get_io_context(gfp_t gfp_flags, int node)
14386db1e29SJens Axboe {
14486db1e29SJens Axboe 	struct io_context *ret = NULL;
14586db1e29SJens Axboe 
14686db1e29SJens Axboe 	/*
14786db1e29SJens Axboe 	 * Check for unlikely race with exiting task. ioc ref count is
14886db1e29SJens Axboe 	 * zero when ioc is being detached.
14986db1e29SJens Axboe 	 */
15086db1e29SJens Axboe 	do {
15186db1e29SJens Axboe 		ret = current_io_context(gfp_flags, node);
15286db1e29SJens Axboe 		if (unlikely(!ret))
15386db1e29SJens Axboe 			break;
154d9c7d394SNikanth Karthikesan 	} while (!atomic_long_inc_not_zero(&ret->refcount));
15586db1e29SJens Axboe 
15686db1e29SJens Axboe 	return ret;
15786db1e29SJens Axboe }
15886db1e29SJens Axboe EXPORT_SYMBOL(get_io_context);
15986db1e29SJens Axboe 
16086db1e29SJens Axboe void copy_io_context(struct io_context **pdst, struct io_context **psrc)
16186db1e29SJens Axboe {
16286db1e29SJens Axboe 	struct io_context *src = *psrc;
16386db1e29SJens Axboe 	struct io_context *dst = *pdst;
16486db1e29SJens Axboe 
16586db1e29SJens Axboe 	if (src) {
166d9c7d394SNikanth Karthikesan 		BUG_ON(atomic_long_read(&src->refcount) == 0);
167d9c7d394SNikanth Karthikesan 		atomic_long_inc(&src->refcount);
16886db1e29SJens Axboe 		put_io_context(dst);
16986db1e29SJens Axboe 		*pdst = src;
17086db1e29SJens Axboe 	}
17186db1e29SJens Axboe }
17286db1e29SJens Axboe EXPORT_SYMBOL(copy_io_context);
17386db1e29SJens Axboe 
17413341598SAdrian Bunk static int __init blk_ioc_init(void)
17586db1e29SJens Axboe {
17686db1e29SJens Axboe 	iocontext_cachep = kmem_cache_create("blkdev_ioc",
17786db1e29SJens Axboe 			sizeof(struct io_context), 0, SLAB_PANIC, NULL);
17886db1e29SJens Axboe 	return 0;
17986db1e29SJens Axboe }
18086db1e29SJens Axboe subsys_initcall(blk_ioc_init);
181