proc_misc.c 23.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 *  linux/fs/proc/proc_misc.c
 *
 *  linux/fs/proc/array.c
 *  Copyright (C) 1992  by Linus Torvalds
 *  based on ideas by Darren Senn
 *
 *  This used to be the part of array.c. See the rest of history and credits
 *  there. I took this into a separate file and switched the thing to generic
 *  proc_file_inode_operations, leaving in array.c only per-process stuff.
 *  Inumbers allocation made dynamic (via create_proc_entry()).  AV, May 1999.
 *
 * Changes:
 * Fulton Green      :  Encapsulated position metric calculations.
 *			<kernel@FultonGreen.com>
 */

#include <linux/types.h>
#include <linux/errno.h>
#include <linux/time.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
23
#include <linux/fs.h>
L
Linus Torvalds 已提交
24 25 26 27 28 29 30 31
#include <linux/tty.h>
#include <linux/string.h>
#include <linux/mman.h>
#include <linux/proc_fs.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/mmzone.h>
#include <linux/pagemap.h>
A
Adrian Bunk 已提交
32
#include <linux/interrupt.h>
L
Linus Torvalds 已提交
33 34
#include <linux/swap.h>
#include <linux/slab.h>
A
Adrian Bunk 已提交
35
#include <linux/genhd.h>
L
Linus Torvalds 已提交
36 37 38 39 40 41 42
#include <linux/smp.h>
#include <linux/signal.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/times.h>
#include <linux/profile.h>
A
Andrew Morton 已提交
43
#include <linux/utsname.h>
L
Linus Torvalds 已提交
44 45 46 47 48
#include <linux/blkdev.h>
#include <linux/hugetlb.h>
#include <linux/jiffies.h>
#include <linux/sysrq.h>
#include <linux/vmalloc.h>
49
#include <linux/crash_dump.h>
50
#include <linux/pid_namespace.h>
51
#include <linux/bootmem.h>
L
Linus Torvalds 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/tlb.h>
#include <asm/div64.h>
#include "internal.h"

#define LOAD_INT(x) ((x) >> FSHIFT)
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
/*
 * Warning: stuff below (imported functions) assumes that its output will fit
 * into one page. For some of those functions it may be wrong. Moreover, we
 * have a way to deal with that gracefully. Right now I used straightforward
 * wrappers, but this needs further analysis wrt potential overflows.
 */
extern int get_hardware_list(char *);
extern int get_stram_list(char *);
extern int get_exec_domain_list(char *);
extern int get_dma_list(char *);

static int proc_calc_metrics(char *page, char **start, off_t off,
				 int count, int *eof, int len)
{
	if (len <= off+count) *eof = 1;
	*start = page + off;
	len -= off;
	if (len>count) len = count;
	if (len<0) len = 0;
	return len;
}

static int loadavg_read_proc(char *page, char **start, off_t off,
				 int count, int *eof, void *data)
{
	int a, b, c;
	int len;
M
Michal Schmidt 已提交
88 89 90 91 92 93 94 95
	unsigned long seq;

	do {
		seq = read_seqbegin(&xtime_lock);
		a = avenrun[0] + (FIXED_1/200);
		b = avenrun[1] + (FIXED_1/200);
		c = avenrun[2] + (FIXED_1/200);
	} while (read_seqretry(&xtime_lock, seq));
L
Linus Torvalds 已提交
96 97 98 99 100

	len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n",
		LOAD_INT(a), LOAD_FRAC(a),
		LOAD_INT(b), LOAD_FRAC(b),
		LOAD_INT(c), LOAD_FRAC(c),
101 102
		nr_running(), nr_threads,
		task_active_pid_ns(current)->last_pid);
L
Linus Torvalds 已提交
103 104 105 106 107 108 109 110 111 112 113 114
	return proc_calc_metrics(page, start, off, count, eof, len);
}

