acct.c 15.6 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/*
 *  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>
49
#include <linux/capability.h>
Linus Torvalds's avatar
Linus Torvalds committed
50 51 52 53 54 55 56
#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>
57
#include <linux/mount.h>
58
#include <linux/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
59 60
#include <asm/div64.h>
#include <linux/blkdev.h> /* sector_div */
61
#include <linux/pid_namespace.h>
Al Viro's avatar
Al Viro committed
62
#include <../fs/mount.h>	/* will go away when we refactor */
Linus Torvalds's avatar
Linus Torvalds committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78

/*
 * 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.
 */
Al Viro's avatar
Al Viro committed
79
static void do_acct_process(struct bsd_acct_struct *acct);
Linus Torvalds's avatar
Linus Torvalds committed
80

81
struct bsd_acct_struct {
Al Viro's avatar
Al Viro committed
82
	long			count;
Al Viro's avatar
Al Viro committed
83 84
	struct hlist_node	s_list;
	struct hlist_node	m_list;
Al Viro's avatar
Al Viro committed
85
	struct mutex		lock;
Al Viro's avatar
Al Viro committed
86 87
	int			active;
	unsigned long		needcheck;
Linus Torvalds's avatar
Linus Torvalds committed
88
	struct file		*file;
89
	struct pid_namespace	*ns;
Linus Torvalds's avatar
Linus Torvalds committed
90 91
};

92 93
static DEFINE_SPINLOCK(acct_lock);

Linus Torvalds's avatar
Linus Torvalds committed
94 95 96
/*
 * Check the amount of free space and suspend/resume accordingly.
 */
Al Viro's avatar
Al Viro committed
97
static int check_free_space(struct bsd_acct_struct *acct)
Linus Torvalds's avatar
Linus Torvalds committed
98 99 100
{
	struct kstatfs sbuf;

Al Viro's avatar
Al Viro committed
101
	if (time_is_before_jiffies(acct->needcheck))
Linus Torvalds's avatar
Linus Torvalds committed
102 103 104
		goto out;

	/* May block */
Al Viro's avatar
Al Viro committed
105
	if (vfs_statfs(&acct->file->f_path, &sbuf))
Linus Torvalds's avatar
Linus Torvalds committed
106 107
		goto out;

108
	if (acct->active) {
Al Viro's avatar
Al Viro committed
109 110 111
		u64 suspend = sbuf.f_blocks * SUSPEND;
		do_div(suspend, 100);
		if (sbuf.f_bavail <= suspend) {
112
			acct->active = 0;
Linus Torvalds's avatar
Linus Torvalds committed
113 114 115
			printk(KERN_INFO "Process accounting paused\n");
		}
	} else {
Al Viro's avatar
Al Viro committed
116 117 118
		u64 resume = sbuf.f_blocks * RESUME;
		do_div(resume, 100);
		if (sbuf.f_bavail >= resume) {
119
			acct->active = 1;
Linus Torvalds's avatar
Linus Torvalds committed
120 121 122 123
			printk(KERN_INFO "Process accounting resumed\n");
		}
	}

Al Viro's avatar
Al Viro committed
124
	acct->needcheck = jiffies + ACCT_TIMEOUT*HZ;
Linus Torvalds's avatar
Linus Torvalds committed
125
out:
Al Viro's avatar
Al Viro committed
126
	return acct->active;
Linus Torvalds's avatar
Linus Torvalds committed
127 128
}

Al Viro's avatar
Al Viro committed
129
static void acct_put(struct bsd_acct_struct *p)
Linus Torvalds's avatar
Linus Torvalds committed
130
{
Al Viro's avatar
Al Viro committed
131 132 133 134 135 136
	spin_lock(&acct_lock);
	if (!--p->count)
		kfree(p);
	spin_unlock(&acct_lock);
}

Al Viro's avatar
Al Viro committed
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
static struct bsd_acct_struct *__acct_get(struct bsd_acct_struct *res)
{
	res->count++;
	spin_unlock(&acct_lock);
	mutex_lock(&res->lock);
	if (!res->ns) {
		mutex_unlock(&res->lock);
		spin_lock(&acct_lock);
		if (!--res->count)
			kfree(res);
		return NULL;
	}
	return res;
}

static struct bsd_acct_struct *acct_get(struct pid_namespace *ns)
Al Viro's avatar
Al Viro committed
153 154 155 156
{
	struct bsd_acct_struct *res;
	spin_lock(&acct_lock);
again:
Al Viro's avatar
Al Viro committed
157 158 159
	if (!ns->bacct) {
		spin_unlock(&acct_lock);
		return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
160
	}
Al Viro's avatar
Al Viro committed
161 162 163
	res = __acct_get(ns->bacct);
	if (!res)
		goto again;
Al Viro's avatar
Al Viro committed
164 165 166 167 168 169 170 171 172 173
	return res;
}

