From 0e4648141af02331f21aabcd34940c70f09a2d04 Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Sun, 25 Jun 2006 05:49:24 -0700 Subject: [PATCH] [PATCH] pacct: add pacct_struct to fix some pacct bugs. The pacct facility need an i/o operation when an accounting record is generated. There is a possibility to wake OOM killer up. If OOM killer is activated, it kills some processes to make them release process memory regions. But acct_process() is called in the killed processes context before calling exit_mm(), so those processes cannot release own memory. In the results, any processes stop in this point and it finally cause a system stall. --- include/linux/acct.h | 4 ++++ include/linux/sched.h | 7 ++++++ kernel/acct.c | 51 ++++++++++++++++++++++++++++++------------- kernel/exit.c | 4 +++- kernel/fork.c | 1 + 5 files changed, 51 insertions(+), 16 deletions(-) diff --git a/include/linux/acct.h b/include/linux/acct.h index 3d54fbcf969e..5bca9b3ef2d7 100644 --- a/include/linux/acct.h +++ b/include/linux/acct.h @@ -121,12 +121,16 @@ struct vfsmount; struct super_block; extern void acct_auto_close_mnt(struct vfsmount *m); extern void acct_auto_close(struct super_block *sb); +extern void acct_init_pacct(struct pacct_struct *pacct); +extern void acct_collect(); extern void acct_process(long exitcode); extern void acct_update_integrals(struct task_struct *tsk); extern void acct_clear_integrals(struct task_struct *tsk); #else #define acct_auto_close_mnt(x) do { } while (0) #define acct_auto_close(x) do { } while (0) +#define acct_init_pacct(x) do { } while (0) +#define acct_collect() do { } while (0) #define acct_process(x) do { } while (0) #define acct_update_integrals(x) do { } while (0) #define acct_clear_integrals(task) do { } while (0) diff --git a/include/linux/sched.h b/include/linux/sched.h index 38b4791e6a5d..abada7c1d5e4 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -358,6 +358,10 @@ struct sighand_struct { spinlock_t siglock; }; +struct pacct_struct { + unsigned long ac_mem; +}; + /* * NOTE! "signal_struct" does not have it's own * locking, because a shared signal_struct always @@ -449,6 +453,9 @@ struct signal_struct { struct key *session_keyring; /* keyring inherited over fork */ struct key *process_keyring; /* keyring private to this process */ #endif +#ifdef CONFIG_BSD_PROCESS_ACCT + struct pacct_struct pacct; /* per-process accounting information */ +#endif }; /* Context switch must be unlocked if interrupts are to be enabled */ diff --git a/kernel/acct.c b/kernel/acct.c index 44dd6bd63517..b35263137824 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -421,9 +421,9 @@ static u32 encode_float(u64 value) */ static void do_acct_process(long exitcode, struct file *file) { + struct pacct_struct *pacct = ¤t->signal->pacct; acct_t ac; mm_segment_t fs; - unsigned long vsize; unsigned long flim; u64 elapsed; u64 run_time; @@ -505,20 +505,9 @@ static void do_acct_process(long exitcode, struct file *file) ac.ac_flag |= ACORE; if (current->flags & PF_SIGNALED) ac.ac_flag |= AXSIG; - - vsize = 0; - if (current->mm) { - struct vm_area_struct *vma; - down_read(¤t->mm->mmap_sem); - vma = current->mm->mmap; - while (vma) { - vsize += vma->vm_end - vma->vm_start; - vma = vma->vm_next; - } - up_read(¤t->mm->mmap_sem); - } - vsize = vsize / 1024; - ac.ac_mem = encode_comp_t(vsize); + spin_lock(¤t->sighand->siglock); + ac.ac_mem = encode_comp_t(pacct->ac_mem); + spin_unlock(¤t->sighand->siglock); ac.ac_io = encode_comp_t(0 /* current->io_usage */); /* %% */ ac.ac_rw = encode_comp_t(ac.ac_io / 1024); ac.ac_minflt = encode_comp_t(current->signal->min_flt + @@ -545,6 +534,38 @@ static void do_acct_process(long exitcode, struct file *file) set_fs(fs); } +/** + * acct_init_pacct - initialize a new pacct_struct + */ +void acct_init_pacct(struct pacct_struct *pacct) +{ + memset(pacct, 0, sizeof(struct pacct_struct)); +} + +/** + * acct_collect - collect accounting information into pacct_struct + */ +void acct_collect(void) +{ + struct pacct_struct *pacct = ¤t->signal->pacct; + unsigned long vsize = 0; + + if (current->mm) { + struct vm_area_struct *vma; + down_read(¤t->mm->mmap_sem); + vma = current->mm->mmap; + while (vma) { + vsize += vma->vm_end - vma->vm_start; + vma = vma->vm_next; + } + up_read(¤t->mm->mmap_sem); + } + + spin_lock(¤t->sighand->siglock); + pacct->ac_mem = vsize / 1024; + spin_unlock(¤t->sighand->siglock); +} + /** * acct_process - now just a wrapper around do_acct_process * @exitcode: task exit code diff --git a/kernel/exit.c b/kernel/exit.c index 601263c0806f..819d82c2efba 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -894,7 +894,7 @@ fastcall NORET_TYPE void do_exit(long code) if (group_dead) { hrtimer_cancel(&tsk->signal->real_timer); exit_itimers(tsk->signal); - acct_process(code); + acct_collect(); } if (unlikely(tsk->robust_list)) exit_robust_list(tsk); @@ -906,6 +906,8 @@ fastcall NORET_TYPE void do_exit(long code) audit_free(tsk); exit_mm(tsk); + if (group_dead) + acct_process(code); exit_sem(tsk); __exit_files(tsk); __exit_fs(tsk); diff --git a/kernel/fork.c b/kernel/fork.c index 49adc0e8d47c..dfd10cb370c3 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -874,6 +874,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts tsk->it_prof_expires = secs_to_cputime(sig->rlim[RLIMIT_CPU].rlim_cur); } + acct_init_pacct(&sig->pacct); return 0; }