[PATCH] pacct: add pacct_struct to fix some pacct bugs.
KaiGai Kohei [Sun, 25 Jun 2006 12:49:24 +0000 (05:49 -0700)]
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
include/linux/sched.h
kernel/acct.c
kernel/exit.c
kernel/fork.c

index 3d54fbc..5bca9b3 100644 (file)
@@ -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)
index 38b4791..abada7c 100644 (file)
@@ -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 */
index 44dd6bd..b352631 100644 (file)
@@ -421,9 +421,9 @@ static u32 encode_float(u64 value)
  */
 static void do_acct_process(long exitcode, struct file *file)
 {
+       struct pacct_struct *pacct = &current->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(&current->mm->mmap_sem);
-               vma = current->mm->mmap;
-               while (vma) {
-                       vsize += vma->vm_end - vma->vm_start;
-                       vma = vma->vm_next;
-               }
-               up_read(&current->mm->mmap_sem);
-       }
-       vsize = vsize / 1024;
-       ac.ac_mem = encode_comp_t(vsize);
+       spin_lock(&current->sighand->siglock);
+       ac.ac_mem = encode_comp_t(pacct->ac_mem);
+       spin_unlock(&current->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 +
@@ -546,6 +535,38 @@ static void do_acct_process(long exitcode, struct file *file)
 }
 
 /**
+ * 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 = &current->signal->pacct;
+       unsigned long vsize = 0;
+
+       if (current->mm) {
+               struct vm_area_struct *vma;
+               down_read(&current->mm->mmap_sem);
+               vma = current->mm->mmap;
+               while (vma) {
+                       vsize += vma->vm_end - vma->vm_start;
+                       vma = vma->vm_next;
+               }
+               up_read(&current->mm->mmap_sem);
+       }
+
+       spin_lock(&current->sighand->siglock);
+       pacct->ac_mem = vsize / 1024;
+       spin_unlock(&current->sighand->siglock);
+}
+
+/**
  * acct_process - now just a wrapper around do_acct_process
  * @exitcode: task exit code
  *
index 601263c..819d82c 100644 (file)
@@ -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);
index 49adc0e..dfd10cb 100644 (file)
@@ -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;
 }