acct.c 15.4 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 <linux/fs_pin.h>
Linus Torvalds's avatar
Linus Torvalds committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

/*
 * 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
80 81
struct bsd_acct_struct {
	struct fs_pin		pin;
82 83
	atomic_long_t		count;
	struct rcu_head		rcu;
Al Viro's avatar
Al Viro committed
84
	struct mutex		lock;
Al Viro's avatar
Al Viro committed
85 86
	int			active;
	unsigned long		needcheck;
Linus Torvalds's avatar
Linus Torvalds committed
87
	struct file		*file;
88
	struct pid_namespace	*ns;
89 90
	struct work_struct	work;
	struct completion	done;
Linus Torvalds's avatar
Linus Torvalds committed
91 92
};

Al Viro's avatar
Al Viro committed
93 94
static void do_acct_process(struct bsd_acct_struct *acct);

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

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

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

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

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

Al Viro's avatar
Al Viro committed
130 131
static void acct_put(struct bsd_acct_struct *p)
{
132 133
	if (atomic_long_dec_and_test(&p->count))
		kfree_rcu(p, rcu);
Al Viro's avatar
Al Viro committed
134 135
}

Al Viro's avatar
Al Viro committed
136 137 138 139 140
static inline struct bsd_acct_struct *to_acct(struct fs_pin *p)
{
	return p ? container_of(p, struct bsd_acct_struct, pin) : NULL;
}

Al Viro's avatar
Al Viro committed
141
static struct bsd_acct_struct *acct_get(struct pid_namespace *ns)
Al Viro's avatar
Al Viro committed
142 143 144
{
	struct bsd_acct_struct *res;
again:
145 146
	smp_rmb();
	rcu_read_lock();
Al Viro's avatar
Al Viro committed
147
	res = to_acct(ACCESS_ONCE(ns->bacct));
148 149
	if (!res) {
		rcu_read_unlock();
Al Viro's avatar
Al Viro committed
150
		return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
151
	}
152
	if (!atomic_long_inc_not_zero(&res->count)) {
Al Viro's avatar
Al Viro committed
153 154
		rcu_read_unlock();
		cpu_relax();
Al Viro's avatar
Al Viro committed
155
		goto again;
Al Viro's avatar
Al Viro committed
156 157 158
	}
	rcu_read_unlock();
	mutex_lock(&res->lock);
Al Viro's avatar
Al Viro committed
159
	if (res != to_acct(ACCESS_ONCE(ns->bacct))) {
Al Viro's avatar
Al Viro committed
160
		mutex_unlock(&res->lock);
Al Viro's avatar
Al Viro committed
161
		acct_put(res);
Al Viro's avatar
Al Viro committed
162 163
		goto again;
	}
Al Viro's avatar
Al Viro committed
164 165 166
	return res;
}

Al Viro's avatar
Al Viro committed
167 168 169 170 171 172 173 174 175 176 177 178 179
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);
}

180 181 182 183 184 185 186 187 188 189
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);
}

190
static int acct_on(struct filename *pathname)
191 192
{
	struct file *file;
Al Viro's avatar
Al Viro committed
193
	struct vfsmount *mnt, *internal;
Al Viro's avatar
Al Viro committed
194
	struct pid_namespace *ns = task_active_pid_ns(current);
Al Viro's avatar
Al Viro committed
195 196
	struct bsd_acct_struct *acct;
	struct fs_pin *old;
Al Viro's avatar
Al Viro committed
197
	int err;
Al Viro's avatar
Al Viro committed
198 199 200 201

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

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

Al Viro's avatar
Al Viro committed
210
	if (!S_ISREG(file_inode(file)->i_mode)) {
Al Viro's avatar
Al Viro committed
211
		kfree(acct);
212 213 214 215 216
		filp_close(file, NULL);
		return -EACCES;
	}

	if (!file->f_op->write) {
Al Viro's avatar
Al Viro committed
217
		kfree(acct);
218 219 220
		filp_close(file, NULL);
		return -EIO;
	}
Al Viro's avatar
Al Viro committed
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
	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;
236

237
	atomic_long_set(&acct->count, 1);
Al Viro's avatar
Al Viro committed
238
	init_fs_pin(&acct->pin, acct_pin_kill);
Al Viro's avatar
Al Viro committed
239 240 241 242
	acct->file = file;
	acct->needcheck = jiffies;
	acct->ns = ns;
	mutex_init(&acct->lock);
Al Viro's avatar
Al Viro committed
243 244
	INIT_WORK(&acct->work, close_work);
	init_completion(&acct->done);
Al Viro's avatar
Al Viro committed
245 246
	mutex_lock_nested(&acct->lock, 1);	/* nobody has seen it yet */
	pin_insert(&acct->pin, mnt);