static int uptime_read_proc(char *page, char **start, off_t off,
				 int count, int *eof, void *data)
{
	struct timespec uptime;
	struct timespec idle;
	int len;
	cputime_t idletime = cputime_add(init_task.utime, init_task.stime);

	do_posix_clock_monotonic_gettime(&uptime);
115
	monotonic_to_bootbased(&uptime);
L
Linus Torvalds 已提交
116 117 118 119 120 121 122 123 124 125
	cputime_to_timespec(idletime, &idle);
	len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
			(unsigned long) uptime.tv_sec,
			(uptime.tv_nsec / (NSEC_PER_SEC / 100)),
			(unsigned long) idle.tv_sec,
			(idle.tv_nsec / (NSEC_PER_SEC / 100)));

	return proc_calc_metrics(page, start, off, count, eof, len);
}

126 127 128 129 130
int __attribute__((weak)) arch_report_meminfo(char *page)
{
	return 0;
}

L
Linus Torvalds 已提交
131 132 133 134 135 136 137 138
static int meminfo_read_proc(char *page, char **start, off_t off,
				 int count, int *eof, void *data)
{
	struct sysinfo i;
	int len;
	unsigned long committed;
	unsigned long allowed;
	struct vmalloc_info vmi;
139
	long cached;
L
Linus Torvalds 已提交
140 141 142 143 144 145 146

/*
 * display in kilobytes.
 */
#define K(x) ((x) << (PAGE_SHIFT - 10))
	si_meminfo(&i);
	si_swapinfo(&i);
A
Alan Cox 已提交
147
	committed = atomic_long_read(&vm_committed_space);
L
Linus Torvalds 已提交
148 149 150
	allowed = ((totalram_pages - hugetlb_total_pages())
		* sysctl_overcommit_ratio / 100) + total_swap_pages;

151 152
	cached = global_page_state(NR_FILE_PAGES) -
			total_swapcache_pages - i.bufferram;
153 154 155
	if (cached < 0)
		cached = 0;

L
Linus Torvalds 已提交
156 157 158 159 160 161 162 163 164 165 166 167 168
	get_vmalloc_info(&vmi);

	/*
	 * Tagged format, for easy grepping and expansion.
	 */
	len = sprintf(page,
		"MemTotal:     %8lu kB\n"
		"MemFree:      %8lu kB\n"
		"Buffers:      %8lu kB\n"
		"Cached:       %8lu kB\n"
		"SwapCached:   %8lu kB\n"
		"Active:       %8lu kB\n"
		"Inactive:     %8lu kB\n"
169
#ifdef CONFIG_HIGHMEM
L
Linus Torvalds 已提交
170 171 172 173
		"HighTotal:    %8lu kB\n"
		"HighFree:     %8lu kB\n"
		"LowTotal:     %8lu kB\n"
		"LowFree:      %8lu kB\n"
174
#endif
L
Linus Torvalds 已提交
175 176 177 178
		"SwapTotal:    %8lu kB\n"
		"SwapFree:     %8lu kB\n"
		"Dirty:        %8lu kB\n"
		"Writeback:    %8lu kB\n"
179
		"AnonPages:    %8lu kB\n"
L
Linus Torvalds 已提交
180 181
		"Mapped:       %8lu kB\n"
		"Slab:         %8lu kB\n"
182 183
		"SReclaimable: %8lu kB\n"
		"SUnreclaim:   %8lu kB\n"
184
		"PageTables:   %8lu kB\n"
185
		"NFS_Unstable: %8lu kB\n"
186
		"Bounce:       %8lu kB\n"
187
		"WritebackTmp: %8lu kB\n"
L
Linus Torvalds 已提交
188 189 190 191 192 193 194 195
		"CommitLimit:  %8lu kB\n"
		"Committed_AS: %8lu kB\n"
		"VmallocTotal: %8lu kB\n"
		"VmallocUsed:  %8lu kB\n"
		"VmallocChunk: %8lu kB\n",
		K(i.totalram),
		K(i.freeram),
		K(i.bufferram),
196
		K(cached),
L
Linus Torvalds 已提交
197
		K(total_swapcache_pages),
198 199
		K(global_page_state(NR_ACTIVE)),
		K(global_page_state(NR_INACTIVE)),
200
#ifdef CONFIG_HIGHMEM
L
Linus Torvalds 已提交
201 202 203 204
		K(i.totalhigh),
		K(i.freehigh),
		K(i.totalram-i.totalhigh),
		K(i.freeram-i.freehigh),
205
#endif
L
Linus Torvalds 已提交
206 207
		K(i.totalswap),
		K(i.freeswap),
208
		K(global_page_state(NR_FILE_DIRTY)),
209
		K(global_page_state(NR_WRITEBACK)),
210
		K(global_page_state(NR_ANON_PAGES)),
211
		K(global_page_state(NR_FILE_MAPPED)),
212 213 214 215
		K(global_page_state(NR_SLAB_RECLAIMABLE) +
				global_page_state(NR_SLAB_UNRECLAIMABLE)),
		K(global_page_state(NR_SLAB_RECLAIMABLE)),
		K(global_page_state(NR_SLAB_UNRECLAIMABLE)),
216
		K(global_page_state(NR_PAGETABLE)),
217
		K(global_page_state(NR_UNSTABLE_NFS)),
218
		K(global_page_state(NR_BOUNCE)),
219
		K(global_page_state(NR_WRITEBACK_TEMP)),
L
Linus Torvalds 已提交
220 221 222 223 224 225 226 227 228
		K(allowed),
		K(committed),
		(unsigned long)VMALLOC_TOTAL >> 10,
		vmi.used >> 10,
		vmi.largest_chunk >> 10
		);

		len += hugetlb_report_meminfo(page + len);

229 230
	len += arch_report_meminfo(page + len);

L
Linus Torvalds 已提交
231 232 233 234 235 236 237 238 239 240
	return proc_calc_metrics(page, start, off, count, eof, len);
#undef K
}

