acct.c 16.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>
Paul McQuade's avatar
Paul McQuade committed
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 {
82
83
84
85
86
87
88
89
	atomic_long_t		count;
	union {
		struct {
			struct hlist_node	s_list;
			struct hlist_node	m_list;
		};
		struct rcu_head rcu;
	};
Al Viro's avatar
Al Viro committed
90
	struct mutex		lock;
Al Viro's avatar
Al Viro committed
91
92
	int			active;
	unsigned long		needcheck;
Linus Torvalds's avatar
Linus Torvalds committed
93
	struct file		*file;
94
	struct pid_namespace	*ns;
95
96
	struct work_struct	work;
	struct completion	done;
Linus Torvalds's avatar
Linus Torvalds committed
97
98
};

99
100
101
102
103
static void acct_free_rcu(struct rcu_head *head)
{
	kfree(container_of(head, struct bsd_acct_struct, rcu));
}

104
105
static DEFINE_SPINLOCK(acct_lock);

Linus Torvalds's avatar
Linus Torvalds committed
106
107
108
/*
 * Check the amount of free space and suspend/resume accordingly.
 */
Al Viro's avatar
Al Viro committed
109
static int check_free_space(struct bsd_acct_struct *acct)
Linus Torvalds's avatar
Linus Torvalds committed
110
111
112
{
	struct kstatfs sbuf;

Al Viro's avatar
Al Viro committed
113
	if (time_is_before_jiffies(acct->needcheck))
Linus Torvalds's avatar
Linus Torvalds committed
114
115
116
		goto out;

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

120
	if (acct->active) {
Al Viro's avatar
Al Viro committed
121
122
123
		u64 suspend = sbuf.f_blocks * SUSPEND;
		do_div(suspend, 100);
		if (sbuf.f_bavail <= suspend) {
124
			acct->active = 0;
Linus Torvalds's avatar
Linus Torvalds committed
125
126
127
			printk(KERN_INFO "Process accounting paused\n");
		}
	} else {
Al Viro's avatar
Al Viro committed
128
129
130
		u64 resume = sbuf.f_blocks * RESUME;
		do_div(resume, 100);
		if (sbuf.f_bavail >= resume) {
131
			acct->active = 1;
Linus Torvalds's avatar
Linus Torvalds committed
132
133
134
135
			printk(KERN_INFO "Process accounting resumed\n");
		}
	}

Al Viro's avatar
Al Viro committed
136
	acct->needcheck = jiffies + ACCT_TIMEOUT*HZ;
Linus Torvalds's avatar
Linus Torvalds committed
137
out:
Al Viro's avatar
Al Viro committed
138
	return acct->active;
Linus Torvalds's avatar
Linus Torvalds committed
139
140
}

Al Viro's avatar
Al Viro committed
141
static void acct_put(struct bsd_acct_struct *p)
Linus Torvalds's avatar
Linus Torvalds committed
142
{
143
144
	if (atomic_long_dec_and_test(&p->count))
		call_rcu(&p->rcu, acct_free_rcu);
Al Viro's avatar
Al Viro committed
145
146
}

Al Viro's avatar
Al Viro committed
147
148
static struct bsd_acct_struct *__acct_get(struct bsd_acct_struct *res)
{
149
150
151
152
153
154
	if (!atomic_long_inc_not_zero(&res->count)) {
		rcu_read_unlock();
		cpu_relax();
		return NULL;
	}
	rcu_read_unlock();
Al Viro's avatar
Al Viro committed
155
156
157
	mutex_lock(&res->lock);
	if (!res->ns) {
		mutex_unlock(&res->lock);
158
		acct_put(res);
Al Viro's avatar
Al Viro committed
159
160
161
162
163
164
		return NULL;
	}
	return res;
}

static struct bsd_acct_struct *acct_get(struct pid_namespace *ns)
Al Viro's avatar
Al Viro committed
165
166
167
{
	struct bsd_acct_struct *res;
again:
168
169
170
171
172
	smp_rmb();
	rcu_read_lock();
	res = ACCESS_ONCE(ns->bacct);
	if (!res) {
		rcu_read_unlock();
Al Viro's avatar
Al Viro committed
173
		return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
174
	}
175
	res = __acct_get(res);
Al Viro's avatar
Al Viro committed
176
177
	if (!res)
		goto again;
Al Viro's avatar
Al Viro committed
178
179
180
	return res;
}