static void acct_kill(struct bsd_acct_struct *acct,
		      struct bsd_acct_struct *new)
{
	if (acct) {
		struct file *file = acct->file;
		struct pid_namespace *ns = acct->ns;
		spin_lock(&acct_lock);
Al Viro's avatar
Al Viro committed
174 175
		hlist_del(&acct->m_list);
		hlist_del(&acct->s_list);
Al Viro's avatar
Al Viro committed
176
		mnt_unpin(file->f_path.mnt);
177
		spin_unlock(&acct_lock);
Al Viro's avatar
Al Viro committed
178 179
		do_acct_process(acct);
		filp_close(file, NULL);
180
		spin_lock(&acct_lock);
Al Viro's avatar
Al Viro committed
181 182
		ns->bacct = new;
		if (new) {
Al Viro's avatar
Al Viro committed
183 184 185 186
			struct vfsmount *m = new->file->f_path.mnt;
			mnt_pin(m);
			hlist_add_head(&new->s_list, &m->mnt_sb->s_pins);
			hlist_add_head(&new->m_list, &real_mount(m)->mnt_pins);
Al Viro's avatar
Al Viro committed
187 188 189 190 191 192
		}
		acct->ns = NULL;
		mutex_unlock(&acct->lock);
		if (!(acct->count -= 2))
			kfree(acct);
		spin_unlock(&acct_lock);
Linus Torvalds's avatar
Linus Torvalds committed
193 194 195
	}
}

196
static int acct_on(struct filename *pathname)
197 198
{
	struct file *file;
199
	struct vfsmount *mnt;
Al Viro's avatar
Al Viro committed
200 201 202 203 204 205
	struct pid_namespace *ns = task_active_pid_ns(current);
	struct bsd_acct_struct *acct, *old;

	acct = kzalloc(sizeof(struct bsd_acct_struct), GFP_KERNEL);
	if (!acct)
		return -ENOMEM;
206 207

	/* Difference from BSD - they don't do O_APPEND */
208
	file = file_open_name(pathname, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
Al Viro's avatar
Al Viro committed
209 210
	if (IS_ERR(file)) {
		kfree(acct);
211
		return PTR_ERR(file);
Al Viro's avatar
Al Viro committed
212
	}
213

Al Viro's avatar
Al Viro committed
214
	if (!S_ISREG(file_inode(file)->i_mode)) {
Al Viro's avatar
Al Viro committed
215
		kfree(acct);
216 217 218 219 220
		filp_close(file, NULL);
		return -EACCES;
	}

	if (!file->f_op->write) {
Al Viro's avatar
Al Viro committed
221
		kfree(acct);
222 223 224 225
		filp_close(file, NULL);
		return -EIO;
	}

Al Viro's avatar
Al Viro committed
226 227 228 229 230 231
	acct->count = 1;
	acct->file = file;
	acct->needcheck = jiffies;
	acct->ns = ns;
	mutex_init(&acct->lock);
	mnt = file->f_path.mnt;
232

Al Viro's avatar
Al Viro committed
233
	old = acct_get(ns);
Al Viro's avatar
Al Viro committed
234 235 236 237
	if (old) {
		acct_kill(old, acct);
	} else {
		spin_lock(&acct_lock);
238
		ns->bacct = acct;
Al Viro's avatar
Al Viro committed
239
		mnt_pin(mnt);
Al Viro's avatar
Al Viro committed
240 241
		hlist_add_head(&acct->s_list, &mnt->mnt_sb->s_pins);
		hlist_add_head(&acct->m_list, &real_mount(mnt)->mnt_pins);
Al Viro's avatar
Al Viro committed
242
		spin_unlock(&acct_lock);
243
	}
244
	mntput(mnt); /* it's pinned, now give up active reference */
245 246 247
	return 0;
}

Al Viro's avatar
Al Viro committed
248 249
static DEFINE_MUTEX(acct_on_mutex);

250 251 252 253 254 255 256 257 258 259
/**
 * 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.
Linus Torvalds's avatar
Linus Torvalds committed
260
 */
261
SYSCALL_DEFINE1(acct, const char __user *, name)
Linus Torvalds's avatar
Linus Torvalds committed
262
{
Eric Paris's avatar
Eric Paris committed
263
	int error = 0;
Linus Torvalds's avatar
Linus Torvalds committed
264 265 266 267 268

	if (!capable(CAP_SYS_PACCT))
		return -EPERM;

	if (name) {
269
		struct filename *tmp = getname(name);
270
		if (IS_ERR(tmp))
Paul McQuade's avatar
Paul McQuade committed
271
			return PTR_ERR(tmp);
Al Viro's avatar
Al Viro committed
272
		mutex_lock(&acct_on_mutex);
273
		error = acct_on(tmp);
Al Viro's avatar
Al Viro committed
274
		mutex_unlock(&acct_on_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
275
		putname(tmp);
276
	} else {
Al Viro's avatar
Al Viro committed
277
		acct_kill(acct_get(task_active_pid_ns(current)), NULL);
Linus Torvalds's avatar
Linus Torvalds committed
278
	}
Eric Paris's avatar
Eric Paris committed
279

280 281
	return error;
}
Linus Torvalds's avatar
Linus Torvalds committed
282

Al Viro's avatar
Al Viro committed
283
void acct_auto_close_mnt(struct hlist_head *list)
284
{
Al Viro's avatar
Al Viro committed
285 286 287 288 289 290 291 292
	while (1) {
		spin_lock(&acct_lock);
		if (!list->first)
			break;
		acct_kill(__acct_get(hlist_entry(list->first,
						 struct bsd_acct_struct,
						 m_list)), NULL);
	}
293
	spin_unlock(&acct_lock);
Linus Torvalds's avatar
Linus Torvalds committed
294 295
}

Al Viro's avatar
Al Viro committed
296
void acct_auto_close(struct hlist_head *list)
Linus Torvalds's avatar
Linus Torvalds committed
297
{
Al Viro's avatar
Al Viro committed
298 299 300 301 302 303 304 305
	while (1) {
		spin_lock(&acct_lock);
		if (!list->first)
			break;
		acct_kill(__acct_get(hlist_entry(list->first,
						 struct bsd_acct_struct,
						 s_list)), NULL);
	}
306 307 308 309 310
	spin_unlock(&acct_lock);
}

void acct_exit_ns(struct pid_namespace *ns)
{
Al Viro's avatar
Al Viro committed
311
	acct_kill(acct_get(ns), NULL);
Linus Torvalds's avatar
Linus Torvalds committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
}

/*
 *  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++;
	}

	/*
338 339
	 * If we need to round up, do it (and handle overflow correctly).
	 */
Linus Torvalds's avatar
Linus Torvalds committed
340 341 342 343 344 345
	if (rnd && (++value > MAXFRACT)) {
		value >>= EXPSIZE;
		exp++;
	}

	/*
346 347
	 * Clean it up and polish it off.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
	exp <<= MANTSIZE;		/* Shift the exponent into place */
	exp += value;			/* and add on the mantissa. */
	return exp;
}

#if ACCT_VERSION==1 || ACCT_VERSION==2
/*
 * 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. */
#define MAXEXP2         ((1 <<EXPSIZE2) - 1)    /* Maximum exponent. */

static comp2_t encode_comp2_t(u64 value)
{
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
	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));
	}
