diff options
-rw-r--r-- | kernel/acct.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/kernel/acct.c b/kernel/acct.c index 6fd375f15626..d9ebc96b1126 100644 --- a/kernel/acct.c +++ b/kernel/acct.c | |||
@@ -92,6 +92,8 @@ struct bsd_acct_struct { | |||
92 | unsigned long needcheck; | 92 | unsigned long needcheck; |
93 | struct file *file; | 93 | struct file *file; |
94 | struct pid_namespace *ns; | 94 | struct pid_namespace *ns; |
95 | struct work_struct work; | ||
96 | struct completion done; | ||
95 | }; | 97 | }; |
96 | 98 | ||
97 | static void acct_free_rcu(struct rcu_head *head) | 99 | static void acct_free_rcu(struct rcu_head *head) |
@@ -176,15 +178,27 @@ again: | |||
176 | return res; | 178 | return res; |
177 | } | 179 | } |
178 | 180 | ||
181 | static void close_work(struct work_struct *work) | ||
182 | { | ||
183 | struct bsd_acct_struct *acct = container_of(work, struct bsd_acct_struct, work); | ||
184 | struct file *file = acct->file; | ||
185 | mnt_unpin(file->f_path.mnt); | ||
186 | if (file->f_op->flush) | ||
187 | file->f_op->flush(file, NULL); | ||
188 | __fput_sync(file); | ||
189 | complete(&acct->done); | ||
190 | } | ||
191 | |||
179 | static void acct_kill(struct bsd_acct_struct *acct, | 192 | static void acct_kill(struct bsd_acct_struct *acct, |
180 | struct bsd_acct_struct *new) | 193 | struct bsd_acct_struct *new) |
181 | { | 194 | { |
182 | if (acct) { | 195 | if (acct) { |
183 | struct file *file = acct->file; | ||
184 | struct pid_namespace *ns = acct->ns; | 196 | struct pid_namespace *ns = acct->ns; |
185 | do_acct_process(acct); | 197 | do_acct_process(acct); |
186 | mnt_unpin(file->f_path.mnt); | 198 | INIT_WORK(&acct->work, close_work); |
187 | filp_close(file, NULL); | 199 | init_completion(&acct->done); |
200 | schedule_work(&acct->work); | ||
201 | wait_for_completion(&acct->done); | ||
188 | spin_lock(&acct_lock); | 202 | spin_lock(&acct_lock); |
189 | hlist_del(&acct->m_list); | 203 | hlist_del(&acct->m_list); |
190 | hlist_del(&acct->s_list); | 204 | hlist_del(&acct->s_list); |