181
182
183
184
185
186
187
188
189
190
191
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;
	mnt_unpin(file->f_path.mnt);
	if (file->f_op->flush)
		file->f_op->flush(file, NULL);
	__fput_sync(file);
	complete(&acct->done);
}

Al Viro's avatar
Al Viro committed
192
193
194
195
196
static void acct_kill(struct bsd_acct_struct *acct,
		      struct bsd_acct_struct *new)
{
	if (acct) {
		struct pid_namespace *ns = acct->ns;
197
		do_acct_process(acct);
198
199
200
201
		INIT_WORK(&acct->work, close_work);
		init_completion(&acct->done);
		schedule_work(&acct->work);
		wait_for_completion(&acct->done);
Al Viro's avatar
Al Viro committed
202
		spin_lock(&acct_lock);
Al Viro's avatar
Al Viro committed
203
204
		hlist_del(&acct->m_list);
		hlist_del(&acct->s_list);
205
		spin_unlock(&acct_lock);
Al Viro's avatar
Al Viro committed
206
207
		ns->bacct = new;
		if (new) {
Al Viro's avatar
Al Viro committed
208
			struct vfsmount *m = new->file->f_path.mnt;
209
			spin_lock(&acct_lock);
Al Viro's avatar
Al Viro committed
210
211
			hlist_add_head(&new->s_list, &m->mnt_sb->s_pins);
			hlist_add_head(&new->m_list, &real_mount(m)->mnt_pins);
212
213
			spin_unlock(&acct_lock);
			mutex_unlock(&new->lock);
Al Viro's avatar
Al Viro committed
214
215
		}
		acct->ns = NULL;
216
		atomic_long_dec(&acct->count);
Al Viro's avatar
Al Viro committed
217
		mutex_unlock(&acct->lock);
218
		acct_put(acct);
Linus Torvalds's avatar
Linus Torvalds committed
219
220
221
	}
}

