acct.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:9k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/kernel/acct.c
  3.  *
  4.  *  BSD Process Accounting for Linux
  5.  *
  6.  *  Author: Marco van Wieringen <mvw@planets.elm.net>
  7.  *
  8.  *  Some code based on ideas and code from:
  9.  *  Thomas K. Dyas <tdyas@eden.rutgers.edu>
  10.  *
  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.
  16.  *
  17.  * (C) Copyright 1995 - 1997 Marco van Wieringen - ELM Consultancy B.V.
  18.  *
  19.  *  Plugged two leaks. 1) It didn't return acct_file into the free_filps if
  20.  *  the file happened to be read-only. 2) If the accounting was suspended
  21.  *  due to the lack of space it happily allowed to reopen it and completely
  22.  *  lost the old acct_file. 3/10/98, Al Viro.
  23.  *
  24.  *  Now we silently close acct_file on attempt to reopen. Cleaned sys_acct().
  25.  *  XTerms and EMACS are manifestations of pure evil. 21/10/98, AV.
  26.  *
  27.  *  Fixed a nasty interaction with with sys_umount(). If the accointing
  28.  *  was suspeneded we failed to stop it on umount(). Messy.
  29.  *  Another one: remount to readonly didn't stop accounting.
  30.  * Question: what should we do if we have CAP_SYS_ADMIN but not
  31.  *  CAP_SYS_PACCT? Current code does the following: umount returns -EBUSY
  32.  *  unless we are messing with the root. In that case we are getting a
  33.  *  real mess with do_remount_sb(). 9/11/98, AV.
  34.  *
  35.  *  Fixed a bunch of races (and pair of leaks). Probably not the best way,
  36.  *  but this one obviously doesn't introduce deadlocks. Later. BTW, found
  37.  *  one race (and leak) in BSD implementation.
  38.  *  OK, that's better. ANOTHER race and leak in BSD variant. There always
  39.  *  is one more bug... 10/11/98, AV.
  40.  *
  41.  * Oh, fsck... Oopsable SMP race in do_process_acct() - we must hold
  42.  * ->mmap_sem to walk the vma list of current->mm. Nasty, since it leaks
  43.  * a struct file opened for write. Fixed. 2/6/2000, AV.
  44.  */
  45. #include <linux/config.h>
  46. #include <linux/errno.h>
  47. #include <linux/kernel.h>
  48. #ifdef CONFIG_BSD_PROCESS_ACCT
  49. #include <linux/mm.h>
  50. #include <linux/slab.h>
  51. #include <linux/acct.h>
  52. #include <linux/smp_lock.h>
  53. #include <linux/file.h>
  54. #include <linux/tty.h>
  55. #include <asm/uaccess.h>
  56. /*
  57.  * These constants control the amount of freespace that suspend and
  58.  * resume the process accounting system, and the time delay between
  59.  * each check.
  60.  * Turned into sysctl-controllable parameters. AV, 12/11/98
  61.  */
  62. int acct_parm[3] = {4, 2, 30};
  63. #define RESUME (acct_parm[0]) /* >foo% free space - resume */
  64. #define SUSPEND (acct_parm[1]) /* <foo% free space - suspend */
  65. #define ACCT_TIMEOUT (acct_parm[2]) /* foo second timeout between checks */
  66. /*
  67.  * External references and all of the globals.
  68.  */
  69. static volatile int acct_active;
  70. static volatile int acct_needcheck;
  71. static struct file *acct_file;
  72. static struct timer_list acct_timer;
  73. static void do_acct_process(long, struct file *);
  74. /*
  75.  * Called whenever the timer says to check the free space.
  76.  */
  77. static void acct_timeout(unsigned long unused)
  78. {
  79. acct_needcheck = 1;
  80. }
  81. /*
  82.  * Check the amount of free space and suspend/resume accordingly.
  83.  */
  84. static int check_free_space(struct file *file)
  85. {
  86. struct statfs sbuf;
  87. int res;
  88. int act;
  89. lock_kernel();
  90. res = acct_active;
  91. if (!file || !acct_needcheck)
  92. goto out;
  93. unlock_kernel();
  94. /* May block */
  95. if (vfs_statfs(file->f_dentry->d_inode->i_sb, &sbuf))
  96. return res;
  97. if (sbuf.f_bavail <= SUSPEND * sbuf.f_blocks / 100)
  98. act = -1;
  99. else if (sbuf.f_bavail >= RESUME * sbuf.f_blocks / 100)
  100. act = 1;
  101. else
  102. act = 0;
  103. /*
  104.  * If some joker switched acct_file under us we'ld better be
  105.  * silent and _not_ touch anything.
  106.  */
  107. lock_kernel();
  108. if (file != acct_file) {
  109. if (act)
  110. res = act>0;
  111. goto out;
  112. }
  113. if (acct_active) {
  114. if (act < 0) {
  115. acct_active = 0;
  116. printk(KERN_INFO "Process accounting pausedn");
  117. }
  118. } else {
  119. if (act > 0) {
  120. acct_active = 1;
  121. printk(KERN_INFO "Process accounting resumedn");
  122. }
  123. }
  124. del_timer(&acct_timer);
  125. acct_needcheck = 0;
  126. acct_timer.expires = jiffies + ACCT_TIMEOUT*HZ;
  127. add_timer(&acct_timer);
  128. res = acct_active;
  129. out:
  130. unlock_kernel();
  131. return res;
  132. }
  133. /*
  134.  *  sys_acct() is the only system call needed to implement process
  135.  *  accounting. It takes the name of the file where accounting records
  136.  *  should be written. If the filename is NULL, accounting will be
  137.  *  shutdown.
  138.  */
  139. asmlinkage long sys_acct(const char *name)
  140. {
  141. struct file *file = NULL, *old_acct = NULL;
  142. char *tmp;
  143. int error;
  144. if (!capable(CAP_SYS_PACCT))
  145. return -EPERM;
  146. if (name) {
  147. tmp = getname(name);
  148. error = PTR_ERR(tmp);
  149. if (IS_ERR(tmp))
  150. goto out;
  151. /* Difference from BSD - they don't do O_APPEND */
  152. file = filp_open(tmp, O_WRONLY|O_APPEND, 0);
  153. putname(tmp);
  154. if (IS_ERR(file)) {
  155. error = PTR_ERR(file);
  156. goto out;
  157. }
  158. error = -EACCES;
  159. if (!S_ISREG(file->f_dentry->d_inode->i_mode)) 
  160. goto out_err;
  161. error = -EIO;
  162. if (!file->f_op->write) 
  163. goto out_err;
  164. }
  165. error = 0;
  166. lock_kernel();
  167. if (acct_file) {
  168. old_acct = acct_file;
  169. del_timer(&acct_timer);
  170. acct_active = 0;
  171. acct_needcheck = 0;
  172. acct_file = NULL;
  173. }
  174. if (name) {
  175. acct_file = file;
  176. acct_needcheck = 0;
  177. acct_active = 1;
  178. /* It's been deleted if it was used before so this is safe */
  179. init_timer(&acct_timer);
  180. acct_timer.function = acct_timeout;
  181. acct_timer.expires = jiffies + ACCT_TIMEOUT*HZ;
  182. add_timer(&acct_timer);
  183. }
  184. unlock_kernel();
  185. if (old_acct) {
  186. do_acct_process(0,old_acct);
  187. filp_close(old_acct, NULL);
  188. }
  189. out:
  190. return error;
  191. out_err:
  192. filp_close(file, NULL);
  193. goto out;
  194. }
  195. void acct_auto_close(kdev_t dev)
  196. {
  197. lock_kernel();
  198. if (acct_file && acct_file->f_dentry->d_inode->i_dev == dev)
  199. sys_acct(NULL);
  200. unlock_kernel();
  201. }
  202. /*
  203.  *  encode an unsigned long into a comp_t
  204.  *
  205.  *  This routine has been adopted from the encode_comp_t() function in
  206.  *  the kern_acct.c file of the FreeBSD operating system. The encoding
  207.  *  is a 13-bit fraction with a 3-bit (base 8) exponent.
  208.  */
  209. #define MANTSIZE 13 /* 13 bit mantissa. */
  210. #define EXPSIZE 3 /* Base 8 (3 bit) exponent. */
  211. #define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */
  212. static comp_t encode_comp_t(unsigned long value)
  213. {
  214. int exp, rnd;
  215. exp = rnd = 0;
  216. while (value > MAXFRACT) {
  217. rnd = value & (1 << (EXPSIZE - 1)); /* Round up? */
  218. value >>= EXPSIZE; /* Base 8 exponent == 3 bit shift. */
  219. exp++;
  220. }
  221. /*
  222.          * If we need to round up, do it (and handle overflow correctly).
  223.          */
  224. if (rnd && (++value > MAXFRACT)) {
  225. value >>= EXPSIZE;
  226. exp++;
  227. }
  228. /*
  229.          * Clean it up and polish it off.
  230.          */
  231. exp <<= MANTSIZE; /* Shift the exponent into place */
  232. exp += value; /* and add on the mantissa. */
  233. return exp;
  234. }
  235. /*
  236.  *  Write an accounting entry for an exiting process
  237.  *
  238.  *  The acct_process() call is the workhorse of the process
  239.  *  accounting system. The struct acct is built here and then written
  240.  *  into the accounting file. This function should only be called from
  241.  *  do_exit().
  242.  */
  243. /*
  244.  *  do_acct_process does all actual work. Caller holds the reference to file.
  245.  */
  246. static void do_acct_process(long exitcode, struct file *file)
  247. {
  248. struct acct ac;
  249. mm_segment_t fs;
  250. unsigned long vsize;
  251. /*
  252.  * First check to see if there is enough free_space to continue
  253.  * the process accounting system.
  254.  */
  255. if (!check_free_space(file))
  256. return;
  257. /*
  258.  * Fill the accounting struct with the needed info as recorded
  259.  * by the different kernel functions.
  260.  */
  261. memset((caddr_t)&ac, 0, sizeof(struct acct));
  262. strncpy(ac.ac_comm, current->comm, ACCT_COMM);
  263. ac.ac_comm[ACCT_COMM - 1] = '';
  264. ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
  265. ac.ac_etime = encode_comp_t(jiffies - current->start_time);
  266. ac.ac_utime = encode_comp_t(current->times.tms_utime);
  267. ac.ac_stime = encode_comp_t(current->times.tms_stime);
  268. ac.ac_uid = current->uid;
  269. ac.ac_gid = current->gid;
  270. ac.ac_tty = (current->tty) ? kdev_t_to_nr(current->tty->device) : 0;
  271. ac.ac_flag = 0;
  272. if (current->flags & PF_FORKNOEXEC)
  273. ac.ac_flag |= AFORK;
  274. if (current->flags & PF_SUPERPRIV)
  275. ac.ac_flag |= ASU;
  276. if (current->flags & PF_DUMPCORE)
  277. ac.ac_flag |= ACORE;
  278. if (current->flags & PF_SIGNALED)
  279. ac.ac_flag |= AXSIG;
  280. vsize = 0;
  281. if (current->mm) {
  282. struct vm_area_struct *vma;
  283. down_read(&current->mm->mmap_sem);
  284. vma = current->mm->mmap;
  285. while (vma) {
  286. vsize += vma->vm_end - vma->vm_start;
  287. vma = vma->vm_next;
  288. }
  289. up_read(&current->mm->mmap_sem);
  290. }
  291. vsize = vsize / 1024;
  292. ac.ac_mem = encode_comp_t(vsize);
  293. ac.ac_io = encode_comp_t(0 /* current->io_usage */); /* %% */
  294. ac.ac_rw = encode_comp_t(ac.ac_io / 1024);
  295. ac.ac_minflt = encode_comp_t(current->min_flt);
  296. ac.ac_majflt = encode_comp_t(current->maj_flt);
  297. ac.ac_swaps = encode_comp_t(current->nswap);
  298. ac.ac_exitcode = exitcode;
  299. /*
  300.          * Kernel segment override to datasegment and write it
  301.          * to the accounting file.
  302.          */
  303. fs = get_fs();
  304. set_fs(KERNEL_DS);
  305. file->f_op->write(file, (char *)&ac,
  306.        sizeof(struct acct), &file->f_pos);
  307. set_fs(fs);
  308. }
  309. /*
  310.  * acct_process - now just a wrapper around do_acct_process
  311.  */
  312. int acct_process(long exitcode)
  313. {
  314. struct file *file = NULL;
  315. lock_kernel();
  316. if (acct_file) {
  317. file = acct_file;
  318. get_file(file);
  319. unlock_kernel();
  320. do_acct_process(exitcode, acct_file);
  321. fput(file);
  322. } else
  323. unlock_kernel();
  324. return 0;
  325. }
  326. #else
  327. /*
  328.  * Dummy system call when BSD process accounting is not configured
  329.  * into the kernel.
  330.  */
  331. asmlinkage long sys_acct(const char * filename)
  332. {
  333. return -ENOSYS;
  334. }
  335. #endif