1 #include <linux/bootmem.h> 2 #include <linux/compiler.h> 3 #include <linux/fs.h> 4 #include <linux/init.h> 5 #include <linux/mm.h> 6 #include <linux/mmzone.h> 7 #include <linux/proc_fs.h> 8 #include <linux/seq_file.h> 9 #include <asm/uaccess.h> 10 #include "internal.h" 11 12 #define KPMSIZE sizeof(u64) 13 #define KPMMASK (KPMSIZE - 1) 14 /* /proc/kpagecount - an array exposing page counts 15 * 16 * Each entry is a u64 representing the corresponding 17 * physical page count. 18 */ 19 static ssize_t kpagecount_read(struct file *file, char __user *buf, 20 size_t count, loff_t *ppos) 21 { 22 u64 __user *out = (u64 __user *)buf; 23 struct page *ppage; 24 unsigned long src = *ppos; 25 unsigned long pfn; 26 ssize_t ret = 0; 27 u64 pcount; 28 29 pfn = src / KPMSIZE; 30 count = min_t(size_t, count, (max_pfn * KPMSIZE) - src); 31 if (src & KPMMASK || count & KPMMASK) 32 return -EINVAL; 33 34 while (count > 0) { 35 ppage = NULL; 36 if (pfn_valid(pfn)) 37 ppage = pfn_to_page(pfn); 38 pfn++; 39 if (!ppage) 40 pcount = 0; 41 else 42 pcount = page_mapcount(ppage); 43 44 if (put_user(pcount, out++)) { 45 ret = -EFAULT; 46 break; 47 } 48 49 count -= KPMSIZE; 50 } 51 52 *ppos += (char __user *)out - buf; 53 if (!ret) 54 ret = (char __user *)out - buf; 55 return ret; 56 } 57 58 static const struct file_operations proc_kpagecount_operations = { 59 .llseek = mem_lseek, 60 .read = kpagecount_read, 61 }; 62 63 /* /proc/kpageflags - an array exposing page flags 64 * 65 * Each entry is a u64 representing the corresponding 66 * physical page flags. 67 */ 68 69 /* These macros are used to decouple internal flags from exported ones */ 70 71 #define KPF_LOCKED 0 72 #define KPF_ERROR 1 73 #define KPF_REFERENCED 2 74 #define KPF_UPTODATE 3 75 #define KPF_DIRTY 4 76 #define KPF_LRU 5 77 #define KPF_ACTIVE 6 78 #define KPF_SLAB 7 79 #define KPF_WRITEBACK 8 80 #define KPF_RECLAIM 9 81 #define KPF_BUDDY 10 82 83 #define kpf_copy_bit(flags, srcpos, dstpos) (((flags >> srcpos) & 1) << dstpos) 84 85 static ssize_t kpageflags_read(struct file *file, char __user *buf, 86 size_t count, loff_t *ppos) 87 { 88 u64 __user *out = (u64 __user *)buf; 89 struct page *ppage; 90 unsigned long src = *ppos; 91 unsigned long pfn; 92 ssize_t ret = 0; 93 u64 kflags, uflags; 94 95 pfn = src / KPMSIZE; 96 count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); 97 if (src & KPMMASK || count & KPMMASK) 98 return -EINVAL; 99 100 while (count > 0) { 101 ppage = NULL; 102 if (pfn_valid(pfn)) 103 ppage = pfn_to_page(pfn); 104 pfn++; 105 if (!ppage) 106 kflags = 0; 107 else 108 kflags = ppage->flags; 109 110 uflags = kpf_copy_bit(KPF_LOCKED, PG_locked, kflags) | 111 kpf_copy_bit(kflags, KPF_ERROR, PG_error) | 112 kpf_copy_bit(kflags, KPF_REFERENCED, PG_referenced) | 113 kpf_copy_bit(kflags, KPF_UPTODATE, PG_uptodate) | 114 kpf_copy_bit(kflags, KPF_DIRTY, PG_dirty) | 115 kpf_copy_bit(kflags, KPF_LRU, PG_lru) | 116 kpf_copy_bit(kflags, KPF_ACTIVE, PG_active) | 117 kpf_copy_bit(kflags, KPF_SLAB, PG_slab) | 118 kpf_copy_bit(kflags, KPF_WRITEBACK, PG_writeback) | 119 kpf_copy_bit(kflags, KPF_RECLAIM, PG_reclaim) | 120 kpf_copy_bit(kflags, KPF_BUDDY, PG_buddy); 121 122 if (put_user(uflags, out++)) { 123 ret = -EFAULT; 124 break; 125 } 126 127 count -= KPMSIZE; 128 } 129 130 *ppos += (char __user *)out - buf; 131 if (!ret) 132 ret = (char __user *)out - buf; 133 return ret; 134 } 135 136 static const struct file_operations proc_kpageflags_operations = { 137 .llseek = mem_lseek, 138 .read = kpageflags_read, 139 }; 140 141 static int __init proc_page_init(void) 142 { 143 proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations); 144 proc_create("kpageflags", S_IRUSR, NULL, &proc_kpageflags_operations); 145 return 0; 146 } 147 module_init(proc_page_init); 148