static int fragmentation_open(struct inode *inode, struct file *file)
{
	(void)inode;
	return seq_open(file, &fragmentation_op);
}

241
static const struct file_operations fragmentation_file_operations = {
L
Linus Torvalds 已提交
242 243 244 245 246 247
	.open		= fragmentation_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

248 249 250 251 252 253 254 255 256 257 258 259
static int pagetypeinfo_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &pagetypeinfo_op);
}

static const struct file_operations pagetypeinfo_file_ops = {
	.open		= pagetypeinfo_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

N
Nikita Danilov 已提交
260 261 262 263 264
static int zoneinfo_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &zoneinfo_op);
}

265
static const struct file_operations proc_zoneinfo_file_operations = {
N
Nikita Danilov 已提交
266 267 268 269 270 271
	.open		= zoneinfo_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

L
Linus Torvalds 已提交
272 273 274 275 276
static int version_read_proc(char *page, char **start, off_t off,
				 int count, int *eof, void *data)
{
	int len;

277
	len = snprintf(page, PAGE_SIZE, linux_proc_banner,
278 279 280
		utsname()->sysname,
		utsname()->release,
		utsname()->version);
L
Linus Torvalds 已提交
281 282 283
	return proc_calc_metrics(page, start, off, count, eof, len);
}

284
extern const struct seq_operations cpuinfo_op;
L
Linus Torvalds 已提交
285 286 287 288
static int cpuinfo_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &cpuinfo_op);
}
289

290
static const struct file_operations proc_cpuinfo_operations = {
291 292 293 294
	.open		= cpuinfo_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
295 296
};

297
static int devinfo_show(struct seq_file *f, void *v)
298
{
299 300 301 302 303 304
	int i = *(loff_t *) v;

	if (i < CHRDEV_MAJOR_HASH_SIZE) {
		if (i == 0)
			seq_printf(f, "Character devices:\n");
		chrdev_show(f, i);
305 306 307
	}
#ifdef CONFIG_BLOCK
	else {
308 309 310 311
		i -= CHRDEV_MAJOR_HASH_SIZE;
		if (i == 0)
			seq_printf(f, "\nBlock devices:\n");
		blkdev_show(f, i);
312
	}
313
#endif
314
	return 0;
315 316
}

317
static void *devinfo_start(struct seq_file *f, loff_t *pos)
318
{
319 320 321
	if (*pos < (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE))
		return pos;
	return NULL;
322 323
}

324
static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos)
325
{
326 327 328 329
	(*pos)++;
	if (*pos >= (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE))
		return NULL;
	return pos;
330 331
}

332
static void devinfo_stop(struct seq_file *f, void *v)
333
{
334
	/* Nothing to do */
335 336
}

