2005-04-17 02:20:36 +04:00
/*
* linux / kernel / acct . c
*
* BSD Process Accounting for Linux
*
* Author : Marco van Wieringen < mvw @ planets . elm . net >
*
* Some code based on ideas and code from :
* Thomas K . Dyas < tdyas @ eden . rutgers . edu >
*
* This file implements BSD - style process accounting . Whenever any
* process exits , an accounting record of type " struct acct " is
* written to the file specified with the acct ( ) system call . It is
* up to user - level programs to do useful things with the accounting
* log . The kernel just provides the raw accounting information .
*
* ( C ) Copyright 1995 - 1997 Marco van Wieringen - ELM Consultancy B . V .
*
* Plugged two leaks . 1 ) It didn ' t return acct_file into the free_filps if
* the file happened to be read - only . 2 ) If the accounting was suspended
* due to the lack of space it happily allowed to reopen it and completely
* lost the old acct_file . 3 / 10 / 98 , Al Viro .
*
* Now we silently close acct_file on attempt to reopen . Cleaned sys_acct ( ) .
* XTerms and EMACS are manifestations of pure evil . 21 / 10 / 98 , AV .
*
* Fixed a nasty interaction with with sys_umount ( ) . If the accointing
* was suspeneded we failed to stop it on umount ( ) . Messy .
* Another one : remount to readonly didn ' t stop accounting .
* Question : what should we do if we have CAP_SYS_ADMIN but not
* CAP_SYS_PACCT ? Current code does the following : umount returns - EBUSY
* unless we are messing with the root . In that case we are getting a
* real mess with do_remount_sb ( ) . 9 / 11 / 98 , AV .
*
* Fixed a bunch of races ( and pair of leaks ) . Probably not the best way ,
* but this one obviously doesn ' t introduce deadlocks . Later . BTW , found
* one race ( and leak ) in BSD implementation .
* OK , that ' s better . ANOTHER race and leak in BSD variant . There always
* is one more bug . . . 10 / 11 / 98 , AV .
*
* Oh , fsck . . . Oopsable SMP race in do_process_acct ( ) - we must hold
* - > mmap_sem to walk the vma list of current - > mm . Nasty , since it leaks
* a struct file opened for write . Fixed . 2 / 6 / 2000 , AV .
*/
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/acct.h>
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/file.h>
# include <linux/tty.h>
# include <linux/security.h>
# include <linux/vfs.h>
# include <linux/jiffies.h>
# include <linux/times.h>
# include <linux/syscalls.h>
2005-11-08 01:13:39 +03:00
# include <linux/mount.h>
2014-06-07 01:37:37 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <asm/div64.h>
# include <linux/blkdev.h> /* sector_div */
2008-03-24 22:29:53 +03:00
# include <linux/pid_namespace.h>
2014-08-07 16:39:04 +04:00
# include <linux/fs_pin.h>
2005-04-17 02:20:36 +04:00
/*
* These constants control the amount of freespace that suspend and
* resume the process accounting system , and the time delay between
* each check .
* Turned into sysctl - controllable parameters . AV , 12 / 11 / 98
*/
int acct_parm [ 3 ] = { 4 , 2 , 30 } ;
# define RESUME (acct_parm[0]) /* >foo% free space - resume */
# define SUSPEND (acct_parm[1]) /* <foo% free space - suspend */
# define ACCT_TIMEOUT (acct_parm[2]) /* foo second timeout between checks */
/*
* External references and all of the globals .
*/
2014-08-07 16:00:52 +04:00
struct bsd_acct_struct {
struct fs_pin pin ;
2015-01-10 20:47:38 +03:00
atomic_long_t count ;
struct rcu_head rcu ;
2014-08-07 15:51:03 +04:00
struct mutex lock ;
2011-12-09 05:08:42 +04:00
int active ;
unsigned long needcheck ;
2005-04-17 02:20:36 +04:00
struct file * file ;
2008-03-24 22:29:53 +03:00
struct pid_namespace * ns ;
2014-08-07 15:35:19 +04:00
struct work_struct work ;
struct completion done ;
2005-04-17 02:20:36 +04:00
} ;
2015-01-11 01:53:21 +03:00
static void do_acct_process ( struct bsd_acct_struct * acct ) ;
2005-04-17 02:20:36 +04:00
/*
* Check the amount of free space and suspend / resume accordingly .
*/
2014-04-19 22:24:18 +04:00
static int check_free_space ( struct bsd_acct_struct * acct )
2005-04-17 02:20:36 +04:00
{
struct kstatfs sbuf ;
2014-04-19 22:24:18 +04:00
if ( time_is_before_jiffies ( acct - > needcheck ) )
2005-04-17 02:20:36 +04:00
goto out ;
/* May block */
2014-04-19 22:24:18 +04:00
if ( vfs_statfs ( & acct - > file - > f_path , & sbuf ) )
2005-04-17 02:20:36 +04:00
goto out ;
2008-07-25 12:48:46 +04:00
if ( acct - > active ) {
2014-04-19 22:24:18 +04:00
u64 suspend = sbuf . f_blocks * SUSPEND ;
do_div ( suspend , 100 ) ;
if ( sbuf . f_bavail < = suspend ) {
2008-07-25 12:48:46 +04:00
acct - > active = 0 ;
2014-07-31 03:28:36 +04:00
pr_info ( " Process accounting paused \n " ) ;
2005-04-17 02:20:36 +04:00
}
} else {
2014-04-19 22:24:18 +04:00
u64 resume = sbuf . f_blocks * RESUME ;
do_div ( resume , 100 ) ;
if ( sbuf . f_bavail > = resume ) {
2008-07-25 12:48:46 +04:00
acct - > active = 1 ;
2014-07-31 03:28:36 +04:00
pr_info ( " Process accounting resumed \n " ) ;
2005-04-17 02:20:36 +04:00
}
}
2011-12-09 05:08:42 +04:00
acct - > needcheck = jiffies + ACCT_TIMEOUT * HZ ;
2005-04-17 02:20:36 +04:00
out :
2014-04-19 22:24:18 +04:00
return acct - > active ;
2005-04-17 02:20:36 +04:00
}
2015-01-10 04:40:02 +03:00
static void acct_put ( struct bsd_acct_struct * p )
{
2015-01-10 20:47:38 +03:00
if ( atomic_long_dec_and_test ( & p - > count ) )
kfree_rcu ( p , rcu ) ;
2015-01-10 04:40:02 +03:00
}
2015-01-11 01:53:21 +03:00
static inline struct bsd_acct_struct * to_acct ( struct fs_pin * p )
{
return p ? container_of ( p , struct bsd_acct_struct , pin ) : NULL ;
}
2014-08-07 14:23:41 +04:00
static struct bsd_acct_struct * acct_get ( struct pid_namespace * ns )
2014-08-07 15:51:03 +04:00
{
struct bsd_acct_struct * res ;
again :
2014-08-07 15:04:28 +04:00
smp_rmb ( ) ;
rcu_read_lock ( ) ;
2015-01-11 01:53:21 +03:00
res = to_acct ( ACCESS_ONCE ( ns - > bacct ) ) ;
2014-08-07 15:04:28 +04:00
if ( ! res ) {
rcu_read_unlock ( ) ;
2014-08-07 14:23:41 +04:00
return NULL ;
2005-04-17 02:20:36 +04:00
}
2015-01-10 20:47:38 +03:00
if ( ! atomic_long_inc_not_zero ( & res - > count ) ) {
2014-08-07 16:39:04 +04:00
rcu_read_unlock ( ) ;
cpu_relax ( ) ;
2014-08-07 14:23:41 +04:00
goto again ;
2014-08-07 16:39:04 +04:00
}
rcu_read_unlock ( ) ;
mutex_lock ( & res - > lock ) ;
2015-01-11 01:53:21 +03:00
if ( res ! = to_acct ( ACCESS_ONCE ( ns - > bacct ) ) ) {
2014-08-07 16:39:04 +04:00
mutex_unlock ( & res - > lock ) ;
2015-01-10 04:40:02 +03:00
acct_put ( res ) ;
2014-08-07 16:39:04 +04:00
goto again ;
}
2014-08-07 15:51:03 +04:00
return res ;
}
2015-01-11 01:53:21 +03:00
static void acct_pin_kill ( struct fs_pin * pin )
{
struct bsd_acct_struct * acct = to_acct ( pin ) ;
mutex_lock ( & acct - > lock ) ;
do_acct_process ( acct ) ;
schedule_work ( & acct - > work ) ;
wait_for_completion ( & acct - > done ) ;
cmpxchg ( & acct - > ns - > bacct , pin , NULL ) ;
mutex_unlock ( & acct - > lock ) ;
pin_remove ( pin ) ;
acct_put ( acct ) ;
}
2014-08-07 15:35:19 +04:00
static void close_work ( struct work_struct * work )
{
struct bsd_acct_struct * acct = container_of ( work , struct bsd_acct_struct , work ) ;
struct file * file = acct - > file ;
if ( file - > f_op - > flush )
file - > f_op - > flush ( file , NULL ) ;
__fput_sync ( file ) ;
complete ( & acct - > done ) ;
}
2012-10-11 00:43:10 +04:00
static int acct_on ( struct filename * pathname )
2005-11-08 01:13:39 +03:00
{
struct file * file ;
2014-08-07 17:12:31 +04:00
struct vfsmount * mnt , * internal ;
2014-08-07 15:51:03 +04:00
struct pid_namespace * ns = task_active_pid_ns ( current ) ;
2015-01-11 01:53:21 +03:00
struct bsd_acct_struct * acct ;
struct fs_pin * old ;
2014-08-07 17:12:31 +04:00
int err ;
2014-08-07 15:51:03 +04:00
acct = kzalloc ( sizeof ( struct bsd_acct_struct ) , GFP_KERNEL ) ;
if ( ! acct )
return - ENOMEM ;
2005-11-08 01:13:39 +03:00
/* Difference from BSD - they don't do O_APPEND */
2012-10-11 00:43:10 +04:00
file = file_open_name ( pathname , O_WRONLY | O_APPEND | O_LARGEFILE , 0 ) ;
2014-08-07 15:51:03 +04:00
if ( IS_ERR ( file ) ) {
kfree ( acct ) ;
2005-11-08 01:13:39 +03:00
return PTR_ERR ( file ) ;
2014-08-07 15:51:03 +04:00
}
2005-11-08 01:13:39 +03:00
2013-01-24 02:07:38 +04:00
if ( ! S_ISREG ( file_inode ( file ) - > i_mode ) ) {
2014-08-07 15:51:03 +04:00
kfree ( acct ) ;
2005-11-08 01:13:39 +03:00
filp_close ( file , NULL ) ;
return - EACCES ;
}
2015-03-31 19:30:48 +03:00
if ( ! ( file - > f_mode & FMODE_CAN_WRITE ) ) {
2014-08-07 15:51:03 +04:00
kfree ( acct ) ;
2005-11-08 01:13:39 +03:00
filp_close ( file , NULL ) ;
return - EIO ;
}
2014-08-07 17:12:31 +04:00
internal = mnt_clone_internal ( & file - > f_path ) ;
if ( IS_ERR ( internal ) ) {
kfree ( acct ) ;
filp_close ( file , NULL ) ;
return PTR_ERR ( internal ) ;
}
err = mnt_want_write ( internal ) ;
if ( err ) {
mntput ( internal ) ;
kfree ( acct ) ;
filp_close ( file , NULL ) ;
return err ;
}
mnt = file - > f_path . mnt ;
file - > f_path . mnt = internal ;
2005-11-08 01:13:39 +03:00
2015-01-10 20:47:38 +03:00
atomic_long_set ( & acct - > count , 1 ) ;
2015-01-11 01:53:21 +03:00
init_fs_pin ( & acct - > pin , acct_pin_kill ) ;
2014-08-07 15:51:03 +04:00
acct - > file = file ;
acct - > needcheck = jiffies ;
acct - > ns = ns ;
mutex_init ( & acct - > lock ) ;
2015-01-11 01:53:21 +03:00
INIT_WORK ( & acct - > work , close_work ) ;
init_completion ( & acct - > done ) ;
2014-08-07 16:39:04 +04:00
mutex_lock_nested ( & acct - > lock , 1 ) ; /* nobody has seen it yet */
pin_insert ( & acct - > pin , mnt ) ;
2008-07-25 12:48:47 +04:00
2015-01-11 01:53:21 +03:00
rcu_read_lock ( ) ;
old = xchg ( & ns - > bacct , & acct - > pin ) ;
2014-08-07 16:39:04 +04:00
mutex_unlock ( & acct - > lock ) ;
2015-01-11 01:53:21 +03:00
pin_kill ( old ) ;
2014-08-07 17:12:31 +04:00
mnt_drop_write ( mnt ) ;
mntput ( mnt ) ;
2005-11-08 01:13:39 +03:00
return 0 ;
}
2014-05-15 14:49:45 +04:00
static DEFINE_MUTEX ( acct_on_mutex ) ;
2005-09-10 11:26:39 +04:00
/**
* sys_acct - enable / disable process accounting
* @ name : file name for accounting records or NULL to shutdown accounting
*
* Returns 0 for success or negative errno values for failure .
*
* sys_acct ( ) is the only system call needed to implement process
* accounting . It takes the name of the file where accounting records
* should be written . If the filename is NULL , accounting will be
* shutdown .
2005-04-17 02:20:36 +04:00
*/
2009-01-14 16:14:06 +03:00
SYSCALL_DEFINE1 ( acct , const char __user * , name )
2005-04-17 02:20:36 +04:00
{
2010-04-07 23:15:25 +04:00
int error = 0 ;
2005-04-17 02:20:36 +04:00
if ( ! capable ( CAP_SYS_PACCT ) )
return - EPERM ;
if ( name ) {
2012-10-10 23:25:28 +04:00
struct filename * tmp = getname ( name ) ;
2014-07-31 03:28:36 +04:00
2005-11-08 01:13:39 +03:00
if ( IS_ERR ( tmp ) )
2014-06-07 01:37:37 +04:00
return PTR_ERR ( tmp ) ;
2014-05-15 14:49:45 +04:00
mutex_lock ( & acct_on_mutex ) ;
2012-10-11 00:43:10 +04:00
error = acct_on ( tmp ) ;
2014-05-15 14:49:45 +04:00
mutex_unlock ( & acct_on_mutex ) ;
2005-04-17 02:20:36 +04:00
putname ( tmp ) ;
2005-11-08 01:13:39 +03:00
} else {
2015-01-11 01:53:21 +03:00
rcu_read_lock ( ) ;
pin_kill ( task_active_pid_ns ( current ) - > bacct ) ;
2005-04-17 02:20:36 +04:00
}
2010-04-07 23:15:25 +04:00
2005-11-08 01:13:39 +03:00
return error ;
}
2005-04-17 02:20:36 +04:00
2008-07-25 12:48:47 +04:00
void acct_exit_ns ( struct pid_namespace * ns )
{
2015-01-11 01:53:21 +03:00
rcu_read_lock ( ) ;
pin_kill ( ns - > bacct ) ;
2005-04-17 02:20:36 +04:00
}
/*
* encode an unsigned long into a comp_t
*
* This routine has been adopted from the encode_comp_t ( ) function in
* the kern_acct . c file of the FreeBSD operating system . The encoding
* is a 13 - bit fraction with a 3 - bit ( base 8 ) exponent .
*/
# define MANTSIZE 13 /* 13 bit mantissa. */
# define EXPSIZE 3 /* Base 8 (3 bit) exponent. */
# define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */
static comp_t encode_comp_t ( unsigned long value )
{
int exp , rnd ;
exp = rnd = 0 ;
while ( value > MAXFRACT ) {
rnd = value & ( 1 < < ( EXPSIZE - 1 ) ) ; /* Round up? */
value > > = EXPSIZE ; /* Base 8 exponent == 3 bit shift. */
exp + + ;
}
/*
2007-10-18 14:06:04 +04:00
* If we need to round up , do it ( and handle overflow correctly ) .
*/
2005-04-17 02:20:36 +04:00
if ( rnd & & ( + + value > MAXFRACT ) ) {
value > > = EXPSIZE ;
exp + + ;
}
/*
2007-10-18 14:06:04 +04:00
* Clean it up and polish it off .
*/
2005-04-17 02:20:36 +04:00
exp < < = MANTSIZE ; /* Shift the exponent into place */
exp + = value ; /* and add on the mantissa. */
return exp ;
}
2014-07-31 03:28:36 +04:00
# if ACCT_VERSION == 1 || ACCT_VERSION == 2
2005-04-17 02:20:36 +04:00
/*
* encode an u64 into a comp2_t ( 24 bits )
*
* Format : 5 bit base 2 exponent , 20 bits mantissa .
* The leading bit of the mantissa is not stored , but implied for
* non - zero exponents .
* Largest encodable value is 50 bits .
*/
# define MANTSIZE2 20 /* 20 bit mantissa. */
# define EXPSIZE2 5 /* 5 bit base 2 exponent. */
# define MAXFRACT2 ((1ul << MANTSIZE2) - 1) /* Maximum fractional value. */
2014-07-31 03:28:36 +04:00
# define MAXEXP2 ((1 << EXPSIZE2) - 1) /* Maximum exponent. */
2005-04-17 02:20:36 +04:00
static comp2_t encode_comp2_t ( u64 value )
{
2007-10-18 14:06:04 +04:00
int exp , rnd ;
exp = ( value > ( MAXFRACT2 > > 1 ) ) ;
rnd = 0 ;
while ( value > MAXFRACT2 ) {
rnd = value & 1 ;
value > > = 1 ;
exp + + ;
}
/*
* If we need to round up , do it ( and handle overflow correctly ) .
*/
if ( rnd & & ( + + value > MAXFRACT2 ) ) {
value > > = 1 ;
exp + + ;
}
if ( exp > MAXEXP2 ) {
/* Overflow. Return largest representable number instead. */
return ( 1ul < < ( MANTSIZE2 + EXPSIZE2 - 1 ) ) - 1 ;
} else {
return ( value & ( MAXFRACT2 > > 1 ) ) | ( exp < < ( MANTSIZE2 - 1 ) ) ;
}
2005-04-17 02:20:36 +04:00
}
# endif
2014-07-31 03:28:36 +04:00
# if ACCT_VERSION == 3
2005-04-17 02:20:36 +04:00
/*
* encode an u64 into a 32 bit IEEE float
*/
static u32 encode_float ( u64 value )
{
unsigned exp = 190 ;
unsigned u ;
2014-07-31 03:28:36 +04:00
if ( value = = 0 )
return 0 ;
while ( ( s64 ) value > 0 ) {
2005-04-17 02:20:36 +04:00
value < < = 1 ;
exp - - ;
}
u = ( u32 ) ( value > > 40 ) & 0x7fffffu ;
return u | ( exp < < 23 ) ;
}
# endif
/*
* Write an accounting entry for an exiting process
*
* The acct_process ( ) call is the workhorse of the process
* accounting system . The struct acct is built here and then written
* into the accounting file . This function should only be called from
2007-11-26 23:21:49 +03:00
* do_exit ( ) or when switching to a different output file .
2005-04-17 02:20:36 +04:00
*/
2014-04-27 07:45:53 +04:00
static void fill_ac ( acct_t * ac )
2005-04-17 02:20:36 +04:00
{
2006-06-25 16:49:24 +04:00
struct pacct_struct * pacct = & current - > signal - > pacct ;
2014-07-17 01:04:34 +04:00
u64 elapsed , run_time ;
2006-12-08 13:36:04 +03:00
struct tty_struct * tty ;
2005-04-17 02:20:36 +04:00
/*
* Fill the accounting struct with the needed info as recorded
* by the different kernel functions .
*/
2014-04-27 07:45:53 +04:00
memset ( ac , 0 , sizeof ( acct_t ) ) ;
2005-04-17 02:20:36 +04:00
2014-04-27 07:45:53 +04:00
ac - > ac_version = ACCT_VERSION | ACCT_BYTEORDER ;
strlcpy ( ac - > ac_comm , current - > comm , sizeof ( ac - > ac_comm ) ) ;
2005-04-17 02:20:36 +04:00
/* calculate run_time in nsec*/
2014-07-17 01:04:34 +04:00
run_time = ktime_get_ns ( ) ;
run_time - = current - > group_leader - > start_time ;
2005-04-17 02:20:36 +04:00
/* convert nsec -> AHZ */
elapsed = nsec_to_AHZ ( run_time ) ;
2014-07-31 03:28:36 +04:00
# if ACCT_VERSION == 3
2014-04-27 07:45:53 +04:00
ac - > ac_etime = encode_float ( elapsed ) ;
2005-04-17 02:20:36 +04:00
# else
2014-04-27 07:45:53 +04:00
ac - > ac_etime = encode_comp_t ( elapsed < ( unsigned long ) - 1l ?
2014-07-31 03:28:36 +04:00
( unsigned long ) elapsed : ( unsigned long ) - 1l ) ;
2005-04-17 02:20:36 +04:00
# endif
2014-07-31 03:28:36 +04:00
# if ACCT_VERSION == 1 || ACCT_VERSION == 2
2005-04-17 02:20:36 +04:00
{
/* new enlarged etime field */
comp2_t etime = encode_comp2_t ( elapsed ) ;
2014-07-31 03:28:36 +04:00
2014-04-27 07:45:53 +04:00
ac - > ac_etime_hi = etime > > 16 ;
ac - > ac_etime_lo = ( u16 ) etime ;
2005-04-17 02:20:36 +04:00
}
# endif
do_div ( elapsed , AHZ ) ;
2014-04-27 07:45:53 +04:00
ac - > ac_btime = get_seconds ( ) - elapsed ;
# if ACCT_VERSION==2
ac - > ac_ahz = AHZ ;
# endif
spin_lock_irq ( & current - > sighand - > siglock ) ;
tty = current - > signal - > tty ; /* Safe as we hold the siglock */
ac - > ac_tty = tty ? old_encode_dev ( tty_devnum ( tty ) ) : 0 ;
ac - > ac_utime = encode_comp_t ( jiffies_to_AHZ ( cputime_to_jiffies ( pacct - > ac_utime ) ) ) ;
ac - > ac_stime = encode_comp_t ( jiffies_to_AHZ ( cputime_to_jiffies ( pacct - > ac_stime ) ) ) ;
ac - > ac_flag = pacct - > ac_flag ;
ac - > ac_mem = encode_comp_t ( pacct - > ac_mem ) ;
ac - > ac_minflt = encode_comp_t ( pacct - > ac_minflt ) ;
ac - > ac_majflt = encode_comp_t ( pacct - > ac_majflt ) ;
ac - > ac_exitcode = pacct - > ac_exitcode ;
spin_unlock_irq ( & current - > sighand - > siglock ) ;
}
/*
* do_acct_process does all actual work . Caller holds the reference to file .
*/
2014-08-07 15:51:03 +04:00
static void do_acct_process ( struct bsd_acct_struct * acct )
2014-04-27 07:45:53 +04:00
{
acct_t ac ;
unsigned long flim ;
const struct cred * orig_cred ;
2014-08-07 15:51:03 +04:00
struct file * file = acct - > file ;
2014-04-27 07:45:53 +04:00
/*
* Accounting records are not subject to resource limits .
*/
flim = current - > signal - > rlim [ RLIMIT_FSIZE ] . rlim_cur ;
current - > signal - > rlim [ RLIMIT_FSIZE ] . rlim_cur = RLIM_INFINITY ;
/* Perform file operations on behalf of whoever enabled accounting */
orig_cred = override_creds ( file - > f_cred ) ;
/*
* First check to see if there is enough free_space to continue
* the process accounting system .
*/
2014-04-19 22:24:18 +04:00
if ( ! check_free_space ( acct ) )
2014-04-27 07:45:53 +04:00
goto out ;
fill_ac ( & ac ) ;
2005-04-17 02:20:36 +04:00
/* we really need to bite the bullet and change layout */
2012-02-08 04:54:50 +04:00
ac . ac_uid = from_kuid_munged ( file - > f_cred - > user_ns , orig_cred - > uid ) ;
ac . ac_gid = from_kgid_munged ( file - > f_cred - > user_ns , orig_cred - > gid ) ;
2014-07-31 03:28:36 +04:00
# if ACCT_VERSION == 1 || ACCT_VERSION == 2
2005-04-17 02:20:36 +04:00
/* backward-compatible 16 bit fields */
2008-11-14 02:39:12 +03:00
ac . ac_uid16 = ac . ac_uid ;
ac . ac_gid16 = ac . ac_gid ;
2005-04-17 02:20:36 +04:00
# endif
2014-07-31 03:28:36 +04:00
# if ACCT_VERSION == 3
2014-10-10 02:30:21 +04:00
{
struct pid_namespace * ns = acct - > ns ;
ac . ac_pid = task_tgid_nr_ns ( current , ns ) ;
rcu_read_lock ( ) ;
ac . ac_ppid = task_tgid_nr_ns ( rcu_dereference ( current - > real_parent ) ,
ns ) ;
rcu_read_unlock ( ) ;
}
2005-04-17 02:20:36 +04:00
# endif
2013-05-04 02:11:23 +04:00
/*
* Get freeze protection . If the fs is frozen , just skip the write
* as we could deadlock the system otherwise .
*/
2014-04-19 22:37:20 +04:00
if ( file_start_write_trylock ( file ) ) {
/* it's been opened O_APPEND, so position is irrelevant */
loff_t pos = 0 ;
__kernel_write ( file , ( char * ) & ac , sizeof ( acct_t ) , & pos ) ;
file_end_write ( file ) ;
}
2009-08-21 01:39:52 +04:00
out :
2014-04-19 22:37:20 +04:00
current - > signal - > rlim [ RLIMIT_FSIZE ] . rlim_cur = flim ;
2009-08-21 01:39:52 +04:00
revert_creds ( orig_cred ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-25 16:49:24 +04:00
/**
* acct_collect - collect accounting information into pacct_struct
2006-06-25 16:49:25 +04:00
* @ exitcode : task exit code
* @ group_dead : not 0 , if this thread is the last one in the process .
2006-06-25 16:49:24 +04:00
*/
2006-06-25 16:49:25 +04:00
void acct_collect ( long exitcode , int group_dead )
2006-06-25 16:49:24 +04:00
{
struct pacct_struct * pacct = & current - > signal - > pacct ;
2012-11-13 17:20:55 +04:00
cputime_t utime , stime ;
2006-06-25 16:49:24 +04:00
unsigned long vsize = 0 ;
2006-06-25 16:49:25 +04:00
if ( group_dead & & current - > mm ) {
2006-06-25 16:49:24 +04:00
struct vm_area_struct * vma ;
2014-07-31 03:28:36 +04:00
2006-06-25 16:49:24 +04:00
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 ) ;
}
2006-06-25 16:49:26 +04:00
spin_lock_irq ( & current - > sighand - > siglock ) ;
2006-06-25 16:49:25 +04:00
if ( group_dead )
pacct - > ac_mem = vsize / 1024 ;
if ( thread_group_leader ( current ) ) {
pacct - > ac_exitcode = exitcode ;
if ( current - > flags & PF_FORKNOEXEC )
pacct - > ac_flag | = AFORK ;
}
if ( current - > flags & PF_SUPERPRIV )
pacct - > ac_flag | = ASU ;
if ( current - > flags & PF_DUMPCORE )
pacct - > ac_flag | = ACORE ;
if ( current - > flags & PF_SIGNALED )
pacct - > ac_flag | = AXSIG ;
2012-11-13 17:20:55 +04:00
task_cputime ( current , & utime , & stime ) ;
pacct - > ac_utime + = utime ;
pacct - > ac_stime + = stime ;
2006-06-25 16:49:26 +04:00
pacct - > ac_minflt + = current - > min_flt ;
pacct - > ac_majflt + = current - > maj_flt ;
spin_unlock_irq ( & current - > sighand - > siglock ) ;
2006-06-25 16:49:24 +04:00
}
2014-05-07 13:12:09 +04:00
static void slow_acct_process ( struct pid_namespace * ns )
2005-04-17 02:20:36 +04:00
{
2014-05-07 13:12:09 +04:00
for ( ; ns ; ns = ns - > parent ) {
2014-08-07 14:23:41 +04:00
struct bsd_acct_struct * acct = acct_get ( ns ) ;
2014-08-07 15:51:03 +04:00
if ( acct ) {
do_acct_process ( acct ) ;
mutex_unlock ( & acct - > lock ) ;
2015-01-10 04:40:02 +03:00
acct_put ( acct ) ;
2014-05-07 13:12:09 +04:00
}
}
2005-04-17 02:20:36 +04:00
}
2008-07-25 12:48:48 +04:00
/**
2014-05-07 13:12:09 +04:00
* acct_process
2008-07-25 12:48:48 +04:00
*
* handles process accounting for an exiting task
*/
void acct_process ( void )
{
struct pid_namespace * ns ;
2008-07-25 12:48:49 +04:00
/*
* This loop is safe lockless , since current is still
* alive and holds its namespace , which in turn holds
* its parent .
*/
2014-05-07 13:12:09 +04:00
for ( ns = task_active_pid_ns ( current ) ; ns ! = NULL ; ns = ns - > parent ) {
2014-08-07 15:51:03 +04:00
if ( ns - > bacct )
2014-05-07 13:12:09 +04:00
break ;
}
if ( unlikely ( ns ) )
slow_acct_process ( ns ) ;
2008-07-25 12:48:48 +04:00
}