16d80e53fSAlexey Dobriyan #include <linux/bootmem.h> 26d80e53fSAlexey Dobriyan #include <linux/compiler.h> 36d80e53fSAlexey Dobriyan #include <linux/fs.h> 46d80e53fSAlexey Dobriyan #include <linux/init.h> 5*9a840895SHugh Dickins #include <linux/ksm.h> 66d80e53fSAlexey Dobriyan #include <linux/mm.h> 76d80e53fSAlexey Dobriyan #include <linux/mmzone.h> 86d80e53fSAlexey Dobriyan #include <linux/proc_fs.h> 96d80e53fSAlexey Dobriyan #include <linux/seq_file.h> 1020a0307cSWu Fengguang #include <linux/hugetlb.h> 116d80e53fSAlexey Dobriyan #include <asm/uaccess.h> 126d80e53fSAlexey Dobriyan #include "internal.h" 136d80e53fSAlexey Dobriyan 146d80e53fSAlexey Dobriyan #define KPMSIZE sizeof(u64) 156d80e53fSAlexey Dobriyan #define KPMMASK (KPMSIZE - 1) 16ed7ce0f1SWu Fengguang 176d80e53fSAlexey Dobriyan /* /proc/kpagecount - an array exposing page counts 186d80e53fSAlexey Dobriyan * 196d80e53fSAlexey Dobriyan * Each entry is a u64 representing the corresponding 206d80e53fSAlexey Dobriyan * physical page count. 216d80e53fSAlexey Dobriyan */ 226d80e53fSAlexey Dobriyan static ssize_t kpagecount_read(struct file *file, char __user *buf, 236d80e53fSAlexey Dobriyan size_t count, loff_t *ppos) 246d80e53fSAlexey Dobriyan { 256d80e53fSAlexey Dobriyan u64 __user *out = (u64 __user *)buf; 266d80e53fSAlexey Dobriyan struct page *ppage; 276d80e53fSAlexey Dobriyan unsigned long src = *ppos; 286d80e53fSAlexey Dobriyan unsigned long pfn; 296d80e53fSAlexey Dobriyan ssize_t ret = 0; 306d80e53fSAlexey Dobriyan u64 pcount; 316d80e53fSAlexey Dobriyan 326d80e53fSAlexey Dobriyan pfn = src / KPMSIZE; 336d80e53fSAlexey Dobriyan count = min_t(size_t, count, (max_pfn * KPMSIZE) - src); 346d80e53fSAlexey Dobriyan if (src & KPMMASK || count & KPMMASK) 356d80e53fSAlexey Dobriyan return -EINVAL; 366d80e53fSAlexey Dobriyan 376d80e53fSAlexey Dobriyan while (count > 0) { 386d80e53fSAlexey Dobriyan if (pfn_valid(pfn)) 396d80e53fSAlexey Dobriyan ppage = pfn_to_page(pfn); 40ed7ce0f1SWu Fengguang else 41ed7ce0f1SWu Fengguang ppage = NULL; 426d80e53fSAlexey Dobriyan if (!ppage) 436d80e53fSAlexey Dobriyan pcount = 0; 446d80e53fSAlexey Dobriyan else 456d80e53fSAlexey Dobriyan pcount = page_mapcount(ppage); 466d80e53fSAlexey Dobriyan 47ed7ce0f1SWu Fengguang if (put_user(pcount, out)) { 486d80e53fSAlexey Dobriyan ret = -EFAULT; 496d80e53fSAlexey Dobriyan break; 506d80e53fSAlexey Dobriyan } 516d80e53fSAlexey Dobriyan 52ed7ce0f1SWu Fengguang pfn++; 53ed7ce0f1SWu Fengguang out++; 546d80e53fSAlexey Dobriyan count -= KPMSIZE; 556d80e53fSAlexey Dobriyan } 566d80e53fSAlexey Dobriyan 576d80e53fSAlexey Dobriyan *ppos += (char __user *)out - buf; 586d80e53fSAlexey Dobriyan if (!ret) 596d80e53fSAlexey Dobriyan ret = (char __user *)out - buf; 606d80e53fSAlexey Dobriyan return ret; 616d80e53fSAlexey Dobriyan } 626d80e53fSAlexey Dobriyan 636d80e53fSAlexey Dobriyan static const struct file_operations proc_kpagecount_operations = { 646d80e53fSAlexey Dobriyan .llseek = mem_lseek, 656d80e53fSAlexey Dobriyan .read = kpagecount_read, 666d80e53fSAlexey Dobriyan }; 676d80e53fSAlexey Dobriyan 686d80e53fSAlexey Dobriyan /* /proc/kpageflags - an array exposing page flags 696d80e53fSAlexey Dobriyan * 706d80e53fSAlexey Dobriyan * Each entry is a u64 representing the corresponding 716d80e53fSAlexey Dobriyan * physical page flags. 726d80e53fSAlexey Dobriyan */ 736d80e53fSAlexey Dobriyan 746d80e53fSAlexey Dobriyan /* These macros are used to decouple internal flags from exported ones */ 756d80e53fSAlexey Dobriyan 766d80e53fSAlexey Dobriyan #define KPF_LOCKED 0 776d80e53fSAlexey Dobriyan #define KPF_ERROR 1 786d80e53fSAlexey Dobriyan #define KPF_REFERENCED 2 796d80e53fSAlexey Dobriyan #define KPF_UPTODATE 3 806d80e53fSAlexey Dobriyan #define KPF_DIRTY 4 816d80e53fSAlexey Dobriyan #define KPF_LRU 5 826d80e53fSAlexey Dobriyan #define KPF_ACTIVE 6 836d80e53fSAlexey Dobriyan #define KPF_SLAB 7 846d80e53fSAlexey Dobriyan #define KPF_WRITEBACK 8 856d80e53fSAlexey Dobriyan #define KPF_RECLAIM 9 866d80e53fSAlexey Dobriyan #define KPF_BUDDY 10 876d80e53fSAlexey Dobriyan 8817797549SWu Fengguang /* 11-20: new additions in 2.6.31 */ 8917797549SWu Fengguang #define KPF_MMAP 11 9017797549SWu Fengguang #define KPF_ANON 12 9117797549SWu Fengguang #define KPF_SWAPCACHE 13 9217797549SWu Fengguang #define KPF_SWAPBACKED 14 9317797549SWu Fengguang #define KPF_COMPOUND_HEAD 15 9417797549SWu Fengguang #define KPF_COMPOUND_TAIL 16 9517797549SWu Fengguang #define KPF_HUGE 17 9617797549SWu Fengguang #define KPF_UNEVICTABLE 18 9717797549SWu Fengguang #define KPF_NOPAGE 20 9817797549SWu Fengguang 99*9a840895SHugh Dickins #define KPF_KSM 21 100*9a840895SHugh Dickins 10117797549SWu Fengguang /* kernel hacking assistances 10217797549SWu Fengguang * WARNING: subject to change, never rely on them! 10317797549SWu Fengguang */ 10417797549SWu Fengguang #define KPF_RESERVED 32 10517797549SWu Fengguang #define KPF_MLOCKED 33 10617797549SWu Fengguang #define KPF_MAPPEDTODISK 34 10717797549SWu Fengguang #define KPF_PRIVATE 35 10817797549SWu Fengguang #define KPF_PRIVATE_2 36 10917797549SWu Fengguang #define KPF_OWNER_PRIVATE 37 11017797549SWu Fengguang #define KPF_ARCH 38 11117797549SWu Fengguang #define KPF_UNCACHED 39 11217797549SWu Fengguang 11317797549SWu Fengguang static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit) 11417797549SWu Fengguang { 11517797549SWu Fengguang return ((kflags >> kbit) & 1) << ubit; 11617797549SWu Fengguang } 11717797549SWu Fengguang 11817797549SWu Fengguang static u64 get_uflags(struct page *page) 11917797549SWu Fengguang { 12017797549SWu Fengguang u64 k; 12117797549SWu Fengguang u64 u; 12217797549SWu Fengguang 12317797549SWu Fengguang /* 12417797549SWu Fengguang * pseudo flag: KPF_NOPAGE 12517797549SWu Fengguang * it differentiates a memory hole from a page with no flags 12617797549SWu Fengguang */ 12717797549SWu Fengguang if (!page) 12817797549SWu Fengguang return 1 << KPF_NOPAGE; 12917797549SWu Fengguang 13017797549SWu Fengguang k = page->flags; 13117797549SWu Fengguang u = 0; 13217797549SWu Fengguang 13317797549SWu Fengguang /* 13417797549SWu Fengguang * pseudo flags for the well known (anonymous) memory mapped pages 13517797549SWu Fengguang * 13617797549SWu Fengguang * Note that page->_mapcount is overloaded in SLOB/SLUB/SLQB, so the 13717797549SWu Fengguang * simple test in page_mapped() is not enough. 13817797549SWu Fengguang */ 13917797549SWu Fengguang if (!PageSlab(page) && page_mapped(page)) 14017797549SWu Fengguang u |= 1 << KPF_MMAP; 14117797549SWu Fengguang if (PageAnon(page)) 14217797549SWu Fengguang u |= 1 << KPF_ANON; 143*9a840895SHugh Dickins if (PageKsm(page)) 144*9a840895SHugh Dickins u |= 1 << KPF_KSM; 14517797549SWu Fengguang 14617797549SWu Fengguang /* 14717797549SWu Fengguang * compound pages: export both head/tail info 14817797549SWu Fengguang * they together define a compound page's start/end pos and order 14917797549SWu Fengguang */ 15017797549SWu Fengguang if (PageHead(page)) 15117797549SWu Fengguang u |= 1 << KPF_COMPOUND_HEAD; 15217797549SWu Fengguang if (PageTail(page)) 15317797549SWu Fengguang u |= 1 << KPF_COMPOUND_TAIL; 15417797549SWu Fengguang if (PageHuge(page)) 15517797549SWu Fengguang u |= 1 << KPF_HUGE; 15617797549SWu Fengguang 15717797549SWu Fengguang u |= kpf_copy_bit(k, KPF_LOCKED, PG_locked); 15817797549SWu Fengguang 15917797549SWu Fengguang /* 16017797549SWu Fengguang * Caveats on high order pages: 16117797549SWu Fengguang * PG_buddy will only be set on the head page; SLUB/SLQB do the same 16217797549SWu Fengguang * for PG_slab; SLOB won't set PG_slab at all on compound pages. 16317797549SWu Fengguang */ 16417797549SWu Fengguang u |= kpf_copy_bit(k, KPF_SLAB, PG_slab); 16517797549SWu Fengguang u |= kpf_copy_bit(k, KPF_BUDDY, PG_buddy); 16617797549SWu Fengguang 16717797549SWu Fengguang u |= kpf_copy_bit(k, KPF_ERROR, PG_error); 16817797549SWu Fengguang u |= kpf_copy_bit(k, KPF_DIRTY, PG_dirty); 16917797549SWu Fengguang u |= kpf_copy_bit(k, KPF_UPTODATE, PG_uptodate); 17017797549SWu Fengguang u |= kpf_copy_bit(k, KPF_WRITEBACK, PG_writeback); 17117797549SWu Fengguang 17217797549SWu Fengguang u |= kpf_copy_bit(k, KPF_LRU, PG_lru); 17317797549SWu Fengguang u |= kpf_copy_bit(k, KPF_REFERENCED, PG_referenced); 17417797549SWu Fengguang u |= kpf_copy_bit(k, KPF_ACTIVE, PG_active); 17517797549SWu Fengguang u |= kpf_copy_bit(k, KPF_RECLAIM, PG_reclaim); 17617797549SWu Fengguang 17717797549SWu Fengguang u |= kpf_copy_bit(k, KPF_SWAPCACHE, PG_swapcache); 17817797549SWu Fengguang u |= kpf_copy_bit(k, KPF_SWAPBACKED, PG_swapbacked); 17917797549SWu Fengguang 18017797549SWu Fengguang u |= kpf_copy_bit(k, KPF_UNEVICTABLE, PG_unevictable); 18117797549SWu Fengguang u |= kpf_copy_bit(k, KPF_MLOCKED, PG_mlocked); 18217797549SWu Fengguang 18317797549SWu Fengguang #ifdef CONFIG_IA64_UNCACHED_ALLOCATOR 18417797549SWu Fengguang u |= kpf_copy_bit(k, KPF_UNCACHED, PG_uncached); 18517797549SWu Fengguang #endif 18617797549SWu Fengguang 18717797549SWu Fengguang u |= kpf_copy_bit(k, KPF_RESERVED, PG_reserved); 18817797549SWu Fengguang u |= kpf_copy_bit(k, KPF_MAPPEDTODISK, PG_mappedtodisk); 18917797549SWu Fengguang u |= kpf_copy_bit(k, KPF_PRIVATE, PG_private); 19017797549SWu Fengguang u |= kpf_copy_bit(k, KPF_PRIVATE_2, PG_private_2); 19117797549SWu Fengguang u |= kpf_copy_bit(k, KPF_OWNER_PRIVATE, PG_owner_priv_1); 19217797549SWu Fengguang u |= kpf_copy_bit(k, KPF_ARCH, PG_arch_1); 19317797549SWu Fengguang 19417797549SWu Fengguang return u; 19517797549SWu Fengguang }; 1966d80e53fSAlexey Dobriyan 1976d80e53fSAlexey Dobriyan static ssize_t kpageflags_read(struct file *file, char __user *buf, 1986d80e53fSAlexey Dobriyan size_t count, loff_t *ppos) 1996d80e53fSAlexey Dobriyan { 2006d80e53fSAlexey Dobriyan u64 __user *out = (u64 __user *)buf; 2016d80e53fSAlexey Dobriyan struct page *ppage; 2026d80e53fSAlexey Dobriyan unsigned long src = *ppos; 2036d80e53fSAlexey Dobriyan unsigned long pfn; 2046d80e53fSAlexey Dobriyan ssize_t ret = 0; 2056d80e53fSAlexey Dobriyan 2066d80e53fSAlexey Dobriyan pfn = src / KPMSIZE; 2076d80e53fSAlexey Dobriyan count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); 2086d80e53fSAlexey Dobriyan if (src & KPMMASK || count & KPMMASK) 2096d80e53fSAlexey Dobriyan return -EINVAL; 2106d80e53fSAlexey Dobriyan 2116d80e53fSAlexey Dobriyan while (count > 0) { 2126d80e53fSAlexey Dobriyan if (pfn_valid(pfn)) 2136d80e53fSAlexey Dobriyan ppage = pfn_to_page(pfn); 214ed7ce0f1SWu Fengguang else 215ed7ce0f1SWu Fengguang ppage = NULL; 2166d80e53fSAlexey Dobriyan 21717797549SWu Fengguang if (put_user(get_uflags(ppage), out)) { 2186d80e53fSAlexey Dobriyan ret = -EFAULT; 2196d80e53fSAlexey Dobriyan break; 2206d80e53fSAlexey Dobriyan } 2216d80e53fSAlexey Dobriyan 222ed7ce0f1SWu Fengguang pfn++; 223ed7ce0f1SWu Fengguang out++; 2246d80e53fSAlexey Dobriyan count -= KPMSIZE; 2256d80e53fSAlexey Dobriyan } 2266d80e53fSAlexey Dobriyan 2276d80e53fSAlexey Dobriyan *ppos += (char __user *)out - buf; 2286d80e53fSAlexey Dobriyan if (!ret) 2296d80e53fSAlexey Dobriyan ret = (char __user *)out - buf; 2306d80e53fSAlexey Dobriyan return ret; 2316d80e53fSAlexey Dobriyan } 2326d80e53fSAlexey Dobriyan 2336d80e53fSAlexey Dobriyan static const struct file_operations proc_kpageflags_operations = { 2346d80e53fSAlexey Dobriyan .llseek = mem_lseek, 2356d80e53fSAlexey Dobriyan .read = kpageflags_read, 2366d80e53fSAlexey Dobriyan }; 2376d80e53fSAlexey Dobriyan 2386d80e53fSAlexey Dobriyan static int __init proc_page_init(void) 2396d80e53fSAlexey Dobriyan { 2406d80e53fSAlexey Dobriyan proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations); 2416d80e53fSAlexey Dobriyan proc_create("kpageflags", S_IRUSR, NULL, &proc_kpageflags_operations); 2426d80e53fSAlexey Dobriyan return 0; 2436d80e53fSAlexey Dobriyan } 2446d80e53fSAlexey Dobriyan module_init(proc_page_init); 245