Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : #include <linux/memblock.h> 3 : : #include <linux/compiler.h> 4 : : #include <linux/fs.h> 5 : : #include <linux/init.h> 6 : : #include <linux/ksm.h> 7 : : #include <linux/mm.h> 8 : : #include <linux/mmzone.h> 9 : : #include <linux/huge_mm.h> 10 : : #include <linux/proc_fs.h> 11 : : #include <linux/seq_file.h> 12 : : #include <linux/hugetlb.h> 13 : : #include <linux/memcontrol.h> 14 : : #include <linux/mmu_notifier.h> 15 : : #include <linux/page_idle.h> 16 : : #include <linux/kernel-page-flags.h> 17 : : #include <linux/uaccess.h> 18 : : #include "internal.h" 19 : : 20 : : #define KPMSIZE sizeof(u64) 21 : : #define KPMMASK (KPMSIZE - 1) 22 : : #define KPMBITS (KPMSIZE * BITS_PER_BYTE) 23 : : 24 : : /* /proc/kpagecount - an array exposing page counts 25 : : * 26 : : * Each entry is a u64 representing the corresponding 27 : : * physical page count. 28 : : */ 29 : 0 : static ssize_t kpagecount_read(struct file *file, char __user *buf, 30 : : size_t count, loff_t *ppos) 31 : : { 32 : : u64 __user *out = (u64 __user *)buf; 33 : : struct page *ppage; 34 : 0 : unsigned long src = *ppos; 35 : : unsigned long pfn; 36 : : ssize_t ret = 0; 37 : : u64 pcount; 38 : : 39 : 0 : pfn = src / KPMSIZE; 40 : 0 : count = min_t(size_t, count, (max_pfn * KPMSIZE) - src); 41 : 0 : if (src & KPMMASK || count & KPMMASK) 42 : : return -EINVAL; 43 : : 44 : 0 : while (count > 0) { 45 : : /* 46 : : * TODO: ZONE_DEVICE support requires to identify 47 : : * memmaps that were actually initialized. 48 : : */ 49 : 0 : ppage = pfn_to_online_page(pfn); 50 : : 51 : 0 : if (!ppage || PageSlab(ppage) || page_has_type(ppage)) 52 : : pcount = 0; 53 : : else 54 : 0 : pcount = page_mapcount(ppage); 55 : : 56 : 0 : if (put_user(pcount, out)) { 57 : : ret = -EFAULT; 58 : : break; 59 : : } 60 : : 61 : 0 : pfn++; 62 : 0 : out++; 63 : 0 : count -= KPMSIZE; 64 : : 65 : 0 : cond_resched(); 66 : : } 67 : : 68 : 0 : *ppos += (char __user *)out - buf; 69 : 0 : if (!ret) 70 : : ret = (char __user *)out - buf; 71 : 0 : return ret; 72 : : } 73 : : 74 : : static const struct file_operations proc_kpagecount_operations = { 75 : : .llseek = mem_lseek, 76 : : .read = kpagecount_read, 77 : : }; 78 : : 79 : : /* /proc/kpageflags - an array exposing page flags 80 : : * 81 : : * Each entry is a u64 representing the corresponding 82 : : * physical page flags. 83 : : */ 84 : : 85 : : static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit) 86 : : { 87 : 0 : return ((kflags >> kbit) & 1) << ubit; 88 : : } 89 : : 90 : 0 : u64 stable_page_flags(struct page *page) 91 : : { 92 : : u64 k; 93 : : u64 u; 94 : : 95 : : /* 96 : : * pseudo flag: KPF_NOPAGE 97 : : * it differentiates a memory hole from a page with no flags 98 : : */ 99 : 0 : if (!page) 100 : : return 1 << KPF_NOPAGE; 101 : : 102 : 0 : k = page->flags; 103 : : u = 0; 104 : : 105 : : /* 106 : : * pseudo flags for the well known (anonymous) memory mapped pages 107 : : * 108 : : * Note that page->_mapcount is overloaded in SLOB/SLUB/SLQB, so the 109 : : * simple test in page_mapped() is not enough. 110 : : */ 111 : 0 : if (!PageSlab(page) && page_mapped(page)) 112 : : u |= 1 << KPF_MMAP; 113 : 0 : if (PageAnon(page)) 114 : 0 : u |= 1 << KPF_ANON; 115 : : if (PageKsm(page)) 116 : : u |= 1 << KPF_KSM; 117 : : 118 : : /* 119 : : * compound pages: export both head/tail info 120 : : * they together define a compound page's start/end pos and order 121 : : */ 122 : 0 : if (PageHead(page)) 123 : 0 : u |= 1 << KPF_COMPOUND_HEAD; 124 : 0 : if (PageTail(page)) 125 : 0 : u |= 1 << KPF_COMPOUND_TAIL; 126 : : if (PageHuge(page)) 127 : : u |= 1 << KPF_HUGE; 128 : : /* 129 : : * PageTransCompound can be true for non-huge compound pages (slab 130 : : * pages or pages allocated by drivers with __GFP_COMP) because it 131 : : * just checks PG_head/PG_tail, so we need to check PageLRU/PageAnon 132 : : * to make sure a given page is a thp, not a non-huge compound page. 133 : : */ 134 : : else if (PageTransCompound(page)) { 135 : : struct page *head = compound_head(page); 136 : : 137 : : if (PageLRU(head) || PageAnon(head)) 138 : : u |= 1 << KPF_THP; 139 : : else if (is_huge_zero_page(head)) { 140 : : u |= 1 << KPF_ZERO_PAGE; 141 : : u |= 1 << KPF_THP; 142 : : } 143 : 0 : } else if (is_zero_pfn(page_to_pfn(page))) 144 : 0 : u |= 1 << KPF_ZERO_PAGE; 145 : : 146 : : 147 : : /* 148 : : * Caveats on high order pages: page->_refcount will only be set 149 : : * -1 on the head page; SLUB/SLQB do the same for PG_slab; 150 : : * SLOB won't set PG_slab at all on compound pages. 151 : : */ 152 : 0 : if (PageBuddy(page)) 153 : 0 : u |= 1 << KPF_BUDDY; 154 : 0 : else if (page_count(page) == 0 && is_free_buddy_page(page)) 155 : 0 : u |= 1 << KPF_BUDDY; 156 : : 157 : 0 : if (PageOffline(page)) 158 : 0 : u |= 1 << KPF_OFFLINE; 159 : 0 : if (PageTable(page)) 160 : 0 : u |= 1 << KPF_PGTABLE; 161 : : 162 : : if (page_is_idle(page)) 163 : : u |= 1 << KPF_IDLE; 164 : : 165 : 0 : u |= kpf_copy_bit(k, KPF_LOCKED, PG_locked); 166 : : 167 : 0 : u |= kpf_copy_bit(k, KPF_SLAB, PG_slab); 168 : 0 : if (PageTail(page) && PageSlab(compound_head(page))) 169 : 0 : u |= 1 << KPF_SLAB; 170 : : 171 : 0 : u |= kpf_copy_bit(k, KPF_ERROR, PG_error); 172 : 0 : u |= kpf_copy_bit(k, KPF_DIRTY, PG_dirty); 173 : 0 : u |= kpf_copy_bit(k, KPF_UPTODATE, PG_uptodate); 174 : 0 : u |= kpf_copy_bit(k, KPF_WRITEBACK, PG_writeback); 175 : : 176 : 0 : u |= kpf_copy_bit(k, KPF_LRU, PG_lru); 177 : 0 : u |= kpf_copy_bit(k, KPF_REFERENCED, PG_referenced); 178 : 0 : u |= kpf_copy_bit(k, KPF_ACTIVE, PG_active); 179 : 0 : u |= kpf_copy_bit(k, KPF_RECLAIM, PG_reclaim); 180 : : 181 : 0 : if (PageSwapCache(page)) 182 : 0 : u |= 1 << KPF_SWAPCACHE; 183 : 0 : u |= kpf_copy_bit(k, KPF_SWAPBACKED, PG_swapbacked); 184 : : 185 : 0 : u |= kpf_copy_bit(k, KPF_UNEVICTABLE, PG_unevictable); 186 : 0 : u |= kpf_copy_bit(k, KPF_MLOCKED, PG_mlocked); 187 : : 188 : : #ifdef CONFIG_MEMORY_FAILURE 189 : : u |= kpf_copy_bit(k, KPF_HWPOISON, PG_hwpoison); 190 : : #endif 191 : : 192 : : #ifdef CONFIG_ARCH_USES_PG_UNCACHED 193 : : u |= kpf_copy_bit(k, KPF_UNCACHED, PG_uncached); 194 : : #endif 195 : : 196 : 0 : u |= kpf_copy_bit(k, KPF_RESERVED, PG_reserved); 197 : 0 : u |= kpf_copy_bit(k, KPF_MAPPEDTODISK, PG_mappedtodisk); 198 : 0 : u |= kpf_copy_bit(k, KPF_PRIVATE, PG_private); 199 : 0 : u |= kpf_copy_bit(k, KPF_PRIVATE_2, PG_private_2); 200 : 0 : u |= kpf_copy_bit(k, KPF_OWNER_PRIVATE, PG_owner_priv_1); 201 : 0 : u |= kpf_copy_bit(k, KPF_ARCH, PG_arch_1); 202 : : 203 : 0 : return u; 204 : : }; 205 : : 206 : 0 : static ssize_t kpageflags_read(struct file *file, char __user *buf, 207 : : size_t count, loff_t *ppos) 208 : : { 209 : : u64 __user *out = (u64 __user *)buf; 210 : : struct page *ppage; 211 : 0 : unsigned long src = *ppos; 212 : : unsigned long pfn; 213 : : ssize_t ret = 0; 214 : : 215 : 0 : pfn = src / KPMSIZE; 216 : 0 : count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); 217 : 0 : if (src & KPMMASK || count & KPMMASK) 218 : : return -EINVAL; 219 : : 220 : 0 : while (count > 0) { 221 : : /* 222 : : * TODO: ZONE_DEVICE support requires to identify 223 : : * memmaps that were actually initialized. 224 : : */ 225 : 0 : ppage = pfn_to_online_page(pfn); 226 : : 227 : 0 : if (put_user(stable_page_flags(ppage), out)) { 228 : : ret = -EFAULT; 229 : : break; 230 : : } 231 : : 232 : 0 : pfn++; 233 : 0 : out++; 234 : 0 : count -= KPMSIZE; 235 : : 236 : 0 : cond_resched(); 237 : : } 238 : : 239 : 0 : *ppos += (char __user *)out - buf; 240 : 0 : if (!ret) 241 : : ret = (char __user *)out - buf; 242 : 0 : return ret; 243 : : } 244 : : 245 : : static const struct file_operations proc_kpageflags_operations = { 246 : : .llseek = mem_lseek, 247 : : .read = kpageflags_read, 248 : : }; 249 : : 250 : : #ifdef CONFIG_MEMCG 251 : 0 : static ssize_t kpagecgroup_read(struct file *file, char __user *buf, 252 : : size_t count, loff_t *ppos) 253 : : { 254 : : u64 __user *out = (u64 __user *)buf; 255 : : struct page *ppage; 256 : 0 : unsigned long src = *ppos; 257 : : unsigned long pfn; 258 : : ssize_t ret = 0; 259 : : u64 ino; 260 : : 261 : 0 : pfn = src / KPMSIZE; 262 : 0 : count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); 263 : 0 : if (src & KPMMASK || count & KPMMASK) 264 : : return -EINVAL; 265 : : 266 : 0 : while (count > 0) { 267 : : /* 268 : : * TODO: ZONE_DEVICE support requires to identify 269 : : * memmaps that were actually initialized. 270 : : */ 271 : 0 : ppage = pfn_to_online_page(pfn); 272 : : 273 : 0 : if (ppage) 274 : 0 : ino = page_cgroup_ino(ppage); 275 : : else 276 : : ino = 0; 277 : : 278 : 0 : if (put_user(ino, out)) { 279 : : ret = -EFAULT; 280 : : break; 281 : : } 282 : : 283 : 0 : pfn++; 284 : 0 : out++; 285 : 0 : count -= KPMSIZE; 286 : : 287 : 0 : cond_resched(); 288 : : } 289 : : 290 : 0 : *ppos += (char __user *)out - buf; 291 : 0 : if (!ret) 292 : : ret = (char __user *)out - buf; 293 : 0 : return ret; 294 : : } 295 : : 296 : : static const struct file_operations proc_kpagecgroup_operations = { 297 : : .llseek = mem_lseek, 298 : : .read = kpagecgroup_read, 299 : : }; 300 : : #endif /* CONFIG_MEMCG */ 301 : : 302 : 3 : static int __init proc_page_init(void) 303 : : { 304 : 3 : proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations); 305 : 3 : proc_create("kpageflags", S_IRUSR, NULL, &proc_kpageflags_operations); 306 : : #ifdef CONFIG_MEMCG 307 : 3 : proc_create("kpagecgroup", S_IRUSR, NULL, &proc_kpagecgroup_operations); 308 : : #endif 309 : 3 : return 0; 310 : : } 311 : : fs_initcall(proc_page_init);