xref: /openbmc/linux/block/blk-ioc.c (revision dc86900e)
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 
196e736be7STejun Heo /**
206e736be7STejun Heo  * get_io_context - increment reference count to io_context
216e736be7STejun Heo  * @ioc: io_context to get
226e736be7STejun Heo  *
236e736be7STejun Heo  * Increment reference count to @ioc.
246e736be7STejun Heo  */
256e736be7STejun Heo void get_io_context(struct io_context *ioc)
266e736be7STejun Heo {
276e736be7STejun Heo 	BUG_ON(atomic_long_read(&ioc->refcount) <= 0);
286e736be7STejun Heo 	atomic_long_inc(&ioc->refcount);
296e736be7STejun Heo }
306e736be7STejun Heo EXPORT_SYMBOL(get_io_context);
316e736be7STejun Heo 
3286db1e29SJens Axboe static void cfq_dtor(struct io_context *ioc)
3386db1e29SJens Axboe {
34ffc4e759SJens Axboe 	if (!hlist_empty(&ioc->cic_list)) {
35ffc4e759SJens Axboe 		struct cfq_io_context *cic;
3686db1e29SJens Axboe 
37e2bd9678SPaul Bolle 		cic = hlist_entry(ioc->cic_list.first, struct cfq_io_context,
38ffc4e759SJens Axboe 								cic_list);
39ffc4e759SJens Axboe 		cic->dtor(ioc);
40ffc4e759SJens Axboe 	}
4186db1e29SJens Axboe }
4286db1e29SJens Axboe 
4342ec57a8STejun Heo /**
4442ec57a8STejun Heo  * put_io_context - put a reference of io_context
4542ec57a8STejun Heo  * @ioc: io_context to put
4642ec57a8STejun Heo  *
4742ec57a8STejun Heo  * Decrement reference count of @ioc and release it if the count reaches
4842ec57a8STejun Heo  * zero.
4986db1e29SJens Axboe  */
5042ec57a8STejun Heo void put_io_context(struct io_context *ioc)
5186db1e29SJens Axboe {
5286db1e29SJens Axboe 	if (ioc == NULL)
5342ec57a8STejun Heo 		return;
5486db1e29SJens Axboe 
5542ec57a8STejun Heo 	BUG_ON(atomic_long_read(&ioc->refcount) <= 0);
5686db1e29SJens Axboe 
5742ec57a8STejun Heo 	if (!atomic_long_dec_and_test(&ioc->refcount))
5842ec57a8STejun Heo 		return;
5942ec57a8STejun Heo 
6086db1e29SJens Axboe 	rcu_read_lock();
6186db1e29SJens Axboe 	cfq_dtor(ioc);
6207416d29SJens Axboe 	rcu_read_unlock();
6386db1e29SJens Axboe 
6486db1e29SJens Axboe 	kmem_cache_free(iocontext_cachep, ioc);
6586db1e29SJens Axboe }
6686db1e29SJens Axboe EXPORT_SYMBOL(put_io_context);
6786db1e29SJens Axboe 
6886db1e29SJens Axboe static void cfq_exit(struct io_context *ioc)
6986db1e29SJens Axboe {
7086db1e29SJens Axboe 	rcu_read_lock();
7186db1e29SJens Axboe 
72ffc4e759SJens Axboe 	if (!hlist_empty(&ioc->cic_list)) {
73ffc4e759SJens Axboe 		struct cfq_io_context *cic;
74ffc4e759SJens Axboe 
75e2bd9678SPaul Bolle 		cic = hlist_entry(ioc->cic_list.first, struct cfq_io_context,
76ffc4e759SJens Axboe 								cic_list);
77ffc4e759SJens Axboe 		cic->exit(ioc);
78ffc4e759SJens Axboe 	}
79ffc4e759SJens Axboe 	rcu_read_unlock();
8086db1e29SJens Axboe }
8186db1e29SJens Axboe 
8227667c99SBart Van Assche /* Called by the exiting task */
83b69f2292SLouis Rilling void exit_io_context(struct task_struct *task)
8486db1e29SJens Axboe {
8586db1e29SJens Axboe 	struct io_context *ioc;
8686db1e29SJens Axboe 
876e736be7STejun Heo 	/* PF_EXITING prevents new io_context from being attached to @task */
886e736be7STejun Heo 	WARN_ON_ONCE(!(current->flags & PF_EXITING));
896e736be7STejun Heo 
90b69f2292SLouis Rilling 	task_lock(task);
91b69f2292SLouis Rilling 	ioc = task->io_context;
92b69f2292SLouis Rilling 	task->io_context = NULL;
93b69f2292SLouis Rilling 	task_unlock(task);
9486db1e29SJens Axboe 
9527667c99SBart Van Assche 	if (atomic_dec_and_test(&ioc->nr_tasks))
9686db1e29SJens Axboe 		cfq_exit(ioc);
9786db1e29SJens Axboe 
9861cc74fbSLouis Rilling 	put_io_context(ioc);
9986db1e29SJens Axboe }
10086db1e29SJens Axboe 
1016e736be7STejun Heo static struct io_context *create_task_io_context(struct task_struct *task,
1026e736be7STejun Heo 						 gfp_t gfp_flags, int node,
1036e736be7STejun Heo 						 bool take_ref)
10486db1e29SJens Axboe {
105df415656SPaul Bolle 	struct io_context *ioc;
10686db1e29SJens Axboe 
10742ec57a8STejun Heo 	ioc = kmem_cache_alloc_node(iocontext_cachep, gfp_flags | __GFP_ZERO,
10842ec57a8STejun Heo 				    node);
10942ec57a8STejun Heo 	if (unlikely(!ioc))
11042ec57a8STejun Heo 		return NULL;
11142ec57a8STejun Heo 
11242ec57a8STejun Heo 	/* initialize */
113df415656SPaul Bolle 	atomic_long_set(&ioc->refcount, 1);
114df415656SPaul Bolle 	atomic_set(&ioc->nr_tasks, 1);
115df415656SPaul Bolle 	spin_lock_init(&ioc->lock);
116df415656SPaul Bolle 	INIT_RADIX_TREE(&ioc->radix_root, GFP_ATOMIC | __GFP_HIGH);
117df415656SPaul Bolle 	INIT_HLIST_HEAD(&ioc->cic_list);
11886db1e29SJens Axboe 
1196e736be7STejun Heo 	/* try to install, somebody might already have beaten us to it */
1206e736be7STejun Heo 	task_lock(task);
1216e736be7STejun Heo 
1226e736be7STejun Heo 	if (!task->io_context && !(task->flags & PF_EXITING)) {
1236e736be7STejun Heo 		task->io_context = ioc;
1246e736be7STejun Heo 	} else {
1256e736be7STejun Heo 		kmem_cache_free(iocontext_cachep, ioc);
1266e736be7STejun Heo 		ioc = task->io_context;
1276e736be7STejun Heo 	}
1286e736be7STejun Heo 
1296e736be7STejun Heo 	if (ioc && take_ref)
1306e736be7STejun Heo 		get_io_context(ioc);
1316e736be7STejun Heo 
1326e736be7STejun Heo 	task_unlock(task);
133df415656SPaul Bolle 	return ioc;
13486db1e29SJens Axboe }
13586db1e29SJens Axboe 
13642ec57a8STejun Heo /**
13742ec57a8STejun Heo  * current_io_context - get io_context of %current
13842ec57a8STejun Heo  * @gfp_flags: allocation flags, used if allocation is necessary
13942ec57a8STejun Heo  * @node: allocation node, used if allocation is necessary
14086db1e29SJens Axboe  *
14142ec57a8STejun Heo  * Return io_context of %current.  If it doesn't exist, it is created with
14242ec57a8STejun Heo  * @gfp_flags and @node.  The returned io_context does NOT have its
14342ec57a8STejun Heo  * reference count incremented.  Because io_context is exited only on task
14442ec57a8STejun Heo  * exit, %current can be sure that the returned io_context is valid and
14542ec57a8STejun Heo  * alive as long as it is executing.
14686db1e29SJens Axboe  */
14786db1e29SJens Axboe struct io_context *current_io_context(gfp_t gfp_flags, int node)
14886db1e29SJens Axboe {
1496e736be7STejun Heo 	might_sleep_if(gfp_flags & __GFP_WAIT);
15086db1e29SJens Axboe 
1516e736be7STejun Heo 	if (current->io_context)
1526e736be7STejun Heo 		return current->io_context;
15386db1e29SJens Axboe 
1546e736be7STejun Heo 	return create_task_io_context(current, gfp_flags, node, false);
15586db1e29SJens Axboe }
1566e736be7STejun Heo EXPORT_SYMBOL(current_io_context);
15786db1e29SJens Axboe 
1586e736be7STejun Heo /**
1596e736be7STejun Heo  * get_task_io_context - get io_context of a task
1606e736be7STejun Heo  * @task: task of interest
1616e736be7STejun Heo  * @gfp_flags: allocation flags, used if allocation is necessary
1626e736be7STejun Heo  * @node: allocation node, used if allocation is necessary
16386db1e29SJens Axboe  *
1646e736be7STejun Heo  * Return io_context of @task.  If it doesn't exist, it is created with
1656e736be7STejun Heo  * @gfp_flags and @node.  The returned io_context has its reference count
1666e736be7STejun Heo  * incremented.
1676e736be7STejun Heo  *
1686e736be7STejun Heo  * This function always goes through task_lock() and it's better to use
1696e736be7STejun Heo  * current_io_context() + get_io_context() for %current.
17086db1e29SJens Axboe  */
1716e736be7STejun Heo struct io_context *get_task_io_context(struct task_struct *task,
1726e736be7STejun Heo 				       gfp_t gfp_flags, int node)
17386db1e29SJens Axboe {
1746e736be7STejun Heo 	struct io_context *ioc;
17586db1e29SJens Axboe 
1766e736be7STejun Heo 	might_sleep_if(gfp_flags & __GFP_WAIT);
17786db1e29SJens Axboe 
1786e736be7STejun Heo 	task_lock(task);
1796e736be7STejun Heo 	ioc = task->io_context;
1806e736be7STejun Heo 	if (likely(ioc)) {
1816e736be7STejun Heo 		get_io_context(ioc);
1826e736be7STejun Heo 		task_unlock(task);
183df415656SPaul Bolle 		return ioc;
18486db1e29SJens Axboe 	}
1856e736be7STejun Heo 	task_unlock(task);
1866e736be7STejun Heo 
1876e736be7STejun Heo 	return create_task_io_context(task, gfp_flags, node, true);
1886e736be7STejun Heo }
1896e736be7STejun Heo EXPORT_SYMBOL(get_task_io_context);
19086db1e29SJens Axboe 
191dc86900eSTejun Heo void ioc_set_changed(struct io_context *ioc, int which)
192dc86900eSTejun Heo {
193dc86900eSTejun Heo 	struct cfq_io_context *cic;
194dc86900eSTejun Heo 	struct hlist_node *n;
195dc86900eSTejun Heo 
196dc86900eSTejun Heo 	hlist_for_each_entry(cic, n, &ioc->cic_list, cic_list)
197dc86900eSTejun Heo 		set_bit(which, &cic->changed);
198dc86900eSTejun Heo }
199dc86900eSTejun Heo 
200dc86900eSTejun Heo /**
201dc86900eSTejun Heo  * ioc_ioprio_changed - notify ioprio change
202dc86900eSTejun Heo  * @ioc: io_context of interest
203dc86900eSTejun Heo  * @ioprio: new ioprio
204dc86900eSTejun Heo  *
205dc86900eSTejun Heo  * @ioc's ioprio has changed to @ioprio.  Set %CIC_IOPRIO_CHANGED for all
206dc86900eSTejun Heo  * cic's.  iosched is responsible for checking the bit and applying it on
207dc86900eSTejun Heo  * request issue path.
208dc86900eSTejun Heo  */
209dc86900eSTejun Heo void ioc_ioprio_changed(struct io_context *ioc, int ioprio)
210dc86900eSTejun Heo {
211dc86900eSTejun Heo 	unsigned long flags;
212dc86900eSTejun Heo 
213dc86900eSTejun Heo 	spin_lock_irqsave(&ioc->lock, flags);
214dc86900eSTejun Heo 	ioc->ioprio = ioprio;
215dc86900eSTejun Heo 	ioc_set_changed(ioc, CIC_IOPRIO_CHANGED);
216dc86900eSTejun Heo 	spin_unlock_irqrestore(&ioc->lock, flags);
217dc86900eSTejun Heo }
218dc86900eSTejun Heo 
219dc86900eSTejun Heo /**
220dc86900eSTejun Heo  * ioc_cgroup_changed - notify cgroup change
221dc86900eSTejun Heo  * @ioc: io_context of interest
222dc86900eSTejun Heo  *
223dc86900eSTejun Heo  * @ioc's cgroup has changed.  Set %CIC_CGROUP_CHANGED for all cic's.
224dc86900eSTejun Heo  * iosched is responsible for checking the bit and applying it on request
225dc86900eSTejun Heo  * issue path.
226dc86900eSTejun Heo  */
227dc86900eSTejun Heo void ioc_cgroup_changed(struct io_context *ioc)
228dc86900eSTejun Heo {
229dc86900eSTejun Heo 	unsigned long flags;
230dc86900eSTejun Heo 
231dc86900eSTejun Heo 	spin_lock_irqsave(&ioc->lock, flags);
232dc86900eSTejun Heo 	ioc_set_changed(ioc, CIC_CGROUP_CHANGED);
233dc86900eSTejun Heo 	spin_unlock_irqrestore(&ioc->lock, flags);
234dc86900eSTejun Heo }
235dc86900eSTejun Heo 
23613341598SAdrian Bunk static int __init blk_ioc_init(void)
23786db1e29SJens Axboe {
23886db1e29SJens Axboe 	iocontext_cachep = kmem_cache_create("blkdev_ioc",
23986db1e29SJens Axboe 			sizeof(struct io_context), 0, SLAB_PANIC, NULL);
24086db1e29SJens Axboe 	return 0;
24186db1e29SJens Axboe }
24286db1e29SJens Axboe subsys_initcall(blk_ioc_init);
243