diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-08-14 06:19:59 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-08-14 06:19:59 -0400 |
| commit | 8d7ccaa545490cdffdfaff0842436a8dd85cf47b (patch) | |
| tree | 8129b5907161bc6ae26deb3645ce1e280c5e1f51 /kernel/acct.c | |
| parent | b2139aa0eec330c711c5a279db361e5ef1178e78 (diff) | |
| parent | 30a2f3c60a84092c8084dfe788b710f8d0768cd4 (diff) | |
Merge commit 'v2.6.27-rc3' into x86/prototypes
Conflicts:
include/asm-x86/dma-mapping.h
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/acct.c')
| -rw-r--r-- | kernel/acct.c | 222 |
1 files changed, 144 insertions, 78 deletions
diff --git a/kernel/acct.c b/kernel/acct.c index 91e1cfd734d2..dd68b9059418 100644 --- a/kernel/acct.c +++ b/kernel/acct.c | |||
| @@ -75,37 +75,39 @@ int acct_parm[3] = {4, 2, 30}; | |||
| 75 | /* | 75 | /* |
| 76 | * External references and all of the globals. | 76 | * External references and all of the globals. |
| 77 | */ | 77 | */ |
| 78 | static void do_acct_process(struct pid_namespace *ns, struct file *); | 78 | static void do_acct_process(struct bsd_acct_struct *acct, |
| 79 | struct pid_namespace *ns, struct file *); | ||
| 79 | 80 | ||
| 80 | /* | 81 | /* |
| 81 | * This structure is used so that all the data protected by lock | 82 | * This structure is used so that all the data protected by lock |
| 82 | * can be placed in the same cache line as the lock. This primes | 83 | * can be placed in the same cache line as the lock. This primes |
| 83 | * the cache line to have the data after getting the lock. | 84 | * the cache line to have the data after getting the lock. |
| 84 | */ | 85 | */ |
| 85 | struct acct_glbs { | 86 | struct bsd_acct_struct { |
| 86 | spinlock_t lock; | ||
| 87 | volatile int active; | 87 | volatile int active; |
| 88 | volatile int needcheck; | 88 | volatile int needcheck; |
| 89 | struct file *file; | 89 | struct file *file; |
| 90 | struct pid_namespace *ns; | 90 | struct pid_namespace *ns; |
| 91 | struct timer_list timer; | 91 | struct timer_list timer; |
| 92 | struct list_head list; | ||
| 92 | }; | 93 | }; |
| 93 | 94 | ||
| 94 | static struct acct_glbs acct_globals __cacheline_aligned = | 95 | static DEFINE_SPINLOCK(acct_lock); |
| 95 | {__SPIN_LOCK_UNLOCKED(acct_globals.lock)}; | 96 | static LIST_HEAD(acct_list); |
| 96 | 97 | ||
| 97 | /* | 98 | /* |
| 98 | * Called whenever the timer says to check the free space. | 99 | * Called whenever the timer says to check the free space. |
| 99 | */ | 100 | */ |
| 100 | static void acct_timeout(unsigned long unused) | 101 | static void acct_timeout(unsigned long x) |
| 101 | { | 102 | { |
| 102 | acct_globals.needcheck = 1; | 103 | struct bsd_acct_struct *acct = (struct bsd_acct_struct *)x; |
| 104 | acct->needcheck = 1; | ||
| 103 | } | 105 | } |
| 104 | 106 | ||
| 105 | /* | 107 | /* |
| 106 | * Check the amount of free space and suspend/resume accordingly. | 108 | * Check the amount of free space and suspend/resume accordingly. |
| 107 | */ | 109 | */ |
| 108 | static int check_free_space(struct file *file) | 110 | static int check_free_space(struct bsd_acct_struct *acct, struct file *file) |
| 109 | { | 111 | { |
| 110 | struct kstatfs sbuf; | 112 | struct kstatfs sbuf; |
| 111 | int res; | 113 | int res; |
| @@ -113,11 +115,11 @@ static int check_free_space(struct file *file) | |||
| 113 | sector_t resume; | 115 | sector_t resume; |
| 114 | sector_t suspend; | 116 | sector_t suspend; |
| 115 | 117 | ||
| 116 | spin_lock(&acct_globals.lock); | 118 | spin_lock(&acct_lock); |
| 117 | res = acct_globals.active; | 119 | res = acct->active; |
| 118 | if (!file || !acct_globals.needcheck) | 120 | if (!file || !acct->needcheck) |
| 119 | goto out; | 121 | goto out; |
| 120 | spin_unlock(&acct_globals.lock); | 122 | spin_unlock(&acct_lock); |
| 121 | 123 | ||
| 122 | /* May block */ | 124 | /* May block */ |
| 123 | if (vfs_statfs(file->f_path.dentry, &sbuf)) | 125 | if (vfs_statfs(file->f_path.dentry, &sbuf)) |
| @@ -136,35 +138,35 @@ static int check_free_space(struct file *file) | |||
| 136 | act = 0; | 138 | act = 0; |
| 137 | 139 | ||
| 138 | /* | 140 | /* |
| 139 | * If some joker switched acct_globals.file under us we'ld better be | 141 | * If some joker switched acct->file under us we'ld better be |
| 140 | * silent and _not_ touch anything. | 142 | * silent and _not_ touch anything. |
| 141 | */ | 143 | */ |
| 142 | spin_lock(&acct_globals.lock); | 144 | spin_lock(&acct_lock); |
| 143 | if (file != acct_globals.file) { | 145 | if (file != acct->file) { |
| 144 | if (act) | 146 | if (act) |
| 145 | res = act>0; | 147 | res = act>0; |
| 146 | goto out; | 148 | goto out; |
| 147 | } | 149 | } |
| 148 | 150 | ||
| 149 | if (acct_globals.active) { | 151 | if (acct->active) { |
| 150 | if (act < 0) { | 152 | if (act < 0) { |
| 151 | acct_globals.active = 0; | 153 | acct->active = 0; |
| 152 | printk(KERN_INFO "Process accounting paused\n"); | 154 | printk(KERN_INFO "Process accounting paused\n"); |
| 153 | } | 155 | } |
| 154 | } else { | 156 | } else { |
| 155 | if (act > 0) { | 157 | if (act > 0) { |
| 156 | acct_globals.active = 1; | 158 | acct->active = 1; |
| 157 | printk(KERN_INFO "Process accounting resumed\n"); | 159 | printk(KERN_INFO "Process accounting resumed\n"); |
| 158 | } | 160 | } |
| 159 | } | 161 | } |
| 160 | 162 | ||
| 161 | del_timer(&acct_globals.timer); | 163 | del_timer(&acct->timer); |
| 162 | acct_globals.needcheck = 0; | 164 | acct->needcheck = 0; |
| 163 | acct_globals.timer.expires = jiffies + ACCT_TIMEOUT*HZ; | 165 | acct->timer.expires = jiffies + ACCT_TIMEOUT*HZ; |
| 164 | add_timer(&acct_globals.timer); | 166 | add_timer(&acct->timer); |
| 165 | res = acct_globals.active; | 167 | res = acct->active; |
| 166 | out: | 168 | out: |
| 167 | spin_unlock(&acct_globals.lock); | 169 | spin_unlock(&acct_lock); |
| 168 | return res; | 170 | return res; |
| 169 | } | 171 | } |
| 170 | 172 | ||
| @@ -172,39 +174,41 @@ out: | |||
| 172 | * Close the old accounting file (if currently open) and then replace | 174 | * Close the old accounting file (if currently open) and then replace |
| 173 | * it with file (if non-NULL). | 175 | * it with file (if non-NULL). |
| 174 | * | 176 | * |
| 175 | * NOTE: acct_globals.lock MUST be held on entry and exit. | 177 | * NOTE: acct_lock MUST be held on entry and exit. |
| 176 | */ | 178 | */ |
| 177 | static void acct_file_reopen(struct file *file) | 179 | static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file, |
| 180 | struct pid_namespace *ns) | ||
| 178 | { | 181 | { |
| 179 | struct file *old_acct = NULL; | 182 | struct file *old_acct = NULL; |
| 180 | struct pid_namespace *old_ns = NULL; | 183 | struct pid_namespace *old_ns = NULL; |
| 181 | 184 | ||
| 182 | if (acct_globals.file) { | 185 | if (acct->file) { |
| 183 | old_acct = acct_globals.file; | 186 | old_acct = acct->file; |
| 184 | old_ns = acct_globals.ns; | 187 | old_ns = acct->ns; |
| 185 | del_timer(&acct_globals.timer); | 188 | del_timer(&acct->timer); |
| 186 | acct_globals.active = 0; | 189 | acct->active = 0; |
| 187 | acct_globals.needcheck = 0; | 190 | acct->needcheck = 0; |
| 188 | acct_globals.file = NULL; | 191 | acct->file = NULL; |
| 192 | acct->ns = NULL; | ||
| 193 | list_del(&acct->list); | ||
| 189 | } | 194 | } |
| 190 | if (file) { | 195 | if (file) { |
| 191 | acct_globals.file = file; | 196 | acct->file = file; |
| 192 | acct_globals.ns = get_pid_ns(task_active_pid_ns(current)); | 197 | acct->ns = ns; |
| 193 | acct_globals.needcheck = 0; | 198 | acct->needcheck = 0; |
| 194 | acct_globals.active = 1; | 199 | acct->active = 1; |
| 200 | list_add(&acct->list, &acct_list); | ||
| 195 | /* It's been deleted if it was used before so this is safe */ | 201 | /* It's been deleted if it was used before so this is safe */ |
| 196 | init_timer(&acct_globals.timer); | 202 | setup_timer(&acct->timer, acct_timeout, (unsigned long)acct); |
| 197 | acct_globals.timer.function = acct_timeout; | 203 | acct->timer.expires = jiffies + ACCT_TIMEOUT*HZ; |
| 198 | acct_globals.timer.expires = jiffies + ACCT_TIMEOUT*HZ; | 204 | add_timer(&acct->timer); |
| 199 | add_timer(&acct_globals.timer); | ||
| 200 | } | 205 | } |
| 201 | if (old_acct) { | 206 | if (old_acct) { |
| 202 | mnt_unpin(old_acct->f_path.mnt); | 207 | mnt_unpin(old_acct->f_path.mnt); |
| 203 | spin_unlock(&acct_globals.lock); | 208 | spin_unlock(&acct_lock); |
| 204 | do_acct_process(old_ns, old_acct); | 209 | do_acct_process(acct, old_ns, old_acct); |
| 205 | filp_close(old_acct, NULL); | 210 | filp_close(old_acct, NULL); |
| 206 | put_pid_ns(old_ns); | 211 | spin_lock(&acct_lock); |
| 207 | spin_lock(&acct_globals.lock); | ||
| 208 | } | 212 | } |
| 209 | } | 213 | } |
| 210 | 214 | ||
| @@ -212,6 +216,8 @@ static int acct_on(char *name) | |||
| 212 | { | 216 | { |
| 213 | struct file *file; | 217 | struct file *file; |
| 214 | int error; | 218 | int error; |
| 219 | struct pid_namespace *ns; | ||
| 220 | struct bsd_acct_struct *acct = NULL; | ||
| 215 | 221 | ||
| 216 | /* Difference from BSD - they don't do O_APPEND */ | 222 | /* Difference from BSD - they don't do O_APPEND */ |
| 217 | file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0); | 223 | file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0); |
| @@ -228,18 +234,34 @@ static int acct_on(char *name) | |||
| 228 | return -EIO; | 234 | return -EIO; |
| 229 | } | 235 | } |
| 230 | 236 | ||
| 237 | ns = task_active_pid_ns(current); | ||
| 238 | if (ns->bacct == NULL) { | ||
| 239 | acct = kzalloc(sizeof(struct bsd_acct_struct), GFP_KERNEL); | ||
| 240 | if (acct == NULL) { | ||
| 241 | filp_close(file, NULL); | ||
| 242 | return -ENOMEM; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 231 | error = security_acct(file); | 246 | error = security_acct(file); |
| 232 | if (error) { | 247 | if (error) { |
| 248 | kfree(acct); | ||
| 233 | filp_close(file, NULL); | 249 | filp_close(file, NULL); |
| 234 | return error; | 250 | return error; |
| 235 | } | 251 | } |
| 236 | 252 | ||
| 237 | spin_lock(&acct_globals.lock); | 253 | spin_lock(&acct_lock); |
| 254 | if (ns->bacct == NULL) { | ||
| 255 | ns->bacct = acct; | ||
| 256 | acct = NULL; | ||
| 257 | } | ||
| 258 | |||
| 238 | mnt_pin(file->f_path.mnt); | 259 | mnt_pin(file->f_path.mnt); |
| 239 | acct_file_reopen(file); | 260 | acct_file_reopen(ns->bacct, file, ns); |
| 240 | spin_unlock(&acct_globals.lock); | 261 | spin_unlock(&acct_lock); |
| 241 | 262 | ||
| 242 | mntput(file->f_path.mnt); /* it's pinned, now give up active reference */ | 263 | mntput(file->f_path.mnt); /* it's pinned, now give up active reference */ |
| 264 | kfree(acct); | ||
| 243 | 265 | ||
| 244 | return 0; | 266 | return 0; |
| 245 | } | 267 | } |
| @@ -269,11 +291,17 @@ asmlinkage long sys_acct(const char __user *name) | |||
| 269 | error = acct_on(tmp); | 291 | error = acct_on(tmp); |
| 270 | putname(tmp); | 292 | putname(tmp); |
| 271 | } else { | 293 | } else { |
| 294 | struct bsd_acct_struct *acct; | ||
| 295 | |||
| 296 | acct = task_active_pid_ns(current)->bacct; | ||
| 297 | if (acct == NULL) | ||
| 298 | return 0; | ||
| 299 | |||
| 272 | error = security_acct(NULL); | 300 | error = security_acct(NULL); |
| 273 | if (!error) { | 301 | if (!error) { |
| 274 | spin_lock(&acct_globals.lock); | 302 | spin_lock(&acct_lock); |
| 275 | acct_file_reopen(NULL); | 303 | acct_file_reopen(acct, NULL, NULL); |
| 276 | spin_unlock(&acct_globals.lock); | 304 | spin_unlock(&acct_lock); |
| 277 | } | 305 | } |
| 278 | } | 306 | } |
| 279 | return error; | 307 | return error; |
| @@ -288,10 +316,16 @@ asmlinkage long sys_acct(const char __user *name) | |||
| 288 | */ | 316 | */ |
| 289 | void acct_auto_close_mnt(struct vfsmount *m) | 317 | void acct_auto_close_mnt(struct vfsmount *m) |
| 290 | { | 318 | { |
| 291 | spin_lock(&acct_globals.lock); | 319 | struct bsd_acct_struct *acct; |
| 292 | if (acct_globals.file && acct_globals.file->f_path.mnt == m) | 320 | |
| 293 | acct_file_reopen(NULL); | 321 | spin_lock(&acct_lock); |
| 294 | spin_unlock(&acct_globals.lock); | 322 | restart: |
| 323 | list_for_each_entry(acct, &acct_list, list) | ||
| 324 | if (acct->file && acct->file->f_path.mnt == m) { | ||
| 325 | acct_file_reopen(acct, NULL, NULL); | ||
| 326 | goto restart; | ||
| 327 | } | ||
| 328 | spin_unlock(&acct_lock); | ||
| 295 | } | 329 | } |
| 296 | 330 | ||
| 297 | /** | 331 | /** |
| @@ -303,12 +337,31 @@ void acct_auto_close_mnt(struct vfsmount *m) | |||
| 303 | */ | 337 | */ |
| 304 | void acct_auto_close(struct super_block *sb) | 338 | void acct_auto_close(struct super_block *sb) |
| 305 | { | 339 | { |
| 306 | spin_lock(&acct_globals.lock); | 340 | struct bsd_acct_struct *acct; |
| 307 | if (acct_globals.file && | 341 | |
| 308 | acct_globals.file->f_path.mnt->mnt_sb == sb) { | 342 | spin_lock(&acct_lock); |
| 309 | acct_file_reopen(NULL); | 343 | restart: |
| 344 | list_for_each_entry(acct, &acct_list, list) | ||
| 345 | if (acct->file && acct->file->f_path.mnt->mnt_sb == sb) { | ||
| 346 | acct_file_reopen(acct, NULL, NULL); | ||
| 347 | goto restart; | ||
| 348 | } | ||
| 349 | spin_unlock(&acct_lock); | ||
| 350 | } | ||
| 351 | |||
| 352 | void acct_exit_ns(struct pid_namespace *ns) | ||
| 353 | { | ||
| 354 | struct bsd_acct_struct *acct; | ||
| 355 | |||
| 356 | spin_lock(&acct_lock); | ||
| 357 | acct = ns->bacct; | ||
| 358 | if (acct != NULL) { | ||
| 359 | if (acct->file != NULL) | ||
| 360 | acct_file_reopen(acct, NULL, NULL); | ||
| 361 | |||
| 362 | kfree(acct); | ||
| 310 | } | 363 | } |
| 311 | spin_unlock(&acct_globals.lock); | 364 | spin_unlock(&acct_lock); |
| 312 | } | 365 | } |
| 313 | 366 | ||
| 314 | /* | 367 | /* |
| @@ -425,7 +478,8 @@ static u32 encode_float(u64 value) | |||
| 425 | /* | 478 | /* |
| 426 | * do_acct_process does all actual work. Caller holds the reference to file. | 479 | * do_acct_process does all actual work. Caller holds the reference to file. |
| 427 | */ | 480 | */ |
| 428 | static void do_acct_process(struct pid_namespace *ns, struct file *file) | 481 | static void do_acct_process(struct bsd_acct_struct *acct, |
| 482 | struct pid_namespace *ns, struct file *file) | ||
| 429 | { | 483 | { |
| 430 | struct pacct_struct *pacct = ¤t->signal->pacct; | 484 | struct pacct_struct *pacct = ¤t->signal->pacct; |
| 431 | acct_t ac; | 485 | acct_t ac; |
| @@ -440,7 +494,7 @@ static void do_acct_process(struct pid_namespace *ns, struct file *file) | |||
| 440 | * First check to see if there is enough free_space to continue | 494 | * First check to see if there is enough free_space to continue |
| 441 | * the process accounting system. | 495 | * the process accounting system. |
| 442 | */ | 496 | */ |
| 443 | if (!check_free_space(file)) | 497 | if (!check_free_space(acct, file)) |
| 444 | return; | 498 | return; |
| 445 | 499 | ||
| 446 | /* | 500 | /* |
| @@ -577,34 +631,46 @@ void acct_collect(long exitcode, int group_dead) | |||
| 577 | spin_unlock_irq(¤t->sighand->siglock); | 631 | spin_unlock_irq(¤t->sighand->siglock); |
| 578 | } | 632 | } |
| 579 | 633 | ||
| 580 | /** | 634 | static void acct_process_in_ns(struct pid_namespace *ns) |
| 581 | * acct_process - now just a wrapper around do_acct_process | ||
| 582 | * @exitcode: task exit code | ||
| 583 | * | ||
| 584 | * handles process accounting for an exiting task | ||
| 585 | */ | ||
| 586 | void acct_process(void) | ||
| 587 | { | 635 | { |
| 588 | struct file *file = NULL; | 636 | struct file *file = NULL; |
| 589 | struct pid_namespace *ns; | 637 | struct bsd_acct_struct *acct; |
| 590 | 638 | ||
| 639 | acct = ns->bacct; | ||
| 591 | /* | 640 | /* |
| 592 | * accelerate the common fastpath: | 641 | * accelerate the common fastpath: |
| 593 | */ | 642 | */ |
| 594 | if (!acct_globals.file) | 643 | if (!acct || !acct->file) |
| 595 | return; | 644 | return; |
| 596 | 645 | ||
| 597 | spin_lock(&acct_globals.lock); | 646 | spin_lock(&acct_lock); |
| 598 | file = acct_globals.file; | 647 | file = acct->file; |
| 599 | if (unlikely(!file)) { | 648 | if (unlikely(!file)) { |
| 600 | spin_unlock(&acct_globals.lock); | 649 | spin_unlock(&acct_lock); |
| 601 | return; | 650 | return; |
| 602 | } | 651 | } |
| 603 | get_file(file); | 652 | get_file(file); |
| 604 | ns = get_pid_ns(acct_globals.ns); | 653 | spin_unlock(&acct_lock); |
| 605 | spin_unlock(&acct_globals.lock); | ||
| 606 | 654 | ||
| 607 | do_acct_process(ns, file); | 655 | do_acct_process(acct, ns, file); |
| 608 | fput(file); | 656 | fput(file); |
| 609 | put_pid_ns(ns); | 657 | } |
| 658 | |||
| 659 | /** | ||
| 660 | * acct_process - now just a wrapper around acct_process_in_ns, | ||
| 661 | * which in turn is a wrapper around do_acct_process. | ||
| 662 | * | ||
| 663 | * handles process accounting for an exiting task | ||
| 664 | */ | ||
| 665 | void acct_process(void) | ||
| 666 | { | ||
| 667 | struct pid_namespace *ns; | ||
| 668 | |||
| 669 | /* | ||
| 670 | * This loop is safe lockless, since current is still | ||
| 671 | * alive and holds its namespace, which in turn holds | ||
| 672 | * its parent. | ||
| 673 | */ | ||
| 674 | for (ns = task_active_pid_ns(current); ns != NULL; ns = ns->parent) | ||
| 675 | acct_process_in_ns(ns); | ||
| 610 | } | 676 | } |