247

Al Viro's avatar
Al Viro committed
248 249
	rcu_read_lock();
	old = xchg(&ns->bacct, &acct->pin);
Al Viro's avatar
Al Viro committed
250
	mutex_unlock(&acct->lock);
Al Viro's avatar
Al Viro committed
251
	pin_kill(old);
Al Viro's avatar
Al Viro committed
252 253
	mnt_drop_write(mnt);
	mntput(mnt);
254 255 256
	return 0;
}

Al Viro's avatar
Al Viro committed
257 258
static DEFINE_MUTEX(acct_on_mutex);

259 260 261 262 263 264 265 266 267 268
/**
 * 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
269
 */
270
SYSCALL_DEFINE1(acct, const char __user *, name)
Linus Torvalds's avatar
Linus Torvalds committed
271
{
Eric Paris's avatar
Eric Paris committed
272
	int error = 0;
Linus Torvalds's avatar
Linus Torvalds committed
273 274 275 276 277

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

	if (name) {
278
		struct filename *tmp = getname(name);
279

280
		if (IS_ERR(tmp))
Paul McQuade's avatar
Paul McQuade committed
281
			return PTR_ERR(tmp);
Al Viro's avatar
Al Viro committed
282
		mutex_lock(&acct_on_mutex);
283
		error = acct_on(tmp);
Al Viro's avatar
Al Viro committed
284
		mutex_unlock(&acct_on_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
285
		putname(tmp);
286
	} else {
Al Viro's avatar
Al Viro committed
287 288
		rcu_read_lock();
		pin_kill(task_active_pid_ns(current)->bacct);
Linus Torvalds's avatar
Linus Torvalds committed
289
	}
Eric Paris's avatar
Eric Paris committed
290

291 292
	return error;
}
Linus Torvalds's avatar
Linus Torvalds committed
293

294 295
void acct_exit_ns(struct pid_namespace *ns)
{
Al Viro's avatar
Al Viro committed
296 297
	rcu_read_lock();
	pin_kill(ns->bacct);
Linus Torvalds's avatar
Linus Torvalds committed
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
}

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

	/*
324 325
	 * If we need to round up, do it (and handle overflow correctly).
	 */
Linus Torvalds's avatar
Linus Torvalds committed
326 327 328 329 330 331
	if (rnd && (++value > MAXFRACT)) {
		value >>= EXPSIZE;
		exp++;
	}

	/*
332 333
	 * Clean it up and polish it off.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
334 335 336 337 338
	exp <<= MANTSIZE;		/* Shift the exponent into place */
	exp += value;			/* and add on the mantissa. */
	return exp;
}

339
#if ACCT_VERSION == 1 || ACCT_VERSION == 2
Linus Torvalds's avatar
Linus Torvalds committed
340 341 342 343 344 345 346 347 348 349 350 351
/*
 * 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. */
352
#define MAXEXP2         ((1 << EXPSIZE2) - 1)    /* Maximum exponent. */
Linus Torvalds's avatar
Linus Torvalds committed
353 354 355

static comp2_t encode_comp2_t(u64 value)
{
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
	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
380 381 382
}
#endif

383
#if ACCT_VERSION == 3
Linus Torvalds's avatar
Linus Torvalds committed
384 385 386 387 388 389 390 391
/*
 * encode an u64 into a 32 bit IEEE float
 */
