diff options
author | Tejun Heo <tj@kernel.org> | 2011-12-14 00:33:40 +0100 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2011-12-14 00:33:40 +0100 |
commit | f2dbd76a0a994bc1d5a3d0e7c844cc373832e86c (patch) | |
tree | cae6a4333ee6e5eb76ef133dfdee95e1943c0ab1 /block/blk-ioc.c | |
parent | 1238033c79e92e5c315af12e45396f1a78c73dec (diff) | |
download | lwn-f2dbd76a0a994bc1d5a3d0e7c844cc373832e86c.tar.gz lwn-f2dbd76a0a994bc1d5a3d0e7c844cc373832e86c.zip |
block, cfq: replace current_io_context() with create_io_context()
When called under queue_lock, current_io_context() triggers lockdep
warning if it hits allocation path. This is because io_context
installation is protected by task_lock which is not IRQ safe, so it
triggers irq-unsafe-lock -> irq -> irq-safe-lock -> irq-unsafe-lock
deadlock warning.
Given the restriction, accessor + creator rolled into one doesn't work
too well. Drop current_io_context() and let the users access
task->io_context directly inside queue_lock combined with explicit
creation using create_io_context().
Future ioc updates will further consolidate ioc access and the create
interface will be unexported.
While at it, relocate ioc internal interface declarations in blk.h and
add section comments before and after.
This patch does not introduce functional change.
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/blk-ioc.c')
-rw-r--r-- | block/blk-ioc.c | 62 |
1 files changed, 17 insertions, 45 deletions
diff --git a/block/blk-ioc.c b/block/blk-ioc.c index fb23965595da..e23c797b4685 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c @@ -205,16 +205,15 @@ void exit_io_context(struct task_struct *task) put_io_context(ioc, NULL); } -static struct io_context *create_task_io_context(struct task_struct *task, - gfp_t gfp_flags, int node, - bool take_ref) +void create_io_context_slowpath(struct task_struct *task, gfp_t gfp_flags, + int node) { struct io_context *ioc; ioc = kmem_cache_alloc_node(iocontext_cachep, gfp_flags | __GFP_ZERO, node); if (unlikely(!ioc)) - return NULL; + return; /* initialize */ atomic_long_set(&ioc->refcount, 1); @@ -226,42 +225,13 @@ static struct io_context *create_task_io_context(struct task_struct *task, /* try to install, somebody might already have beaten us to it */ task_lock(task); - - if (!task->io_context && !(task->flags & PF_EXITING)) { + if (!task->io_context && !(task->flags & PF_EXITING)) task->io_context = ioc; - } else { + else kmem_cache_free(iocontext_cachep, ioc); - ioc = task->io_context; - } - - if (ioc && take_ref) - get_io_context(ioc); - task_unlock(task); - return ioc; } - -/** - * current_io_context - get io_context of %current - * @gfp_flags: allocation flags, used if allocation is necessary - * @node: allocation node, used if allocation is necessary - * - * Return io_context of %current. If it doesn't exist, it is created with - * @gfp_flags and @node. The returned io_context does NOT have its - * reference count incremented. Because io_context is exited only on task - * exit, %current can be sure that the returned io_context is valid and - * alive as long as it is executing. - */ -struct io_context *current_io_context(gfp_t gfp_flags, int node) -{ - might_sleep_if(gfp_flags & __GFP_WAIT); - - if (current->io_context) - return current->io_context; - - return create_task_io_context(current, gfp_flags, node, false); -} -EXPORT_SYMBOL(current_io_context); +EXPORT_SYMBOL(create_io_context_slowpath); /** * get_task_io_context - get io_context of a task @@ -274,7 +244,7 @@ EXPORT_SYMBOL(current_io_context); * incremented. * * This function always goes through task_lock() and it's better to use - * current_io_context() + get_io_context() for %current. + * %current->io_context + get_io_context() for %current. */ struct io_context *get_task_io_context(struct task_struct *task, gfp_t gfp_flags, int node) @@ -283,16 +253,18 @@ struct io_context *get_task_io_context(struct task_struct *task, might_sleep_if(gfp_flags & __GFP_WAIT); - task_lock(task); - ioc = task->io_context; - if (likely(ioc)) { - get_io_context(ioc); + do { + task_lock(task); + ioc = task->io_context; + if (likely(ioc)) { + get_io_context(ioc); + task_unlock(task); + return ioc; + } task_unlock(task); - return ioc; - } - task_unlock(task); + } while (create_io_context(task, gfp_flags, node)); - return create_task_io_context(task, gfp_flags, node, true); + return NULL; } EXPORT_SYMBOL(get_task_io_context); |