diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-08-07 06:23:41 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-08-07 14:40:08 -0400 |
commit | 215752fce31c80f3b3a1530bc7cddb3ba6a69b3a (patch) | |
tree | 70274a8d3ba397085593cf98be126a376f9221bf /kernel | |
parent | 54a4d58a6459a93fc6ee898354b3d2ffb80dd03a (diff) |
acct: get rid of acct_list
Put these suckers on per-vfsmount and per-superblock lists instead.
Note: right now it's still acct_lock for everything, but that's
going to change.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/acct.c | 135 |
1 files changed, 55 insertions, 80 deletions
diff --git a/kernel/acct.c b/kernel/acct.c index 019f012a3c6f..21fbb3c27c2a 100644 --- a/kernel/acct.c +++ b/kernel/acct.c | |||
@@ -59,6 +59,7 @@ | |||
59 | #include <asm/div64.h> | 59 | #include <asm/div64.h> |
60 | #include <linux/blkdev.h> /* sector_div */ | 60 | #include <linux/blkdev.h> /* sector_div */ |
61 | #include <linux/pid_namespace.h> | 61 | #include <linux/pid_namespace.h> |
62 | #include <../fs/mount.h> /* will go away when we refactor */ | ||
62 | 63 | ||
63 | /* | 64 | /* |
64 | * These constants control the amount of freespace that suspend and | 65 | * These constants control the amount of freespace that suspend and |
@@ -79,16 +80,16 @@ static void do_acct_process(struct bsd_acct_struct *acct); | |||
79 | 80 | ||
80 | struct bsd_acct_struct { | 81 | struct bsd_acct_struct { |
81 | long count; | 82 | long count; |
83 | struct hlist_node s_list; | ||
84 | struct hlist_node m_list; | ||
82 | struct mutex lock; | 85 | struct mutex lock; |
83 | int active; | 86 | int active; |
84 | unsigned long needcheck; | 87 | unsigned long needcheck; |
85 | struct file *file; | 88 | struct file *file; |
86 | struct pid_namespace *ns; | 89 | struct pid_namespace *ns; |
87 | struct list_head list; | ||
88 | }; | 90 | }; |
89 | 91 | ||
90 | static DEFINE_SPINLOCK(acct_lock); | 92 | static DEFINE_SPINLOCK(acct_lock); |
91 | static LIST_HEAD(acct_list); | ||
92 | 93 | ||
93 | /* | 94 | /* |
94 | * Check the amount of free space and suspend/resume accordingly. | 95 | * Check the amount of free space and suspend/resume accordingly. |
@@ -133,25 +134,33 @@ static void acct_put(struct bsd_acct_struct *p) | |||
133 | spin_unlock(&acct_lock); | 134 | spin_unlock(&acct_lock); |
134 | } | 135 | } |
135 | 136 | ||
136 | static struct bsd_acct_struct *acct_get(struct bsd_acct_struct **p) | 137 | static struct bsd_acct_struct *__acct_get(struct bsd_acct_struct *res) |
138 | { | ||
139 | res->count++; | ||
140 | spin_unlock(&acct_lock); | ||
141 | mutex_lock(&res->lock); | ||
142 | if (!res->ns) { | ||
143 | mutex_unlock(&res->lock); | ||
144 | spin_lock(&acct_lock); | ||
145 | if (!--res->count) | ||
146 | kfree(res); | ||
147 | return NULL; | ||
148 | } | ||
149 | return res; | ||
150 | } | ||
151 | |||
152 | static struct bsd_acct_struct *acct_get(struct pid_namespace *ns) | ||
137 | { | 153 | { |
138 | struct bsd_acct_struct *res; | 154 | struct bsd_acct_struct *res; |
139 | spin_lock(&acct_lock); | 155 | spin_lock(&acct_lock); |
140 | again: | 156 | again: |
141 | res = *p; | 157 | if (!ns->bacct) { |
142 | if (res) | 158 | spin_unlock(&acct_lock); |
143 | res->count++; | 159 | return NULL; |
144 | spin_unlock(&acct_lock); | ||
145 | if (res) { | ||
146 | mutex_lock(&res->lock); | ||
147 | if (!res->ns) { | ||
148 | mutex_unlock(&res->lock); | ||
149 | spin_lock(&acct_lock); | ||
150 | if (!--res->count) | ||
151 | kfree(res); | ||
152 | goto again; | ||
153 | } | ||
154 | } | 160 | } |
161 | res = __acct_get(ns->bacct); | ||
162 | if (!res) | ||
163 | goto again; | ||
155 | return res; | 164 | return res; |
156 | } | 165 | } |
157 | 166 | ||
@@ -162,7 +171,8 @@ static void acct_kill(struct bsd_acct_struct *acct, | |||
162 | struct file *file = acct->file; | 171 | struct file *file = acct->file; |
163 | struct pid_namespace *ns = acct->ns; | 172 | struct pid_namespace *ns = acct->ns; |
164 | spin_lock(&acct_lock); | 173 | spin_lock(&acct_lock); |
165 | list_del(&acct->list); | 174 | hlist_del(&acct->m_list); |
175 | hlist_del(&acct->s_list); | ||
166 | mnt_unpin(file->f_path.mnt); | 176 | mnt_unpin(file->f_path.mnt); |
167 | spin_unlock(&acct_lock); | 177 | spin_unlock(&acct_lock); |
168 | do_acct_process(acct); | 178 | do_acct_process(acct); |
@@ -170,8 +180,10 @@ static void acct_kill(struct bsd_acct_struct *acct, | |||
170 | spin_lock(&acct_lock); | 180 | spin_lock(&acct_lock); |
171 | ns->bacct = new; | 181 | ns->bacct = new; |
172 | if (new) { | 182 | if (new) { |
173 | mnt_pin(new->file->f_path.mnt); | 183 | struct vfsmount *m = new->file->f_path.mnt; |
174 | list_add(&new->list, &acct_list); | 184 | mnt_pin(m); |
185 | hlist_add_head(&new->s_list, &m->mnt_sb->s_pins); | ||
186 | hlist_add_head(&new->m_list, &real_mount(m)->mnt_pins); | ||
175 | } | 187 | } |
176 | acct->ns = NULL; | 188 | acct->ns = NULL; |
177 | mutex_unlock(&acct->lock); | 189 | mutex_unlock(&acct->lock); |
@@ -218,14 +230,15 @@ static int acct_on(struct filename *pathname) | |||
218 | mutex_init(&acct->lock); | 230 | mutex_init(&acct->lock); |
219 | mnt = file->f_path.mnt; | 231 | mnt = file->f_path.mnt; |
220 | 232 | ||
221 | old = acct_get(&ns->bacct); | 233 | old = acct_get(ns); |
222 | if (old) { | 234 | if (old) { |
223 | acct_kill(old, acct); | 235 | acct_kill(old, acct); |
224 | } else { | 236 | } else { |
225 | spin_lock(&acct_lock); | 237 | spin_lock(&acct_lock); |
226 | ns->bacct = acct; | 238 | ns->bacct = acct; |
227 | mnt_pin(mnt); | 239 | mnt_pin(mnt); |
228 | list_add(&acct->list, &acct_list); | 240 | hlist_add_head(&acct->s_list, &mnt->mnt_sb->s_pins); |
241 | hlist_add_head(&acct->m_list, &real_mount(mnt)->mnt_pins); | ||
229 | spin_unlock(&acct_lock); | 242 | spin_unlock(&acct_lock); |
230 | } | 243 | } |
231 | mntput(mnt); /* it's pinned, now give up active reference */ | 244 | mntput(mnt); /* it's pinned, now give up active reference */ |
@@ -261,79 +274,41 @@ SYSCALL_DEFINE1(acct, const char __user *, name) | |||
261 | mutex_unlock(&acct_on_mutex); | 274 | mutex_unlock(&acct_on_mutex); |
262 | putname(tmp); | 275 | putname(tmp); |
263 | } else { | 276 | } else { |
264 | acct_kill(acct_get(&task_active_pid_ns(current)->bacct), NULL); | 277 | acct_kill(acct_get(task_active_pid_ns(current)), NULL); |
265 | } | 278 | } |
266 | 279 | ||
267 | return error; | 280 | return error; |
268 | } | 281 | } |
269 | 282 | ||
270 | /** | 283 | void acct_auto_close_mnt(struct hlist_head *list) |
271 | * acct_auto_close - turn off a filesystem's accounting if it is on | ||
272 | * @m: vfsmount being shut down | ||
273 | * | ||
274 | * If the accounting is turned on for a file in the subtree pointed to | ||
275 | * to by m, turn accounting off. Done when m is about to die. | ||
276 | */ | ||
277 | void acct_auto_close_mnt(struct vfsmount *m) | ||
278 | { | 284 | { |
279 | struct bsd_acct_struct *acct; | 285 | while (1) { |
280 | 286 | spin_lock(&acct_lock); | |
281 | spin_lock(&acct_lock); | 287 | if (!list->first) |
282 | restart: | 288 | break; |
283 | list_for_each_entry(acct, &acct_list, list) | 289 | acct_kill(__acct_get(hlist_entry(list->first, |
284 | if (acct->file->f_path.mnt == m) { | 290 | struct bsd_acct_struct, |
285 | acct->count++; | 291 | m_list)), NULL); |
286 | spin_unlock(&acct_lock); | 292 | } |
287 | mutex_lock(&acct->lock); | ||
288 | if (!acct->ns) { | ||
289 | mutex_unlock(&acct->lock); | ||
290 | spin_lock(&acct_lock); | ||
291 | if (!--acct->count) | ||
292 | kfree(acct); | ||
293 | goto restart; | ||
294 | } | ||
295 | acct_kill(acct, NULL); | ||
296 | spin_lock(&acct_lock); | ||
297 | goto restart; | ||
298 | } | ||
299 | spin_unlock(&acct_lock); | 293 | spin_unlock(&acct_lock); |
300 | } | 294 | } |
301 | 295 | ||
302 | /** | 296 | void acct_auto_close(struct hlist_head *list) |
303 | * acct_auto_close - turn off a filesystem's accounting if it is on | ||
304 | * @sb: super block for the filesystem | ||
305 | * | ||
306 | * If the accounting is turned on for a file in the filesystem pointed | ||
307 | * to by sb, turn accounting off. | ||
308 | */ | ||
309 | void acct_auto_close(struct super_block *sb) | ||
310 | { | 297 | { |
311 | struct bsd_acct_struct *acct; | 298 | while (1) { |
312 | 299 | spin_lock(&acct_lock); | |
313 | spin_lock(&acct_lock); | 300 | if (!list->first) |
314 | restart: | 301 | break; |
315 | list_for_each_entry(acct, &acct_list, list) | 302 | acct_kill(__acct_get(hlist_entry(list->first, |
316 | if (acct->file->f_path.dentry->d_sb == sb) { | 303 | struct bsd_acct_struct, |
317 | acct->count++; | 304 | s_list)), NULL); |
318 | spin_unlock(&acct_lock); | 305 | } |
319 | mutex_lock(&acct->lock); | ||
320 | if (!acct->ns) { | ||
321 | mutex_unlock(&acct->lock); | ||
322 | spin_lock(&acct_lock); | ||
323 | if (!--acct->count) | ||
324 | kfree(acct); | ||
325 | goto restart; | ||
326 | } | ||
327 | acct_kill(acct, NULL); | ||
328 | spin_lock(&acct_lock); | ||
329 | goto restart; | ||
330 | } | ||
331 | spin_unlock(&acct_lock); | 306 | spin_unlock(&acct_lock); |
332 | } | 307 | } |
333 | 308 | ||
334 | void acct_exit_ns(struct pid_namespace *ns) | 309 | void acct_exit_ns(struct pid_namespace *ns) |
335 | { | 310 | { |
336 | acct_kill(acct_get(&ns->bacct), NULL); | 311 | acct_kill(acct_get(ns), NULL); |
337 | } | 312 | } |
338 | 313 | ||
339 | /* | 314 | /* |
@@ -602,7 +577,7 @@ void acct_collect(long exitcode, int group_dead) | |||
602 | static void slow_acct_process(struct pid_namespace *ns) | 577 | static void slow_acct_process(struct pid_namespace *ns) |
603 | { | 578 | { |
604 | for ( ; ns; ns = ns->parent) { | 579 | for ( ; ns; ns = ns->parent) { |
605 | struct bsd_acct_struct *acct = acct_get(&ns->bacct); | 580 | struct bsd_acct_struct *acct = acct_get(ns); |
606 | if (acct) { | 581 | if (acct) { |
607 | do_acct_process(acct); | 582 | do_acct_process(acct); |
608 | mutex_unlock(&acct->lock); | 583 | mutex_unlock(&acct->lock); |