337
static const struct seq_operations devinfo_ops = {
338 339 340 341
	.start = devinfo_start,
	.next  = devinfo_next,
	.stop  = devinfo_stop,
	.show  = devinfo_show
342 343
};

344
static int devinfo_open(struct inode *inode, struct file *filp)
345
{
346
	return seq_open(filp, &devinfo_ops);
347 348
}

349
static const struct file_operations proc_devinfo_operations = {
350 351 352 353 354 355
	.open		= devinfo_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

L
Linus Torvalds 已提交
356 357 358 359
static int vmstat_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &vmstat_op);
}
360
static const struct file_operations proc_vmstat_file_operations = {
L
Linus Torvalds 已提交
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
	.open		= vmstat_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

#ifdef CONFIG_PROC_HARDWARE
static int hardware_read_proc(char *page, char **start, off_t off,
				 int count, int *eof, void *data)
{
	int len = get_hardware_list(page);
	return proc_calc_metrics(page, start, off, count, eof, len);
}
#endif

#ifdef CONFIG_STRAM_PROC
static int stram_read_proc(char *page, char **start, off_t off,
				 int count, int *eof, void *data)
{
	int len = get_stram_list(page);
	return proc_calc_metrics(page, start, off, count, eof, len);
}
#endif

385
#ifdef CONFIG_BLOCK
L
Linus Torvalds 已提交
386 387 388 389
static int partitions_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &partitions_op);
}
390
static const struct file_operations proc_partitions_operations = {
L
Linus Torvalds 已提交
391 392 393 394 395 396 397 398 399 400
	.open		= partitions_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static int diskstats_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &diskstats_op);
}
401
static const struct file_operations proc_diskstats_operations = {
L
Linus Torvalds 已提交
402 403 404 405 406
	.open		= diskstats_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};
407
#endif
L
Linus Torvalds 已提交
408 409

#ifdef CONFIG_MODULES
410
extern const struct seq_operations modules_op;
L
Linus Torvalds 已提交
411 412 413 414
static int modules_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &modules_op);
}
415
static const struct file_operations proc_modules_operations = {
L
Linus Torvalds 已提交
416 417 418 419 420 421 422
	.open		= modules_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};
#endif

423
#ifdef CONFIG_SLABINFO
L
Linus Torvalds 已提交
424 425 426 427
static int slabinfo_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &slabinfo_op);
}
428
static const struct file_operations proc_slabinfo_operations = {
L
Linus Torvalds 已提交
429 430 431 432 433 434
	.open		= slabinfo_open,
	.read		= seq_read,
	.write		= slabinfo_write,
	.llseek		= seq_lseek,
	.release	= seq_release,
};
435 436

#ifdef CONFIG_DEBUG_SLAB_LEAK
437
extern const struct seq_operations slabstats_op;
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
static int slabstats_open(struct inode *inode, struct file *file)
{
	unsigned long *n = kzalloc(PAGE_SIZE, GFP_KERNEL);
	int ret = -ENOMEM;
	if (n) {
		ret = seq_open(file, &slabstats_op);
		if (!ret) {
			struct seq_file *m = file->private_data;
			*n = PAGE_SIZE / (2 * sizeof(unsigned long));
			m->private = n;
			n = NULL;
		}
		kfree(n);
	}
	return ret;
}

455
static const struct file_operations proc_slabstats_operations = {
456 457 458
	.open		= slabstats_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
459
	.release	= seq_release_private,
460 461
};
#endif
462
#endif
L
Linus Torvalds 已提交
463

464 465 466 467 468 469 470 471 472 473 474 475 476 477
#ifdef CONFIG_MMU
static int vmalloc_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &vmalloc_op);
}

static const struct file_operations proc_vmalloc_operations = {
	.open		= vmalloc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};
#endif

478 479 480 481 482 483 484
#ifndef arch_irq_stat_cpu
#define arch_irq_stat_cpu(cpu) 0
#endif
#ifndef arch_irq_stat
#define arch_irq_stat() 0
#endif