static u32 encode_float(u64 value)
{
	unsigned exp = 190;
	unsigned u;

392 393 394
	if (value == 0)
		return 0;
	while ((s64)value > 0) {
Linus Torvalds's avatar
Linus Torvalds committed
395 396 397 398 399 400 401 402 403 404 405 406 407 408
		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
409
 *  do_exit() or when switching to a different output file.
Linus Torvalds's avatar
Linus Torvalds committed
410 411
 */

412
static void fill_ac(acct_t *ac)
Linus Torvalds's avatar
Linus Torvalds committed
413
{
414
	struct pacct_struct *pacct = &current->signal->pacct;
415
	u64 elapsed, run_time;
416
	struct tty_struct *tty;
Linus Torvalds's avatar
Linus Torvalds committed
417 418 419 420 421

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

424 425
	ac->ac_version = ACCT_VERSION | ACCT_BYTEORDER;
	strlcpy(ac->ac_comm, current->comm, sizeof(ac->ac_comm));
Linus Torvalds's avatar
Linus Torvalds committed
426 427

	/* calculate run_time in nsec*/
428 429
	run_time = ktime_get_ns();
	run_time -= current->group_leader->start_time;
Linus Torvalds's avatar
Linus Torvalds committed
430 431
	/* convert nsec -> AHZ */
	elapsed = nsec_to_AHZ(run_time);
432
#if ACCT_VERSION == 3
433
	ac->ac_etime = encode_float(elapsed);
Linus Torvalds's avatar
Linus Torvalds committed
434
#else
435
	ac->ac_etime = encode_comp_t(elapsed < (unsigned long) -1l ?
436
				(unsigned long) elapsed : (unsigned long) -1l);
Linus Torvalds's avatar
Linus Torvalds committed
437
#endif
438
#if ACCT_VERSION == 1 || ACCT_VERSION == 2
Linus Torvalds's avatar
Linus Torvalds committed
439 440 441
	{
		/* new enlarged etime field */
		comp2_t etime = encode_comp2_t(elapsed);
442

443 444
		ac->ac_etime_hi = etime >> 16;
		ac->ac_etime_lo = (u16) etime;
Linus Torvalds's avatar
Linus Torvalds committed
445 446 447
	}
#endif
	do_div(elapsed, AHZ);
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
	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
468
static void do_acct_process(struct bsd_acct_struct *acct)
469 470 471 472
{
	acct_t ac;
	unsigned long flim;
	const struct cred *orig_cred;
Al Viro's avatar
Al Viro committed
473
	struct file *file = acct->file;
474 475 476 477 478 479 480 481 482 483 484 485 486

	/*
	 * 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
487
	if (!check_free_space(acct))
488 489 490
		goto out;

	fill_ac(&ac);
Linus Torvalds's avatar
Linus Torvalds committed
491
	/* we really need to bite the bullet and change layout */
492 493
	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);
494
#if ACCT_VERSION == 1 || ACCT_VERSION == 2
Linus Torvalds's avatar
Linus Torvalds committed
495
	/* backward-compatible 16 bit fields */
496 497
	ac.ac_uid16 = ac.ac_uid;
	ac.ac_gid16 = ac.ac_gid;
Linus Torvalds's avatar
Linus Torvalds committed
498
#endif
499
#if ACCT_VERSION == 3
Ying Xue's avatar
Ying Xue committed
500 501 502 503 504 505 506 507 508
	{
		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();
	}
Linus Torvalds's avatar
Linus Torvalds committed
509
#endif
510 511 512 513
	/*
	 * 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
514 515 516 517 518 519
	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);
	}
520
out:
Al Viro's avatar
Al Viro committed
521
	current->signal->rlim[RLIMIT_FSIZE].rlim_cur = flim;
522
	revert_creds(orig_cred);
Linus Torvalds's avatar
Linus Torvalds committed
523 524
}

525 526
/**
 * acct_collect - collect accounting information into pacct_struct
527 528
 * @exitcode: task exit code
 * @group_dead: not 0, if this thread is the last one in the process.
529
 */
530
void acct_collect(long exitcode, int group_dead)
531 532
{
	struct pacct_struct *pacct = &current->signal->pacct;
533
	cputime_t utime, stime;
534 535
	unsigned long vsize = 0;

536
	if (group_dead && current->mm) {
537
		struct vm_area_struct *vma;
538

539 540 541 542 543 544 545 546 547
		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);
	}

548
	spin_lock_irq(&current->sighand->siglock);
549 550 551 552 553 554 555 556 557 558 559 560 561
	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;
562 563 564
	task_cputime(current, &utime, &stime);
	pacct->ac_utime += utime;
	pacct->ac_stime += stime;
565 566 567
	pacct->ac_minflt += current->min_flt;
	pacct->ac_majflt += current->maj_flt;
	spin_unlock_irq(&current->sighand->siglock);
568 569
}

570
static void slow_acct_process(struct pid_namespace *ns)
Linus Torvalds's avatar
Linus Torvalds committed
571
{
572
	for ( ; ns; ns = ns->parent) {
Al Viro's avatar
Al Viro committed
573
		struct bsd_acct_struct *acct = acct_get(ns);
Al Viro's avatar
Al Viro committed
574 575 576
		if (acct) {
			do_acct_process(acct);
			mutex_unlock(&acct->lock);
Al Viro's avatar
Al Viro committed
577
			acct_put(acct);
578 579
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
580
}
581 582

/**
583
 * acct_process
584 585 586 587 588 589 590
 *
 * handles process accounting for an exiting task
 */
void acct_process(void)
{
	struct pid_namespace *ns;

591 592 593 594 595
	/*
	 * This loop is safe lockless, since current is still
	 * alive and holds its namespace, which in turn holds
	 * its parent.
	 */
596
	for (ns = task_active_pid_ns(current); ns != NULL; ns = ns->parent) {
Al Viro's avatar
Al Viro committed
597
		if (ns->bacct)
598 599 600 601
			break;
	}
	if (unlikely(ns))
		slow_acct_process(ns);
602
}