diff options
Diffstat (limited to 'fs/proc/proc_misc.c')
-rw-r--r-- | fs/proc/proc_misc.c | 172 |
1 files changed, 156 insertions, 16 deletions
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 3462bfde89f6..468805d40e2b 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/mm.h> | 29 | #include <linux/mm.h> |
30 | #include <linux/mmzone.h> | 30 | #include <linux/mmzone.h> |
31 | #include <linux/pagemap.h> | 31 | #include <linux/pagemap.h> |
32 | #include <linux/interrupt.h> | ||
32 | #include <linux/swap.h> | 33 | #include <linux/swap.h> |
33 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
34 | #include <linux/smp.h> | 35 | #include <linux/smp.h> |
@@ -46,6 +47,7 @@ | |||
46 | #include <linux/vmalloc.h> | 47 | #include <linux/vmalloc.h> |
47 | #include <linux/crash_dump.h> | 48 | #include <linux/crash_dump.h> |
48 | #include <linux/pid_namespace.h> | 49 | #include <linux/pid_namespace.h> |
50 | #include <linux/bootmem.h> | ||
49 | #include <asm/uaccess.h> | 51 | #include <asm/uaccess.h> |
50 | #include <asm/pgtable.h> | 52 | #include <asm/pgtable.h> |
51 | #include <asm/io.h> | 53 | #include <asm/io.h> |
@@ -63,7 +65,6 @@ | |||
63 | */ | 65 | */ |
64 | extern int get_hardware_list(char *); | 66 | extern int get_hardware_list(char *); |
65 | extern int get_stram_list(char *); | 67 | extern int get_stram_list(char *); |
66 | extern int get_filesystem_list(char *); | ||
67 | extern int get_exec_domain_list(char *); | 68 | extern int get_exec_domain_list(char *); |
68 | extern int get_dma_list(char *); | 69 | extern int get_dma_list(char *); |
69 | 70 | ||
@@ -83,10 +84,15 @@ static int loadavg_read_proc(char *page, char **start, off_t off, | |||
83 | { | 84 | { |
84 | int a, b, c; | 85 | int a, b, c; |
85 | int len; | 86 | int len; |
87 | unsigned long seq; | ||
88 | |||
89 | do { | ||
90 | seq = read_seqbegin(&xtime_lock); | ||
91 | a = avenrun[0] + (FIXED_1/200); | ||
92 | b = avenrun[1] + (FIXED_1/200); | ||
93 | c = avenrun[2] + (FIXED_1/200); | ||
94 | } while (read_seqretry(&xtime_lock, seq)); | ||
86 | 95 | ||
87 | a = avenrun[0] + (FIXED_1/200); | ||
88 | b = avenrun[1] + (FIXED_1/200); | ||
89 | c = avenrun[2] + (FIXED_1/200); | ||
90 | len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", | 96 | len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", |
91 | LOAD_INT(a), LOAD_FRAC(a), | 97 | LOAD_INT(a), LOAD_FRAC(a), |
92 | LOAD_INT(b), LOAD_FRAC(b), | 98 | LOAD_INT(b), LOAD_FRAC(b), |
@@ -216,7 +222,7 @@ static int meminfo_read_proc(char *page, char **start, off_t off, | |||
216 | #undef K | 222 | #undef K |
217 | } | 223 | } |
218 | 224 | ||
219 | extern struct seq_operations fragmentation_op; | 225 | extern const struct seq_operations fragmentation_op; |
220 | static int fragmentation_open(struct inode *inode, struct file *file) | 226 | static int fragmentation_open(struct inode *inode, struct file *file) |
221 | { | 227 | { |
222 | (void)inode; | 228 | (void)inode; |
@@ -230,7 +236,7 @@ static const struct file_operations fragmentation_file_operations = { | |||
230 | .release = seq_release, | 236 | .release = seq_release, |
231 | }; | 237 | }; |
232 | 238 | ||
233 | extern struct seq_operations pagetypeinfo_op; | 239 | extern const struct seq_operations pagetypeinfo_op; |
234 | static int pagetypeinfo_open(struct inode *inode, struct file *file) | 240 | static int pagetypeinfo_open(struct inode *inode, struct file *file) |
235 | { | 241 | { |
236 | return seq_open(file, &pagetypeinfo_op); | 242 | return seq_open(file, &pagetypeinfo_op); |
@@ -243,7 +249,7 @@ static const struct file_operations pagetypeinfo_file_ops = { | |||
243 | .release = seq_release, | 249 | .release = seq_release, |
244 | }; | 250 | }; |
245 | 251 | ||
246 | extern struct seq_operations zoneinfo_op; | 252 | extern const struct seq_operations zoneinfo_op; |
247 | static int zoneinfo_open(struct inode *inode, struct file *file) | 253 | static int zoneinfo_open(struct inode *inode, struct file *file) |
248 | { | 254 | { |
249 | return seq_open(file, &zoneinfo_op); | 255 | return seq_open(file, &zoneinfo_op); |
@@ -268,7 +274,7 @@ static int version_read_proc(char *page, char **start, off_t off, | |||
268 | return proc_calc_metrics(page, start, off, count, eof, len); | 274 | return proc_calc_metrics(page, start, off, count, eof, len); |
269 | } | 275 | } |
270 | 276 | ||
271 | extern struct seq_operations cpuinfo_op; | 277 | extern const struct seq_operations cpuinfo_op; |
272 | static int cpuinfo_open(struct inode *inode, struct file *file) | 278 | static int cpuinfo_open(struct inode *inode, struct file *file) |
273 | { | 279 | { |
274 | return seq_open(file, &cpuinfo_op); | 280 | return seq_open(file, &cpuinfo_op); |
@@ -321,7 +327,7 @@ static void devinfo_stop(struct seq_file *f, void *v) | |||
321 | /* Nothing to do */ | 327 | /* Nothing to do */ |
322 | } | 328 | } |
323 | 329 | ||
324 | static struct seq_operations devinfo_ops = { | 330 | static const struct seq_operations devinfo_ops = { |
325 | .start = devinfo_start, | 331 | .start = devinfo_start, |
326 | .next = devinfo_next, | 332 | .next = devinfo_next, |
327 | .stop = devinfo_stop, | 333 | .stop = devinfo_stop, |
@@ -340,7 +346,7 @@ static const struct file_operations proc_devinfo_operations = { | |||
340 | .release = seq_release, | 346 | .release = seq_release, |
341 | }; | 347 | }; |
342 | 348 | ||
343 | extern struct seq_operations vmstat_op; | 349 | extern const struct seq_operations vmstat_op; |
344 | static int vmstat_open(struct inode *inode, struct file *file) | 350 | static int vmstat_open(struct inode *inode, struct file *file) |
345 | { | 351 | { |
346 | return seq_open(file, &vmstat_op); | 352 | return seq_open(file, &vmstat_op); |
@@ -371,7 +377,7 @@ static int stram_read_proc(char *page, char **start, off_t off, | |||
371 | #endif | 377 | #endif |
372 | 378 | ||
373 | #ifdef CONFIG_BLOCK | 379 | #ifdef CONFIG_BLOCK |
374 | extern struct seq_operations partitions_op; | 380 | extern const struct seq_operations partitions_op; |
375 | static int partitions_open(struct inode *inode, struct file *file) | 381 | static int partitions_open(struct inode *inode, struct file *file) |
376 | { | 382 | { |
377 | return seq_open(file, &partitions_op); | 383 | return seq_open(file, &partitions_op); |
@@ -383,7 +389,7 @@ static const struct file_operations proc_partitions_operations = { | |||
383 | .release = seq_release, | 389 | .release = seq_release, |
384 | }; | 390 | }; |
385 | 391 | ||
386 | extern struct seq_operations diskstats_op; | 392 | extern const struct seq_operations diskstats_op; |
387 | static int diskstats_open(struct inode *inode, struct file *file) | 393 | static int diskstats_open(struct inode *inode, struct file *file) |
388 | { | 394 | { |
389 | return seq_open(file, &diskstats_op); | 395 | return seq_open(file, &diskstats_op); |
@@ -397,7 +403,7 @@ static const struct file_operations proc_diskstats_operations = { | |||
397 | #endif | 403 | #endif |
398 | 404 | ||
399 | #ifdef CONFIG_MODULES | 405 | #ifdef CONFIG_MODULES |
400 | extern struct seq_operations modules_op; | 406 | extern const struct seq_operations modules_op; |
401 | static int modules_open(struct inode *inode, struct file *file) | 407 | static int modules_open(struct inode *inode, struct file *file) |
402 | { | 408 | { |
403 | return seq_open(file, &modules_op); | 409 | return seq_open(file, &modules_op); |
@@ -424,7 +430,7 @@ static const struct file_operations proc_slabinfo_operations = { | |||
424 | }; | 430 | }; |
425 | 431 | ||
426 | #ifdef CONFIG_DEBUG_SLAB_LEAK | 432 | #ifdef CONFIG_DEBUG_SLAB_LEAK |
427 | extern struct seq_operations slabstats_op; | 433 | extern const struct seq_operations slabstats_op; |
428 | static int slabstats_open(struct inode *inode, struct file *file) | 434 | static int slabstats_open(struct inode *inode, struct file *file) |
429 | { | 435 | { |
430 | unsigned long *n = kzalloc(PAGE_SIZE, GFP_KERNEL); | 436 | unsigned long *n = kzalloc(PAGE_SIZE, GFP_KERNEL); |
@@ -598,8 +604,7 @@ static void int_seq_stop(struct seq_file *f, void *v) | |||
598 | } | 604 | } |
599 | 605 | ||
600 | 606 | ||
601 | extern int show_interrupts(struct seq_file *f, void *v); /* In arch code */ | 607 | static const struct seq_operations int_seq_ops = { |
602 | static struct seq_operations int_seq_ops = { | ||
603 | .start = int_seq_start, | 608 | .start = int_seq_start, |
604 | .next = int_seq_next, | 609 | .next = int_seq_next, |
605 | .stop = int_seq_stop, | 610 | .stop = int_seq_stop, |
@@ -675,6 +680,137 @@ static const struct file_operations proc_sysrq_trigger_operations = { | |||
675 | }; | 680 | }; |
676 | #endif | 681 | #endif |
677 | 682 | ||
683 | #ifdef CONFIG_PROC_PAGE_MONITOR | ||
684 | #define KPMSIZE sizeof(u64) | ||
685 | #define KPMMASK (KPMSIZE - 1) | ||
686 | /* /proc/kpagecount - an array exposing page counts | ||
687 | * | ||
688 | * Each entry is a u64 representing the corresponding | ||
689 | * physical page count. | ||
690 | */ | ||
691 | static ssize_t kpagecount_read(struct file *file, char __user *buf, | ||
692 | size_t count, loff_t *ppos) | ||
693 | { | ||
694 | u64 __user *out = (u64 __user *)buf; | ||
695 | struct page *ppage; | ||
696 | unsigned long src = *ppos; | ||
697 | unsigned long pfn; | ||
698 | ssize_t ret = 0; | ||
699 | u64 pcount; | ||
700 | |||
701 | pfn = src / KPMSIZE; | ||
702 | count = min_t(size_t, count, (max_pfn * KPMSIZE) - src); | ||
703 | if (src & KPMMASK || count & KPMMASK) | ||
704 | return -EIO; | ||
705 | |||
706 | while (count > 0) { | ||
707 | ppage = NULL; | ||
708 | if (pfn_valid(pfn)) | ||
709 | ppage = pfn_to_page(pfn); | ||
710 | pfn++; | ||
711 | if (!ppage) | ||
712 | pcount = 0; | ||
713 | else | ||
714 | pcount = atomic_read(&ppage->_count); | ||
715 | |||
716 | if (put_user(pcount, out++)) { | ||
717 | ret = -EFAULT; | ||
718 | break; | ||
719 | } | ||
720 | |||
721 | count -= KPMSIZE; | ||
722 | } | ||
723 | |||
724 | *ppos += (char __user *)out - buf; | ||
725 | if (!ret) | ||
726 | ret = (char __user *)out - buf; | ||
727 | return ret; | ||
728 | } | ||
729 | |||
730 | static struct file_operations proc_kpagecount_operations = { | ||
731 | .llseek = mem_lseek, | ||
732 | .read = kpagecount_read, | ||
733 | }; | ||
734 | |||
735 | /* /proc/kpageflags - an array exposing page flags | ||
736 | * | ||
737 | * Each entry is a u64 representing the corresponding | ||
738 | * physical page flags. | ||
739 | */ | ||
740 | |||
741 | /* These macros are used to decouple internal flags from exported ones */ | ||
742 | |||
743 | #define KPF_LOCKED 0 | ||
744 | #define KPF_ERROR 1 | ||
745 | #define KPF_REFERENCED 2 | ||
746 | #define KPF_UPTODATE 3 | ||
747 | #define KPF_DIRTY 4 | ||
748 | #define KPF_LRU 5 | ||
749 | #define KPF_ACTIVE 6 | ||
750 | #define KPF_SLAB 7 | ||
751 | #define KPF_WRITEBACK 8 | ||
752 | #define KPF_RECLAIM 9 | ||
753 | #define KPF_BUDDY 10 | ||
754 | |||
755 | #define kpf_copy_bit(flags, srcpos, dstpos) (((flags >> srcpos) & 1) << dstpos) | ||
756 | |||
757 | static ssize_t kpageflags_read(struct file *file, char __user *buf, | ||
758 | size_t count, loff_t *ppos) | ||
759 | { | ||
760 | u64 __user *out = (u64 __user *)buf; | ||
761 | struct page *ppage; | ||
762 | unsigned long src = *ppos; | ||
763 | unsigned long pfn; | ||
764 | ssize_t ret = 0; | ||
765 | u64 kflags, uflags; | ||
766 | |||
767 | pfn = src / KPMSIZE; | ||
768 | count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); | ||
769 | if (src & KPMMASK || count & KPMMASK) | ||
770 | return -EIO; | ||
771 | |||
772 | while (count > 0) { | ||
773 | ppage = NULL; | ||
774 | if (pfn_valid(pfn)) | ||
775 | ppage = pfn_to_page(pfn); | ||
776 | pfn++; | ||
777 | if (!ppage) | ||
778 | kflags = 0; | ||
779 | else | ||
780 | kflags = ppage->flags; | ||
781 | |||
782 | uflags = kpf_copy_bit(KPF_LOCKED, PG_locked, kflags) | | ||
783 | kpf_copy_bit(kflags, KPF_ERROR, PG_error) | | ||
784 | kpf_copy_bit(kflags, KPF_REFERENCED, PG_referenced) | | ||
785 | kpf_copy_bit(kflags, KPF_UPTODATE, PG_uptodate) | | ||
786 | kpf_copy_bit(kflags, KPF_DIRTY, PG_dirty) | | ||
787 | kpf_copy_bit(kflags, KPF_LRU, PG_lru) | | ||
788 | kpf_copy_bit(kflags, KPF_ACTIVE, PG_active) | | ||
789 | kpf_copy_bit(kflags, KPF_SLAB, PG_slab) | | ||
790 | kpf_copy_bit(kflags, KPF_WRITEBACK, PG_writeback) | | ||
791 | kpf_copy_bit(kflags, KPF_RECLAIM, PG_reclaim) | | ||
792 | kpf_copy_bit(kflags, KPF_BUDDY, PG_buddy); | ||
793 | |||
794 | if (put_user(uflags, out++)) { | ||
795 | ret = -EFAULT; | ||
796 | break; | ||
797 | } | ||
798 | |||
799 | count -= KPMSIZE; | ||
800 | } | ||
801 | |||
802 | *ppos += (char __user *)out - buf; | ||
803 | if (!ret) | ||
804 | ret = (char __user *)out - buf; | ||
805 | return ret; | ||
806 | } | ||
807 | |||
808 | static struct file_operations proc_kpageflags_operations = { | ||
809 | .llseek = mem_lseek, | ||
810 | .read = kpageflags_read, | ||
811 | }; | ||
812 | #endif /* CONFIG_PROC_PAGE_MONITOR */ | ||
813 | |||
678 | struct proc_dir_entry *proc_root_kcore; | 814 | struct proc_dir_entry *proc_root_kcore; |
679 | 815 | ||
680 | void create_seq_entry(char *name, mode_t mode, const struct file_operations *f) | 816 | void create_seq_entry(char *name, mode_t mode, const struct file_operations *f) |
@@ -755,6 +891,10 @@ void __init proc_misc_init(void) | |||
755 | (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE; | 891 | (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE; |
756 | } | 892 | } |
757 | #endif | 893 | #endif |
894 | #ifdef CONFIG_PROC_PAGE_MONITOR | ||
895 | create_seq_entry("kpagecount", S_IRUSR, &proc_kpagecount_operations); | ||
896 | create_seq_entry("kpageflags", S_IRUSR, &proc_kpageflags_operations); | ||
897 | #endif | ||
758 | #ifdef CONFIG_PROC_VMCORE | 898 | #ifdef CONFIG_PROC_VMCORE |
759 | proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL); | 899 | proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL); |
760 | if (proc_vmcore) | 900 | if (proc_vmcore) |