L
Linus Torvalds 已提交
485 486 487 488 489
static int show_stat(struct seq_file *p, void *v)
{
	int i;
	unsigned long jif;
	cputime64_t user, nice, system, idle, iowait, irq, softirq, steal;
490
	cputime64_t guest;
L
Linus Torvalds 已提交
491
	u64 sum = 0;
492
	struct timespec boottime;
493 494 495 496 497
	unsigned int *per_irq_sum;

	per_irq_sum = kzalloc(sizeof(unsigned int)*NR_IRQS, GFP_KERNEL);
	if (!per_irq_sum)
		return -ENOMEM;
L
Linus Torvalds 已提交
498 499 500

	user = nice = system = idle = iowait =
		irq = softirq = steal = cputime64_zero;
501
	guest = cputime64_zero;
502 503
	getboottime(&boottime);
	jif = boottime.tv_sec;
L
Linus Torvalds 已提交
504

505
	for_each_possible_cpu(i) {
L
Linus Torvalds 已提交
506 507 508 509 510 511 512 513 514 515
		int j;

		user = cputime64_add(user, kstat_cpu(i).cpustat.user);
		nice = cputime64_add(nice, kstat_cpu(i).cpustat.nice);
		system = cputime64_add(system, kstat_cpu(i).cpustat.system);
		idle = cputime64_add(idle, kstat_cpu(i).cpustat.idle);
		iowait = cputime64_add(iowait, kstat_cpu(i).cpustat.iowait);
		irq = cputime64_add(irq, kstat_cpu(i).cpustat.irq);
		softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
		steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
516
		guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
517 518 519 520 521
		for (j = 0; j < NR_IRQS; j++) {
			unsigned int temp = kstat_cpu(i).irqs[j];
			sum += temp;
			per_irq_sum[j] += temp;
		}
522
		sum += arch_irq_stat_cpu(i);
L
Linus Torvalds 已提交
523
	}
524
	sum += arch_irq_stat();
L
Linus Torvalds 已提交
525

526
	seq_printf(p, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
L
Linus Torvalds 已提交
527 528 529 530 531 532 533
		(unsigned long long)cputime64_to_clock_t(user),
		(unsigned long long)cputime64_to_clock_t(nice),
		(unsigned long long)cputime64_to_clock_t(system),
		(unsigned long long)cputime64_to_clock_t(idle),
		(unsigned long long)cputime64_to_clock_t(iowait),
		(unsigned long long)cputime64_to_clock_t(irq),
		(unsigned long long)cputime64_to_clock_t(softirq),
534 535
		(unsigned long long)cputime64_to_clock_t(steal),
		(unsigned long long)cputime64_to_clock_t(guest));
L
Linus Torvalds 已提交
536 537 538 539 540 541 542 543 544 545 546
	for_each_online_cpu(i) {

		/* Copy values here to work around gcc-2.95.3, gcc-2.96 */
		user = kstat_cpu(i).cpustat.user;
		nice = kstat_cpu(i).cpustat.nice;
		system = kstat_cpu(i).cpustat.system;
		idle = kstat_cpu(i).cpustat.idle;
		iowait = kstat_cpu(i).cpustat.iowait;
		irq = kstat_cpu(i).cpustat.irq;
		softirq = kstat_cpu(i).cpustat.softirq;
		steal = kstat_cpu(i).cpustat.steal;
547 548 549
		guest = kstat_cpu(i).cpustat.guest;
		seq_printf(p,
			"cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
L
Linus Torvalds 已提交
550 551 552 553 554 555 556 557
			i,
			(unsigned long long)cputime64_to_clock_t(user),
			(unsigned long long)cputime64_to_clock_t(nice),
			(unsigned long long)cputime64_to_clock_t(system),
			(unsigned long long)cputime64_to_clock_t(idle),
			(unsigned long long)cputime64_to_clock_t(iowait),
			(unsigned long long)cputime64_to_clock_t(irq),
			(unsigned long long)cputime64_to_clock_t(softirq),
558 559
			(unsigned long long)cputime64_to_clock_t(steal),
			(unsigned long long)cputime64_to_clock_t(guest));
L
Linus Torvalds 已提交
560 561 562 563
	}
	seq_printf(p, "intr %llu", (unsigned long long)sum);

	for (i = 0; i < NR_IRQS; i++)
564
		seq_printf(p, " %u", per_irq_sum[i]);
L
Linus Torvalds 已提交
565 566 567 568 569 570 571 572 573 574 575 576 577

	seq_printf(p,
		"\nctxt %llu\n"
		"btime %lu\n"
		"processes %lu\n"
		"procs_running %lu\n"
		"procs_blocked %lu\n",
		nr_context_switches(),
		(unsigned long)jif,
		total_forks,
		nr_running(),
		nr_iowait());

578
	kfree(per_irq_sum);
L
Linus Torvalds 已提交
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
	return 0;
}