222
static int acct_on(struct filename *pathname)
223
224
{
	struct file *file;
225
	struct vfsmount *mnt;
Al Viro's avatar
Al Viro committed
226
227
228
229
230
231
	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;
232
233

	/* Difference from BSD - they don't do O_APPEND */
234
	file = file_open_name(pathname, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
Al Viro's avatar
Al Viro committed
235
236
	if (IS_ERR(file)) {
		kfree(acct);
237
		return PTR_ERR(file);
Al Viro's avatar
Al Viro committed
238
	}
239

Al Viro's avatar
Al Viro committed
240
	if (!S_ISREG(file_inode(file)->i_mode)) {
Al Viro's avatar
Al Viro committed
241
		kfree(acct);
242
243
244
245
246
		filp_close(file, NULL);
		return -EACCES;
	}

	if (!file->f_op->write) {
Al Viro's avatar
Al Viro committed
247
		kfree(acct);
248
249
250
251
		filp_close(file, NULL);
		return -EIO;
	}

252
	atomic_long_set(&acct->count, 1);
Al Viro's avatar
Al Viro committed
253
254
255
256
257
	acct->file = file;
	acct->needcheck = jiffies;
	acct->ns = ns;
	mutex_init(&acct->lock);
	mnt = file->f_path.mnt;
Al Viro's avatar
Al Viro committed
258
	mnt_pin(mnt);
259

Al Viro's avatar
Al Viro committed
260
	old = acct_get(ns);
261
	mutex_lock_nested(&acct->lock, 1);	/* nobody has seen it yet */
Al Viro's avatar
Al Viro committed
262
263
264
	if (old) {
		acct_kill(old, acct);
	} else {
265
		ns->bacct = acct;
266
		spin_lock(&acct_lock);
Al Viro's avatar
Al Viro committed
267
268
		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
269
		spin_unlock(&acct_lock);
270
		mutex_unlock(&acct->lock);
271
	}
272
	mntput(mnt); /* it's pinned, now give up active reference */
273
274
275
	return 0;
}

Al Viro's avatar
Al Viro committed
276
277
static DEFINE_MUTEX(acct_on_mutex);

278
279
280
281
282
283
284
285
286
287
/**
 * 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
288
 */
289
SYSCALL_DEFINE1(acct, const char __user *, name)
Linus Torvalds's avatar
Linus Torvalds committed
290
{
Eric Paris's avatar
Eric Paris committed
291
	int error = 0;
Linus Torvalds's avatar
Linus Torvalds committed
292
293
294
295
296

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

	if (name) {
297
		struct filename *tmp = getname(name);
298
		if (IS_ERR(tmp))
Paul McQuade's avatar
Paul McQuade committed
299
			return PTR_ERR(tmp);
Al Viro's avatar
Al Viro committed
300
		mutex_lock(&acct_on_mutex);
301
		error = acct_on(tmp);
Al Viro's avatar
Al Viro committed
302
		mutex_unlock(&acct_on_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
303
		putname(tmp);
304
	} else {
Al Viro's avatar
Al Viro committed
305
		acct_kill(acct_get(task_active_pid_ns(current)), NULL);
Linus Torvalds's avatar
Linus Torvalds committed
306
	}
Eric Paris's avatar
Eric Paris committed
307

308
309
	return error;
}
Linus Torvalds's avatar
Linus Torvalds committed
310

Al Viro's avatar
Al Viro committed
311
void acct_auto_close_mnt(struct hlist_head *list)
312
{
313
	rcu_read_lock();
Al Viro's avatar
Al Viro committed
314
	while (1) {
315
316
		struct hlist_node *p = ACCESS_ONCE(list->first);
		if (!p)
Al Viro's avatar
Al Viro committed
317
			break;
318
		acct_kill(__acct_get(hlist_entry(p,
Al Viro's avatar
Al Viro committed
319
320
						 struct bsd_acct_struct,
						 m_list)), NULL);
321
		rcu_read_lock();
Al Viro's avatar
Al Viro committed
322
	}
323
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
324
325
}

Al Viro's avatar
Al Viro committed
326
void acct_auto_close(struct hlist_head *list)
Linus Torvalds's avatar
Linus Torvalds committed
327
{
328
	rcu_read_lock();
Al Viro's avatar
Al Viro committed
329
	while (1) {
330
331
		struct hlist_node *p = ACCESS_ONCE(list->first);
		if (!p)
Al Viro's avatar
Al Viro committed
332
			break;
333
		acct_kill(__acct_get(hlist_entry(p,
Al Viro's avatar
Al Viro committed
334
335
						 struct bsd_acct_struct,
						 s_list)), NULL);
336
		rcu_read_lock();
Al Viro's avatar
Al Viro committed
337
	}
338
	rcu_read_unlock();
339
340
341
342
}

void acct_exit_ns(struct pid_namespace *ns)
{
Al Viro's avatar
Al Viro committed
343
	acct_kill(acct_get(ns), NULL);
Linus Torvalds's avatar
Linus Torvalds committed
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
}

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

	/*
370
371
	 * If we need to round up, do it (and handle overflow correctly).
	 */
Linus Torvalds's avatar
Linus Torvalds committed
372
373
374
375
376
377
	if (rnd && (++value > MAXFRACT)) {
		value >>= EXPSIZE;
		exp++;
	}

	/*
378
379
	 * Clean it up and polish it off.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
	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)
{
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
	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
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
}
#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
Ingo Molnar's avatar
Ingo Molnar committed
454
 *  do_exit() or when switching to a different output file.
Linus Torvalds's avatar
Linus Torvalds committed
455
456
 */

457
static void fill_ac(acct_t *ac)
Linus Torvalds's avatar
Linus Torvalds committed
458
{
459
	struct pacct_struct *pacct = &current->signal->pacct;
460
	u64 elapsed, run_time;
461
	struct tty_struct *tty;
Linus Torvalds's avatar
Linus Torvalds committed
462
463
464
465
466

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

469
470
	ac->ac_version = ACCT_VERSION | ACCT_BYTEORDER;
	strlcpy(ac->ac_comm, current->comm, sizeof(ac->ac_comm));
Linus Torvalds's avatar
Linus Torvalds committed
471
472

	/* calculate run_time in nsec*/
473
474
	run_time = ktime_get_ns();
	run_time -= current->group_leader->start_time;
Linus Torvalds's avatar
Linus Torvalds committed
475
476
477
	/* convert nsec -> AHZ */
	elapsed = nsec_to_AHZ(run_time);
#if ACCT_VERSION==3
478
	ac->ac_etime = encode_float(elapsed);
Linus Torvalds's avatar
Linus Torvalds committed
479
#else
480
	ac->ac_etime = encode_comp_t(elapsed < (unsigned long) -1l ?
Linus Torvalds's avatar
Linus Torvalds committed
481
482
483
484
485
486
	                       (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);
487
488
		ac->ac_etime_hi = etime >> 16;
		ac->ac_etime_lo = (u16) etime;
Linus Torvalds's avatar
Linus Torvalds committed
489
490
491
	}
#endif
	do_div(elapsed, AHZ);
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
	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
512
static void do_acct_process(struct bsd_acct_struct *acct)
513
514
515
516
{
	acct_t ac;
	unsigned long flim;
	const struct cred *orig_cred;
Al Viro's avatar
Al Viro committed
517
518
	struct pid_namespace *ns = acct->ns;
	struct file *file = acct->file;
519
520
521
522
523
524
525
526
527
528
529
530
531

	/*
	 * 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
532
	if (!check_free_space(acct))
533
534
535
		goto out;

	fill_ac(&ac);
Linus Torvalds's avatar
Linus Torvalds committed
536
	/* we really need to bite the bullet and change layout */
537
538
	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
539
540
#if ACCT_VERSION==1 || ACCT_VERSION==2
	/* backward-compatible 16 bit fields */
541
542
	ac.ac_uid16 = ac.ac_uid;
	ac.ac_gid16 = ac.ac_gid;
Linus Torvalds's avatar
Linus Torvalds committed
543
544
#endif
#if ACCT_VERSION==3
545
	ac.ac_pid = task_tgid_nr_ns(current, ns);
546
	rcu_read_lock();
547
	ac.ac_ppid = task_tgid_nr_ns(rcu_dereference(current->real_parent), ns);
548
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
549
#endif
550
551
552
553
	/*
	 * 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
554
555
556
557
558
559
	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);
	}
560
out:
Al Viro's avatar
Al Viro committed
561
	current->signal->rlim[RLIMIT_FSIZE].rlim_cur = flim;
562
	revert_creds(orig_cred);
Linus Torvalds's avatar
Linus Torvalds committed
563
564
}

565
566
/**
 * acct_collect - collect accounting information into pacct_struct
567
568
 * @exitcode: task exit code
 * @group_dead: not 0, if this thread is the last one in the process.
569
 */
570
void acct_collect(long exitcode, int group_dead)
571
572
{
	struct pacct_struct *pacct = &current->signal->pacct;
573
	cputime_t utime, stime;
574
575
	unsigned long vsize = 0;

576
	if (group_dead && current->mm) {
577
578
579
580
581
582
583
584
585
586
		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);
	}

587
	spin_lock_irq(&current->sighand->siglock);
588
589
590
591
592
593
594
595
596
597
598
599
600
	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;
601
602
603
	task_cputime(current, &utime, &stime);
	pacct->ac_utime += utime;
	pacct->ac_stime += stime;
604
605
606
	pacct->ac_minflt += current->min_flt;
	pacct->ac_majflt += current->maj_flt;
	spin_unlock_irq(&current->sighand->siglock);
607
608
}

609
static void slow_acct_process(struct pid_namespace *ns)
Linus Torvalds's avatar
Linus Torvalds committed
610
{
611
	for ( ; ns; ns = ns->parent) {
Al Viro's avatar
Al Viro committed
612
		struct bsd_acct_struct *acct = acct_get(ns);
Al Viro's avatar
Al Viro committed
613
614
615
616
		if (acct) {
			do_acct_process(acct);
			mutex_unlock(&acct->lock);
			acct_put(acct);
617
618
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
619
}
620
621

/**
622
 * acct_process
623
624
625
626
627
628
629
 *
 * handles process accounting for an exiting task
 */
void acct_process(void)
{
	struct pid_namespace *ns;

630
631
632
633
634
	/*
	 * This loop is safe lockless, since current is still
	 * alive and holds its namespace, which in turn holds
	 * its parent.
	 */
635
	for (ns = task_active_pid_ns(current); ns != NULL; ns = ns->parent) {
Al Viro's avatar
Al Viro committed
636
		if (ns->bacct)
637
638
639
640
			break;
	}
	if (unlikely(ns))
		slow_acct_process(ns);
641
}