4 * BSD Process Accounting for Linux
6 * Author: Marco van Wieringen <mvw@planets.elm.net>
8 * Some code based on ideas and code from:
9 * Thomas K. Dyas <tdyas@eden.rutgers.edu>
11 * This file implements BSD-style process accounting. Whenever any
12 * process exits, an accounting record of type "struct acct" is
13 * written to the file specified with the acct() system call. It is
14 * up to user-level programs to do useful things with the accounting
15 * log. The kernel just provides the raw accounting information.
17 * (C) Copyright 1995 - 1997 Marco van Wieringen - ELM Consultancy B.V.
21 #include <linux/config.h>
22 #include <linux/errno.h>
23 #include <linux/kernel.h>
25 #ifdef CONFIG_BSD_PROCESS_ACCT
27 #include <linux/vfs.h>
28 #include <linux/types.h>
29 #include <linux/fcntl.h>
30 #include <linux/stat.h>
31 #include <linux/sched.h>
33 #include <linux/timer.h>
34 #include <linux/tty.h>
35 #include <linux/acct.h>
36 #include <linux/major.h>
37 #include <linux/smp.h>
38 #include <linux/smp_lock.h>
40 #include <asm/uaccess.h>
43 * These constants control the amount of freespace that suspend and
44 * resume the process accounting system, and the time delay between
48 #define RESUME (4) /* More than 4% free space will resume */
49 #define SUSPEND (2) /* Less than 2% free space will suspend */
50 #define ACCT_TIMEOUT (30 * HZ) /* 30 second timeout between checks */
53 * External references and all of the globals.
55 extern int close_fp(struct file
*);
57 void acct_timeout(unsigned long);
59 static volatile int acct_active
= 0;
60 static volatile int acct_needcheck
= 0;
61 static struct file
*acct_file
= NULL
;
62 static struct timer_list acct_timer
= { NULL
, NULL
, 0, 0, acct_timeout
};
65 * Called whenever the timer says to check the free space.
67 void acct_timeout(unsigned long unused
)
73 * Check the amount of free space and suspend/resume accordingly.
75 static void check_free_space(void)
80 if (!acct_file
|| !acct_needcheck
)
83 if (!acct_file
->f_dentry
->d_inode
->i_sb
->s_op
||
84 !acct_file
->f_dentry
->d_inode
->i_sb
->s_op
->statfs
)
89 acct_file
->f_dentry
->d_inode
->i_sb
->s_op
->statfs(acct_file
->f_dentry
->d_inode
->i_sb
, &sbuf
, sizeof(struct statfs
));
93 if (sbuf
.f_bavail
<= SUSPEND
* sbuf
.f_blocks
/ 100) {
95 printk(KERN_INFO
"Process accounting paused\r\n");
98 if (sbuf
.f_bavail
>= RESUME
* sbuf
.f_blocks
/ 100) {
100 printk(KERN_INFO
"Process accounting resumed\r\n");
103 del_timer(&acct_timer
);
105 acct_timer
.expires
= jiffies
+ ACCT_TIMEOUT
;
106 add_timer(&acct_timer
);
110 * sys_acct() is the only system call needed to implement process
111 * accounting. It takes the name of the file where accounting records
112 * should be written. If the filename is NULL, accounting will be
115 asmlinkage
int sys_acct(const char *name
)
117 struct dentry
*dentry
;
126 if (name
== (char *)NULL
) {
129 del_timer(&acct_timer
);
139 error
= PTR_ERR(tmp
);
143 dentry
= open_namei(tmp
, O_RDWR
, 0600);
146 error
= PTR_ERR(dentry
);
150 inode
= dentry
->d_inode
;
152 if (!S_ISREG(inode
->i_mode
)) {
158 if (!inode
->i_op
|| !inode
->i_op
->default_file_ops
||
159 !inode
->i_op
->default_file_ops
->write
) {
165 if ((acct_file
= get_empty_filp()) != (struct file
*)NULL
) {
166 acct_file
->f_mode
= (O_WRONLY
+ 1) & O_ACCMODE
;
167 acct_file
->f_flags
= O_WRONLY
;
168 acct_file
->f_dentry
= dentry
;
169 acct_file
->f_pos
= inode
->i_size
;
170 acct_file
->f_reada
= 0;
171 acct_file
->f_op
= inode
->i_op
->default_file_ops
;
172 if ((error
= get_write_access(acct_file
->f_dentry
->d_inode
)) == 0) {
173 if (acct_file
->f_op
&& acct_file
->f_op
->open
)
174 error
= acct_file
->f_op
->open(inode
, acct_file
);
178 acct_timer
.expires
= jiffies
+ ACCT_TIMEOUT
;
179 add_timer(&acct_timer
);
183 put_write_access(acct_file
->f_dentry
->d_inode
);
185 acct_file
->f_count
--;
197 void acct_auto_close(kdev_t dev
)
199 if (acct_active
&& acct_file
&& acct_file
->f_dentry
->d_inode
->i_dev
== dev
)
200 sys_acct((char *)NULL
);
204 * encode an unsigned long into a comp_t
206 * This routine has been adopted from the encode_comp_t() function in
207 * the kern_acct.c file of the FreeBSD operating system. The encoding
208 * is a 13-bit fraction with a 3-bit (base 8) exponent.
211 #define MANTSIZE 13 /* 13 bit mantissa. */
212 #define EXPSIZE 3 /* Base 8 (3 bit) exponent. */
213 #define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */
215 static comp_t
encode_comp_t(unsigned long value
)
220 while (value
> MAXFRACT
) {
221 rnd
= value
& (1 << (EXPSIZE
- 1)); /* Round up? */
222 value
>>= EXPSIZE
; /* Base 8 exponent == 3 bit shift. */
227 * If we need to round up, do it (and handle overflow correctly).
229 if (rnd
&& (++value
> MAXFRACT
)) {
235 * Clean it up and polish it off.
237 exp
<<= MANTSIZE
; /* Shift the exponent into place */
238 exp
+= value
; /* and add on the mantissa. */
243 * Write an accounting entry for an exiting process
245 * The acct_process() call is the workhorse of the process
246 * accounting system. The struct acct is built here and then written
247 * into the accounting file. This function should only be called from
250 #define KSTK_EIP(stack) (((unsigned long *)(stack))[1019])
251 #define KSTK_ESP(stack) (((unsigned long *)(stack))[1022])
253 int acct_process(long exitcode
)
260 * First check to see if there is enough free_space to continue the process
261 * accounting system. Check_free_space toggle's the acct_active flag so we
262 * need to check that after check_free_space.
271 * Fill the accounting struct with the needed info as recorded
272 * by the different kernel functions.
274 memset((caddr_t
)&ac
, 0, sizeof(struct acct
));
276 strncpy(ac
.ac_comm
, current
->comm
, ACCT_COMM
);
277 ac
.ac_comm
[ACCT_COMM
- 1] = '\0';
279 ac
.ac_btime
= CT_TO_SECS(current
->start_time
) + (xtime
.tv_sec
- (jiffies
/ HZ
));
280 ac
.ac_etime
= encode_comp_t(jiffies
- current
->start_time
);
281 ac
.ac_utime
= encode_comp_t(current
->times
.tms_utime
);
282 ac
.ac_stime
= encode_comp_t(current
->times
.tms_stime
);
283 ac
.ac_uid
= current
->uid
;
284 ac
.ac_gid
= current
->gid
;
285 ac
.ac_tty
= (current
->tty
) ? kdev_t_to_nr(current
->tty
->device
) : 0;
288 if (current
->flags
& PF_FORKNOEXEC
)
290 if (current
->flags
& PF_SUPERPRIV
)
292 if (current
->flags
& PF_DUMPCORE
)
294 if (current
->flags
& PF_SIGNALED
)
299 struct vm_area_struct
*vma
= current
->mm
->mmap
;
301 vsize
+= vma
->vm_end
- vma
->vm_start
;
305 vsize
= vsize
/ 1024;
306 ac
.ac_mem
= encode_comp_t(vsize
);
307 ac
.ac_io
= encode_comp_t(current
->io_usage
); /* %% */
308 ac
.ac_rw
= encode_comp_t(ac
.ac_io
/ 1024);
309 ac
.ac_minflt
= encode_comp_t(current
->min_flt
);
310 ac
.ac_majflt
= encode_comp_t(current
->maj_flt
);
311 ac
.ac_swaps
= encode_comp_t(current
->nswap
);
312 ac
.ac_exitcode
= exitcode
;
315 * Kernel segment override to datasegment and write it to the accounting file.
319 acct_file
->f_op
->write(acct_file
, (char *)&ac
,
320 sizeof(struct acct
), &acct_file
->f_pos
);
327 * Dummy system call when BSD process accounting is not configured
331 asmlinkage
int sys_acct(const char * filename
)