static int stat_open(struct inode *inode, struct file *file)
{
	unsigned size = 4096 * (1 + num_possible_cpus() / 32);
	char *buf;
	struct seq_file *m;
	int res;

	/* don't ask for more than the kmalloc() max size, currently 128 KB */
	if (size > 128 * 1024)
		size = 128 * 1024;
	buf = kmalloc(size, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	res = single_open(file, show_stat, NULL);
	if (!res) {
		m = file->private_data;
		m->buf = buf;
		m->size = size;
	} else
		kfree(buf);
	return res;
}
605
static const struct file_operations proc_stat_operations = {
L
Linus Torvalds 已提交
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
	.open		= stat_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

/*
 * /proc/interrupts
 */
static void *int_seq_start(struct seq_file *f, loff_t *pos)
{
	return (*pos <= NR_IRQS) ? pos : NULL;
}

static void *int_seq_next(struct seq_file *f, void *v, loff_t *pos)
{
	(*pos)++;
	if (*pos > NR_IRQS)
		return NULL;
	return pos;
}

static void int_seq_stop(struct seq_file *f, void *v)
{
	/* Nothing to do */
}


634
static const struct seq_operations int_seq_ops = {
L
Linus Torvalds 已提交
635 636 637 638 639 640 641 642 643 644 645
	.start = int_seq_start,
	.next  = int_seq_next,
	.stop  = int_seq_stop,
	.show  = show_interrupts
};

static int interrupts_open(struct inode *inode, struct file *filp)
{
	return seq_open(filp, &int_seq_ops);
}

646
static const struct file_operations proc_interrupts_operations = {
L
Linus Torvalds 已提交
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
	.open		= interrupts_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static int filesystems_read_proc(char *page, char **start, off_t off,
				 int count, int *eof, void *data)
{
	int len = get_filesystem_list(page);
	return proc_calc_metrics(page, start, off, count, eof, len);
}

static int cmdline_read_proc(char *page, char **start, off_t off,
				 int count, int *eof, void *data)
{
	int len;

	len = sprintf(page, "%s\n", saved_command_line);
	return proc_calc_metrics(page, start, off, count, eof, len);
}

669
static int locks_open(struct inode *inode, struct file *filp)
L
Linus Torvalds 已提交
670
{
671
	return seq_open(filp, &locks_seq_operations);
L
Linus Torvalds 已提交
672 673
}

674 675 676 677 678 679 680
static const struct file_operations proc_locks_operations = {
	.open		= locks_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

L
Linus Torvalds 已提交
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
static int execdomains_read_proc(char *page, char **start, off_t off,
				 int count, int *eof, void *data)
{
	int len = get_exec_domain_list(page);
	return proc_calc_metrics(page, start, off, count, eof, len);
}

#ifdef CONFIG_MAGIC_SYSRQ
/*
 * writing 'C' to /proc/sysrq-trigger is like sysrq-C
 */
static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
				   size_t count, loff_t *ppos)
{
	if (count) {
		char c;

		if (get_user(c, buf))
			return -EFAULT;
700
		__handle_sysrq(c, NULL, 0);
L
Linus Torvalds 已提交
701 702 703 704
	}
	return count;
}

705
static const struct file_operations proc_sysrq_trigger_operations = {
L
Linus Torvalds 已提交
706 707 708 709
	.write		= write_sysrq_trigger,
};
#endif

710
#ifdef CONFIG_PROC_PAGE_MONITOR
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
#define KPMSIZE sizeof(u64)
#define KPMMASK (KPMSIZE - 1)
/* /proc/kpagecount - an array exposing page counts
 *
 * Each entry is a u64 representing the corresponding
 * physical page count.
 */
static ssize_t kpagecount_read(struct file *file, char __user *buf,
			     size_t count, loff_t *ppos)
{
	u64 __user *out = (u64 __user *)buf;
	struct page *ppage;
	unsigned long src = *ppos;
	unsigned long pfn;
	ssize_t ret = 0;
	u64 pcount;

	pfn = src / KPMSIZE;
	count = min_t(size_t, count, (max_pfn * KPMSIZE) - src);
	if (src & KPMMASK || count & KPMMASK)
731
		return -EINVAL;
732 733

	while (count > 0) {
734 735 736 737
		ppage = NULL;
		if (pfn_valid(pfn))
			ppage = pfn_to_page(pfn);
		pfn++;
738 739 740
		if (!ppage)
			pcount = 0;
		else
741
			pcount = page_mapcount(ppage);
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761

		if (put_user(pcount, out++)) {
			ret = -EFAULT;
			break;
		}

		count -= KPMSIZE;
	}

	*ppos += (char __user *)out - buf;
	if (!ret)
		ret = (char __user *)out - buf;
	return ret;
}

static struct file_operations proc_kpagecount_operations = {
	.llseek = mem_lseek,
	.read = kpagecount_read,
};

762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
/* /proc/kpageflags - an array exposing page flags
 *
 * Each entry is a u64 representing the corresponding
 * physical page flags.
 */

/* These macros are used to decouple internal flags from exported ones */

#define KPF_LOCKED     0
#define KPF_ERROR      1
#define KPF_REFERENCED 2
#define KPF_UPTODATE   3
#define KPF_DIRTY      4
#define KPF_LRU        5
#define KPF_ACTIVE     6
#define KPF_SLAB       7
#define KPF_WRITEBACK  8
#define KPF_RECLAIM    9
#define KPF_BUDDY     10

#define kpf_copy_bit(flags, srcpos, dstpos) (((flags >> srcpos) & 1) << dstpos)

static ssize_t kpageflags_read(struct file *file, char __user *buf,
			     size_t count, loff_t *ppos)
{
	u64 __user *out = (u64 __user *)buf;
	struct page *ppage;
	unsigned long src = *ppos;
	unsigned long pfn;
	ssize_t ret = 0;
	u64 kflags, uflags;

	pfn = src / KPMSIZE;
	count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src);
	if (src & KPMMASK || count & KPMMASK)
797
		return -EINVAL;
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838

	while (count > 0) {
		ppage = NULL;
		if (pfn_valid(pfn))
			ppage = pfn_to_page(pfn);
		pfn++;
		if (!ppage)
			kflags = 0;
		else
			kflags = ppage->flags;

		uflags = kpf_copy_bit(KPF_LOCKED, PG_locked, kflags) |
			kpf_copy_bit(kflags, KPF_ERROR, PG_error) |
			kpf_copy_bit(kflags, KPF_REFERENCED, PG_referenced) |
			kpf_copy_bit(kflags, KPF_UPTODATE, PG_uptodate) |
			kpf_copy_bit(kflags, KPF_DIRTY, PG_dirty) |
			kpf_copy_bit(kflags, KPF_LRU, PG_lru) |
			kpf_copy_bit(kflags, KPF_ACTIVE, PG_active) |
			kpf_copy_bit(kflags, KPF_SLAB, PG_slab) |
			kpf_copy_bit(kflags, KPF_WRITEBACK, PG_writeback) |
			kpf_copy_bit(kflags, KPF_RECLAIM, PG_reclaim) |
			kpf_copy_bit(kflags, KPF_BUDDY, PG_buddy);

		if (put_user(uflags, out++)) {
			ret = -EFAULT;
			break;
		}

		count -= KPMSIZE;
	}

	*ppos += (char __user *)out - buf;
	if (!ret)
		ret = (char __user *)out - buf;
	return ret;
}

static struct file_operations proc_kpageflags_operations = {
	.llseek = mem_lseek,
	.read = kpageflags_read,
};
839
#endif /* CONFIG_PROC_PAGE_MONITOR */
840

L
Linus Torvalds 已提交
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
struct proc_dir_entry *proc_root_kcore;

void __init proc_misc_init(void)
{
	static struct {
		char *name;
		int (*read_proc)(char*,char**,off_t,int,int*,void*);
	} *p, simple_ones[] = {
		{"loadavg",     loadavg_read_proc},
		{"uptime",	uptime_read_proc},
		{"meminfo",	meminfo_read_proc},
		{"version",	version_read_proc},
#ifdef CONFIG_PROC_HARDWARE
		{"hardware",	hardware_read_proc},
#endif
#ifdef CONFIG_STRAM_PROC
		{"stram",	stram_read_proc},
#endif
		{"filesystems",	filesystems_read_proc},
		{"cmdline",	cmdline_read_proc},
		{"execdomains",	execdomains_read_proc},
		{NULL,}
	};
	for (p = simple_ones; p->name; p++)
		create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL);

	proc_symlink("mounts", NULL, "self/mounts");

	/* And now for trickier ones */
870
#ifdef CONFIG_PRINTK
871
	proc_create("kmsg", S_IRUSR, NULL, &proc_kmsg_operations);
872
#endif
A
Alexey Dobriyan 已提交
873 874 875
	proc_create("locks", 0, NULL, &proc_locks_operations);
	proc_create("devices", 0, NULL, &proc_devinfo_operations);
	proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations);
876
#ifdef CONFIG_BLOCK
A
Alexey Dobriyan 已提交
877
	proc_create("partitions", 0, NULL, &proc_partitions_operations);
878
#endif
A
Alexey Dobriyan 已提交
879 880
	proc_create("stat", 0, NULL, &proc_stat_operations);
	proc_create("interrupts", 0, NULL, &proc_interrupts_operations);
881
#ifdef CONFIG_SLABINFO
A
Alexey Dobriyan 已提交
882
	proc_create("slabinfo",S_IWUSR|S_IRUGO,NULL,&proc_slabinfo_operations);
883
#ifdef CONFIG_DEBUG_SLAB_LEAK
A
Alexey Dobriyan 已提交
884
	proc_create("slab_allocators", 0, NULL, &proc_slabstats_operations);
885
#endif
886 887 888
#endif
#ifdef CONFIG_MMU
	proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations);