Linus Torvalds's avatar
Linus Torvalds committed
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
}
#endif

#if ACCT_VERSION==3
/*
 * encode an u64 into a 32 bit IEEE float
 */
static u32 encode_float(u64 value)
{
	unsigned exp = 190;
	unsigned u;

	if (value==0) return 0;
	while ((s64)value > 0){
		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
422
 *  do_exit() or when switching to a different output file.
Linus Torvalds's avatar
Linus Torvalds committed
423 424
 */

425
static void fill_ac(acct_t *ac)
Linus Torvalds's avatar
Linus Torvalds committed
426
{
427
	struct pacct_struct *pacct = &current->signal->pacct;
428
	u64 elapsed, run_time;
429
	struct tty_struct *tty;
Linus Torvalds's avatar
Linus Torvalds committed
430 431 432 433 434

	/*
	 * Fill the accounting struct with the needed info as recorded
	 * by the different kernel functions.
	 */
435
	memset(ac, 0, sizeof(acct_t));
Linus Torvalds's avatar
Linus Torvalds committed
436

437 438
	ac->ac_version = ACCT_VERSION | ACCT_BYTEORDER;
	strlcpy(ac->ac_comm, current->comm, sizeof(ac->ac_comm));
Linus Torvalds's avatar
Linus Torvalds committed
439 440

	/* calculate run_time in nsec*/
441 442
	run_time = ktime_get_ns();
	run_time -= current->group_leader->start_time;
Linus Torvalds's avatar
Linus Torvalds committed
443 444 445
	/* convert nsec -> AHZ */
	elapsed = nsec_to_AHZ(run_time);
#if ACCT_VERSION==3
446
	ac->ac_etime = encode_float(elapsed);
Linus Torvalds's avatar
Linus Torvalds committed
447
#else
448
	ac->ac_etime = encode_comp_t(elapsed < (unsigned long) -1l ?
Linus Torvalds's avatar
Linus Torvalds committed
449 450 451 452 453 454
	                       (unsigned long) elapsed : (unsigned long) -1l);
#endif
#if ACCT_VERSION==1 || ACCT_VERSION==2
	{
		/* new enlarged etime field */
		comp2_t etime = encode_comp2_t(elapsed);
455 456
		ac->ac_etime_hi = etime >> 16;
		ac->ac_etime_lo = (u16) etime;
Linus Torvalds's avatar
Linus Torvalds committed
457 458 459
	}
#endif
	do_div(elapsed, AHZ);
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
	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.
 */
Al Viro's avatar
Al Viro committed
480
static void do_acct_process(struct bsd_acct_struct *acct)
481 482 483 484
{
	acct_t ac;
	unsigned long flim;
	const struct cred *orig_cred;
Al Viro's avatar
Al Viro committed
485 486
	struct pid_namespace *ns = acct->ns;
	struct file *file = acct->file;
487 488 489 490 491 492 493 494 495 496 497 498 499

	/*
	 * 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.
	 */
Al Viro's avatar
Al Viro committed
500
	if (!check_free_space(acct))
501 502 503
		goto out;

	fill_ac(&ac);
Linus Torvalds's avatar
Linus Torvalds committed
504
	/* we really need to bite the bullet and change layout */
505 506
	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);
Linus Torvalds's avatar
Linus Torvalds committed
507 508
#if ACCT_VERSION==1 || ACCT_VERSION==2
	/* backward-compatible 16 bit fields */
509 510
	ac.ac_uid16 = ac.ac_uid;
	ac.ac_gid16 = ac.ac_gid;
Linus Torvalds's avatar
Linus Torvalds committed
511 512
#endif
#if ACCT_VERSION==3
513
	ac.ac_pid = task_tgid_nr_ns(current, ns);
514
	rcu_read_lock();
515
	ac.ac_ppid = task_tgid_nr_ns(rcu_dereference(current->real_parent), ns);
516
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
517
#endif
518 519 520 521
	/*
	 * Get freeze protection. If the fs is frozen, just skip the write
	 * as we could deadlock the system otherwise.
	 */
Al Viro's avatar
Al Viro committed
522 523 524 525 526 527
	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);
	}
528
out:
Al Viro's avatar
Al Viro committed
529
	current->signal->rlim[RLIMIT_FSIZE].rlim_cur = flim;
530
	revert_creds(orig_cred);
Linus Torvalds's avatar
Linus Torvalds committed
531 532
}

