diff options
author | Louis Rilling <louis.rilling@kerlabs.com> | 2009-12-04 08:52:42 -0500 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2009-12-04 10:36:18 -0500 |
commit | b69f2292063d2caf37ca9aec7d63ded203701bf3 (patch) | |
tree | be4acb81ea4ab7014047808ec2b2c908e8334f55 | |
parent | 61cc74fbb87af6aa551a06a370590c9bc07e29d9 (diff) |
block: Fix io_context leak after failure of clone with CLONE_IO
With CLONE_IO, parent's io_context->nr_tasks is incremented, but never
decremented whenever copy_process() fails afterwards, which prevents
exit_io_context() from calling IO schedulers exit functions.
Give a task_struct to exit_io_context(), and call exit_io_context() instead of
put_io_context() in copy_process() cleanup path.
Signed-off-by: Louis Rilling <louis.rilling@kerlabs.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r-- | block/blk-ioc.c | 10 | ||||
-rw-r--r-- | include/linux/iocontext.h | 5 | ||||
-rw-r--r-- | kernel/exit.c | 2 | ||||
-rw-r--r-- | kernel/fork.c | 3 |
4 files changed, 11 insertions, 9 deletions
diff --git a/block/blk-ioc.c b/block/blk-ioc.c index dcd041290b28..cbdabb0dd6d7 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c | |||
@@ -66,14 +66,14 @@ static void cfq_exit(struct io_context *ioc) | |||
66 | } | 66 | } |
67 | 67 | ||
68 | /* Called by the exitting task */ | 68 | /* Called by the exitting task */ |
69 | void exit_io_context(void) | 69 | void exit_io_context(struct task_struct *task) |
70 | { | 70 | { |
71 | struct io_context *ioc; | 71 | struct io_context *ioc; |
72 | 72 | ||
73 | task_lock(current); | 73 | task_lock(task); |
74 | ioc = current->io_context; | 74 | ioc = task->io_context; |
75 | current->io_context = NULL; | 75 | task->io_context = NULL; |
76 | task_unlock(current); | 76 | task_unlock(task); |
77 | 77 | ||
78 | if (atomic_dec_and_test(&ioc->nr_tasks)) { | 78 | if (atomic_dec_and_test(&ioc->nr_tasks)) { |
79 | if (ioc->aic && ioc->aic->exit) | 79 | if (ioc->aic && ioc->aic->exit) |
diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h index d61b0b8b5cd1..a63235996309 100644 --- a/include/linux/iocontext.h +++ b/include/linux/iocontext.h | |||
@@ -98,14 +98,15 @@ static inline struct io_context *ioc_task_link(struct io_context *ioc) | |||
98 | return NULL; | 98 | return NULL; |
99 | } | 99 | } |
100 | 100 | ||
101 | struct task_struct; | ||
101 | #ifdef CONFIG_BLOCK | 102 | #ifdef CONFIG_BLOCK |
102 | int put_io_context(struct io_context *ioc); | 103 | int put_io_context(struct io_context *ioc); |
103 | void exit_io_context(void); | 104 | void exit_io_context(struct task_struct *task); |
104 | struct io_context *get_io_context(gfp_t gfp_flags, int node); | 105 | struct io_context *get_io_context(gfp_t gfp_flags, int node); |
105 | struct io_context *alloc_io_context(gfp_t gfp_flags, int node); | 106 | struct io_context *alloc_io_context(gfp_t gfp_flags, int node); |
106 | void copy_io_context(struct io_context **pdst, struct io_context **psrc); | 107 | void copy_io_context(struct io_context **pdst, struct io_context **psrc); |
107 | #else | 108 | #else |
108 | static inline void exit_io_context(void) | 109 | static inline void exit_io_context(struct task_struct *task) |
109 | { | 110 | { |
110 | } | 111 | } |
111 | 112 | ||
diff --git a/kernel/exit.c b/kernel/exit.c index f7864ac2ecc1..2544000125d9 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -1004,7 +1004,7 @@ NORET_TYPE void do_exit(long code) | |||
1004 | tsk->flags |= PF_EXITPIDONE; | 1004 | tsk->flags |= PF_EXITPIDONE; |
1005 | 1005 | ||
1006 | if (tsk->io_context) | 1006 | if (tsk->io_context) |
1007 | exit_io_context(); | 1007 | exit_io_context(tsk); |
1008 | 1008 | ||
1009 | if (tsk->splice_pipe) | 1009 | if (tsk->splice_pipe) |
1010 | __free_pipe_info(tsk->splice_pipe); | 1010 | __free_pipe_info(tsk->splice_pipe); |
diff --git a/kernel/fork.c b/kernel/fork.c index 166b8c49257c..607353425bb0 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1310,7 +1310,8 @@ bad_fork_free_pid: | |||
1310 | if (pid != &init_struct_pid) | 1310 | if (pid != &init_struct_pid) |
1311 | free_pid(pid); | 1311 | free_pid(pid); |
1312 | bad_fork_cleanup_io: | 1312 | bad_fork_cleanup_io: |
1313 | put_io_context(p->io_context); | 1313 | if (p->io_context) |
1314 | exit_io_context(p); | ||
1314 | bad_fork_cleanup_namespaces: | 1315 | bad_fork_cleanup_namespaces: |
1315 | exit_task_namespaces(p); | 1316 | exit_task_namespaces(p); |
1316 | bad_fork_cleanup_mm: | 1317 | bad_fork_cleanup_mm: |