889
#endif
A
Alexey Dobriyan 已提交
890 891 892 893
	proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
	proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops);
	proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations);
	proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations);
894
#ifdef CONFIG_BLOCK
A
Alexey Dobriyan 已提交
895
	proc_create("diskstats", 0, NULL, &proc_diskstats_operations);
896
#endif
L
Linus Torvalds 已提交
897
#ifdef CONFIG_MODULES
A
Alexey Dobriyan 已提交
898
	proc_create("modules", 0, NULL, &proc_modules_operations);
L
Linus Torvalds 已提交
899 900
#endif
#ifdef CONFIG_SCHEDSTATS
A
Alexey Dobriyan 已提交
901
	proc_create("schedstat", 0, NULL, &proc_schedstat_operations);
L
Linus Torvalds 已提交
902 903
#endif
#ifdef CONFIG_PROC_KCORE
A
Alexey Dobriyan 已提交
904 905
	proc_root_kcore = proc_create("kcore", S_IRUSR, NULL, &proc_kcore_operations);
	if (proc_root_kcore)
L
Linus Torvalds 已提交
906 907 908
		proc_root_kcore->size =
				(size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
#endif
909
#ifdef CONFIG_PROC_PAGE_MONITOR
A
Alexey Dobriyan 已提交
910 911
	proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations);
	proc_create("kpageflags", S_IRUSR, NULL, &proc_kpageflags_operations);
912
#endif
913
#ifdef CONFIG_PROC_VMCORE
A
Alexey Dobriyan 已提交
914
	proc_vmcore = proc_create("vmcore", S_IRUSR, NULL, &proc_vmcore_operations);
915
#endif
L
Linus Torvalds 已提交
916
#ifdef CONFIG_MAGIC_SYSRQ
A
Alexey Dobriyan 已提交
917
	proc_create("sysrq-trigger", S_IWUSR, NULL, &proc_sysrq_trigger_operations);
L
Linus Torvalds 已提交
918 919
#endif
}