533 534
/**
 * acct_collect - collect accounting information into pacct_struct
535 536
 * @exitcode: task exit code
 * @group_dead: not 0, if this thread is the last one in the process.
537
 */
538
void acct_collect(long exitcode, int group_dead)
539 540
{
	struct pacct_struct *pacct = &current->signal->pacct;
541
	cputime_t utime, stime;
542 543
	unsigned long vsize = 0;

544
	if (group_dead && current->mm) {
545 546 547 548 549 550 551 552 553 554
		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);
	}

555
	spin_lock_irq(&current->sighand->siglock);
556 557 558 559 560 561 562 563 564 565 566 567 568
	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;
569 570 571
	task_cputime(current, &utime, &stime);
	pacct->ac_utime += utime;
	pacct->ac_stime += stime;
572 573 574
	pacct->ac_minflt += current->min_flt;
	pacct->ac_majflt += current->maj_flt;
	spin_unlock_irq(&current->sighand->siglock);
575 576
}

577
static void slow_acct_process(struct pid_namespace *ns)
Linus Torvalds's avatar
Linus Torvalds committed
578
{
579
	for ( ; ns; ns = ns->parent) {
Al Viro's avatar
Al Viro committed
580
		struct bsd_acct_struct *acct = acct_get(ns);
Al Viro's avatar
Al Viro committed
581 582 583 584
		if (acct) {
			do_acct_process(acct);
			mutex_unlock(&acct->lock);
			acct_put(acct);
585 586
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
587
}
588 589

/**
590
 * acct_process
591 592 593 594 595 596 597
 *
 * handles process accounting for an exiting task
 */
void acct_process(void)
{
	struct pid_namespace *ns;

598 599 600 601 602
	/*
	 * This loop is safe lockless, since current is still
	 * alive and holds its namespace, which in turn holds
	 * its parent.
	 */
603
	for (ns = task_active_pid_ns(current); ns != NULL; ns = ns->parent) {
Al Viro's avatar
Al Viro committed
604
		if (ns->bacct)
605 606 607 608
			break;
	}
	if (unlikely(ns))
		slow_acct_process(ns);
609
}