2008-10-06 14:26:12 +04:00
|
|
|
#include <linux/bootmem.h>
|
|
|
|
#include <linux/compiler.h>
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/init.h>
|
2009-09-22 04:02:01 +04:00
|
|
|
#include <linux/ksm.h>
|
2008-10-06 14:26:12 +04:00
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/mmzone.h>
|
|
|
|
#include <linux/proc_fs.h>
|
|
|
|
#include <linux/seq_file.h>
|
mm: introduce PageHuge() for testing huge/gigantic pages
A series of patches to enhance the /proc/pagemap interface and to add a
userspace executable which can be used to present the pagemap data.
Export 10 more flags to end users (and more for kernel developers):
11. KPF_MMAP (pseudo flag) memory mapped page
12. KPF_ANON (pseudo flag) memory mapped page (anonymous)
13. KPF_SWAPCACHE page is in swap cache
14. KPF_SWAPBACKED page is swap/RAM backed
15. KPF_COMPOUND_HEAD (*)
16. KPF_COMPOUND_TAIL (*)
17. KPF_HUGE hugeTLB pages
18. KPF_UNEVICTABLE page is in the unevictable LRU list
19. KPF_HWPOISON hardware detected corruption
20. KPF_NOPAGE (pseudo flag) no page frame at the address
(*) For compound pages, exporting _both_ head/tail info enables
users to tell where a compound page starts/ends, and its order.
a simple demo of the page-types tool
# ./page-types -h
page-types [options]
-r|--raw Raw mode, for kernel developers
-a|--addr addr-spec Walk a range of pages
-b|--bits bits-spec Walk pages with specified bits
-l|--list Show page details in ranges
-L|--list-each Show page details one by one
-N|--no-summary Don't show summay info
-h|--help Show this usage message
addr-spec:
N one page at offset N (unit: pages)
N+M pages range from N to N+M-1
N,M pages range from N to M-1
N, pages range from N to end
,M pages range from 0 to M
bits-spec:
bit1,bit2 (flags & (bit1|bit2)) != 0
bit1,bit2=bit1 (flags & (bit1|bit2)) == bit1
bit1,~bit2 (flags & (bit1|bit2)) == bit1
=bit1,bit2 flags == (bit1|bit2)
bit-names:
locked error referenced uptodate
dirty lru active slab
writeback reclaim buddy mmap
anonymous swapcache swapbacked compound_head
compound_tail huge unevictable hwpoison
nopage reserved(r) mlocked(r) mappedtodisk(r)
private(r) private_2(r) owner_private(r) arch(r)
uncached(r) readahead(o) slob_free(o) slub_frozen(o)
slub_debug(o)
(r) raw mode bits (o) overloaded bits
# ./page-types
flags page-count MB symbolic-flags long-symbolic-flags
0x0000000000000000 487369 1903 _________________________________
0x0000000000000014 5 0 __R_D____________________________ referenced,dirty
0x0000000000000020 1 0 _____l___________________________ lru
0x0000000000000024 34 0 __R__l___________________________ referenced,lru
0x0000000000000028 3838 14 ___U_l___________________________ uptodate,lru
0x0001000000000028 48 0 ___U_l_______________________I___ uptodate,lru,readahead
0x000000000000002c 6478 25 __RU_l___________________________ referenced,uptodate,lru
0x000100000000002c 47 0 __RU_l_______________________I___ referenced,uptodate,lru,readahead
0x0000000000000040 8344 32 ______A__________________________ active
0x0000000000000060 1 0 _____lA__________________________ lru,active
0x0000000000000068 348 1 ___U_lA__________________________ uptodate,lru,active
0x0001000000000068 12 0 ___U_lA______________________I___ uptodate,lru,active,readahead
0x000000000000006c 988 3 __RU_lA__________________________ referenced,uptodate,lru,active
0x000100000000006c 48 0 __RU_lA______________________I___ referenced,uptodate,lru,active,readahead
0x0000000000004078 1 0 ___UDlA_______b__________________ uptodate,dirty,lru,active,swapbacked
0x000000000000407c 34 0 __RUDlA_______b__________________ referenced,uptodate,dirty,lru,active,swapbacked
0x0000000000000400 503 1 __________B______________________ buddy
0x0000000000000804 1 0 __R________M_____________________ referenced,mmap
0x0000000000000828 1029 4 ___U_l_____M_____________________ uptodate,lru,mmap
0x0001000000000828 43 0 ___U_l_____M_________________I___ uptodate,lru,mmap,readahead
0x000000000000082c 382 1 __RU_l_____M_____________________ referenced,uptodate,lru,mmap
0x000100000000082c 12 0 __RU_l_____M_________________I___ referenced,uptodate,lru,mmap,readahead
0x0000000000000868 192 0 ___U_lA____M_____________________ uptodate,lru,active,mmap
0x0001000000000868 12 0 ___U_lA____M_________________I___ uptodate,lru,active,mmap,readahead
0x000000000000086c 800 3 __RU_lA____M_____________________ referenced,uptodate,lru,active,mmap
0x000100000000086c 31 0 __RU_lA____M_________________I___ referenced,uptodate,lru,active,mmap,readahead
0x0000000000004878 2 0 ___UDlA____M__b__________________ uptodate,dirty,lru,active,mmap,swapbacked
0x0000000000001000 492 1 ____________a____________________ anonymous
0x0000000000005808 4 0 ___U_______Ma_b__________________ uptodate,mmap,anonymous,swapbacked
0x0000000000005868 2839 11 ___U_lA____Ma_b__________________ uptodate,lru,active,mmap,anonymous,swapbacked
0x000000000000586c 30 0 __RU_lA____Ma_b__________________ referenced,uptodate,lru,active,mmap,anonymous,swapbacked
total 513968 2007
# ./page-types -r
flags page-count MB symbolic-flags long-symbolic-flags
0x0000000000000000 468002 1828 _________________________________
0x0000000100000000 19102 74 _____________________r___________ reserved
0x0000000000008000 41 0 _______________H_________________ compound_head
0x0000000000010000 188 0 ________________T________________ compound_tail
0x0000000000008014 1 0 __R_D__________H_________________ referenced,dirty,compound_head
0x0000000000010014 4 0 __R_D___________T________________ referenced,dirty,compound_tail
0x0000000000000020 1 0 _____l___________________________ lru
0x0000000800000024 34 0 __R__l__________________P________ referenced,lru,private
0x0000000000000028 3794 14 ___U_l___________________________ uptodate,lru
0x0001000000000028 46 0 ___U_l_______________________I___ uptodate,lru,readahead
0x0000000400000028 44 0 ___U_l_________________d_________ uptodate,lru,mappedtodisk
0x0001000400000028 2 0 ___U_l_________________d_____I___ uptodate,lru,mappedtodisk,readahead
0x000000000000002c 6434 25 __RU_l___________________________ referenced,uptodate,lru
0x000100000000002c 47 0 __RU_l_______________________I___ referenced,uptodate,lru,readahead
0x000000040000002c 14 0 __RU_l_________________d_________ referenced,uptodate,lru,mappedtodisk
0x000000080000002c 30 0 __RU_l__________________P________ referenced,uptodate,lru,private
0x0000000800000040 8124 31 ______A_________________P________ active,private
0x0000000000000040 219 0 ______A__________________________ active
0x0000000800000060 1 0 _____lA_________________P________ lru,active,private
0x0000000000000068 322 1 ___U_lA__________________________ uptodate,lru,active
0x0001000000000068 12 0 ___U_lA______________________I___ uptodate,lru,active,readahead
0x0000000400000068 13 0 ___U_lA________________d_________ uptodate,lru,active,mappedtodisk
0x0000000800000068 12 0 ___U_lA_________________P________ uptodate,lru,active,private
0x000000000000006c 977 3 __RU_lA__________________________ referenced,uptodate,lru,active
0x000100000000006c 48 0 __RU_lA______________________I___ referenced,uptodate,lru,active,readahead
0x000000040000006c 5 0 __RU_lA________________d_________ referenced,uptodate,lru,active,mappedtodisk
0x000000080000006c 3 0 __RU_lA_________________P________ referenced,uptodate,lru,active,private
0x0000000c0000006c 3 0 __RU_lA________________dP________ referenced,uptodate,lru,active,mappedtodisk,private
0x0000000c00000068 1 0 ___U_lA________________dP________ uptodate,lru,active,mappedtodisk,private
0x0000000000004078 1 0 ___UDlA_______b__________________ uptodate,dirty,lru,active,swapbacked
0x000000000000407c 34 0 __RUDlA_______b__________________ referenced,uptodate,dirty,lru,active,swapbacked
0x0000000000000400 538 2 __________B______________________ buddy
0x0000000000000804 1 0 __R________M_____________________ referenced,mmap
0x0000000000000828 1029 4 ___U_l_____M_____________________ uptodate,lru,mmap
0x0001000000000828 43 0 ___U_l_____M_________________I___ uptodate,lru,mmap,readahead
0x000000000000082c 382 1 __RU_l_____M_____________________ referenced,uptodate,lru,mmap
0x000100000000082c 12 0 __RU_l_____M_________________I___ referenced,uptodate,lru,mmap,readahead
0x0000000000000868 192 0 ___U_lA____M_____________________ uptodate,lru,active,mmap
0x0001000000000868 12 0 ___U_lA____M_________________I___ uptodate,lru,active,mmap,readahead
0x000000000000086c 800 3 __RU_lA____M_____________________ referenced,uptodate,lru,active,mmap
0x000100000000086c 31 0 __RU_lA____M_________________I___ referenced,uptodate,lru,active,mmap,readahead
0x0000000000004878 2 0 ___UDlA____M__b__________________ uptodate,dirty,lru,active,mmap,swapbacked
0x0000000000001000 492 1 ____________a____________________ anonymous
0x0000000000005008 2 0 ___U________a_b__________________ uptodate,anonymous,swapbacked
0x0000000000005808 4 0 ___U_______Ma_b__________________ uptodate,mmap,anonymous,swapbacked
0x000000000000580c 1 0 __RU_______Ma_b__________________ referenced,uptodate,mmap,anonymous,swapbacked
0x0000000000005868 2839 11 ___U_lA____Ma_b__________________ uptodate,lru,active,mmap,anonymous,swapbacked
0x000000000000586c 29 0 __RU_lA____Ma_b__________________ referenced,uptodate,lru,active,mmap,anonymous,swapbacked
total 513968 2007
# ./page-types --raw --list --no-summary --bits reserved
offset count flags
0 15 _____________________r___________
31 4 _____________________r___________
159 97 _____________________r___________
4096 2067 _____________________r___________
6752 2390 _____________________r___________
9355 3 _____________________r___________
9728 14526 _____________________r___________
This patch:
Introduce PageHuge(), which identifies huge/gigantic pages by their
dedicated compound destructor functions.
Also move prep_compound_gigantic_page() to hugetlb.c and make
__free_pages_ok() non-static.
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Matt Mackall <mpm@selenic.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-06-17 02:32:22 +04:00
|
|
|
#include <linux/hugetlb.h>
|
2009-12-16 14:19:59 +03:00
|
|
|
#include <linux/kernel-page-flags.h>
|
2008-10-06 14:26:12 +04:00
|
|
|
#include <asm/uaccess.h>
|
|
|
|
#include "internal.h"
|
|
|
|
|
|
|
|
#define KPMSIZE sizeof(u64)
|
|
|
|
#define KPMMASK (KPMSIZE - 1)
|
2009-06-17 02:32:23 +04:00
|
|
|
|
2008-10-06 14:26:12 +04:00
|
|
|
/* /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)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
while (count > 0) {
|
|
|
|
if (pfn_valid(pfn))
|
|
|
|
ppage = pfn_to_page(pfn);
|
2009-06-17 02:32:23 +04:00
|
|
|
else
|
|
|
|
ppage = NULL;
|
2011-01-13 04:00:34 +03:00
|
|
|
if (!ppage || PageSlab(ppage))
|
2008-10-06 14:26:12 +04:00
|
|
|
pcount = 0;
|
|
|
|
else
|
|
|
|
pcount = page_mapcount(ppage);
|
|
|
|
|
2009-06-17 02:32:23 +04:00
|
|
|
if (put_user(pcount, out)) {
|
2008-10-06 14:26:12 +04:00
|
|
|
ret = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-06-17 02:32:23 +04:00
|
|
|
pfn++;
|
|
|
|
out++;
|
2008-10-06 14:26:12 +04:00
|
|
|
count -= KPMSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ppos += (char __user *)out - buf;
|
|
|
|
if (!ret)
|
|
|
|
ret = (char __user *)out - buf;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct file_operations proc_kpagecount_operations = {
|
|
|
|
.llseek = mem_lseek,
|
|
|
|
.read = kpagecount_read,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* /proc/kpageflags - an array exposing page flags
|
|
|
|
*
|
|
|
|
* Each entry is a u64 representing the corresponding
|
|
|
|
* physical page flags.
|
|
|
|
*/
|
|
|
|
|
2009-06-17 02:32:24 +04:00
|
|
|
static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit)
|
|
|
|
{
|
|
|
|
return ((kflags >> kbit) & 1) << ubit;
|
|
|
|
}
|
|
|
|
|
2009-12-16 14:19:59 +03:00
|
|
|
u64 stable_page_flags(struct page *page)
|
2009-06-17 02:32:24 +04:00
|
|
|
{
|
|
|
|
u64 k;
|
|
|
|
u64 u;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pseudo flag: KPF_NOPAGE
|
|
|
|
* it differentiates a memory hole from a page with no flags
|
|
|
|
*/
|
|
|
|
if (!page)
|
|
|
|
return 1 << KPF_NOPAGE;
|
|
|
|
|
|
|
|
k = page->flags;
|
|
|
|
u = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pseudo flags for the well known (anonymous) memory mapped pages
|
|
|
|
*
|
|
|
|
* Note that page->_mapcount is overloaded in SLOB/SLUB/SLQB, so the
|
|
|
|
* simple test in page_mapped() is not enough.
|
|
|
|
*/
|
|
|
|
if (!PageSlab(page) && page_mapped(page))
|
|
|
|
u |= 1 << KPF_MMAP;
|
|
|
|
if (PageAnon(page))
|
|
|
|
u |= 1 << KPF_ANON;
|
2009-09-22 04:02:01 +04:00
|
|
|
if (PageKsm(page))
|
|
|
|
u |= 1 << KPF_KSM;
|
2009-06-17 02:32:24 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* compound pages: export both head/tail info
|
|
|
|
* they together define a compound page's start/end pos and order
|
|
|
|
*/
|
|
|
|
if (PageHead(page))
|
|
|
|
u |= 1 << KPF_COMPOUND_HEAD;
|
|
|
|
if (PageTail(page))
|
|
|
|
u |= 1 << KPF_COMPOUND_TAIL;
|
|
|
|
if (PageHuge(page))
|
|
|
|
u |= 1 << KPF_HUGE;
|
2012-10-09 03:33:47 +04:00
|
|
|
/*
|
|
|
|
* PageTransCompound can be true for non-huge compound pages (slab
|
|
|
|
* pages or pages allocated by drivers with __GFP_COMP) because it
|
2014-01-24 03:52:53 +04:00
|
|
|
* just checks PG_head/PG_tail, so we need to check PageLRU/PageAnon
|
|
|
|
* to make sure a given page is a thp, not a non-huge compound page.
|
2012-10-09 03:33:47 +04:00
|
|
|
*/
|
2014-03-04 03:38:18 +04:00
|
|
|
else if (PageTransCompound(page) && (PageLRU(compound_head(page)) ||
|
|
|
|
PageAnon(compound_head(page))))
|
2012-03-22 03:33:58 +04:00
|
|
|
u |= 1 << KPF_THP;
|
2009-06-17 02:32:24 +04:00
|
|
|
|
|
|
|
/*
|
2011-01-14 02:47:00 +03:00
|
|
|
* Caveats on high order pages: page->_count will only be set
|
|
|
|
* -1 on the head page; SLUB/SLQB do the same for PG_slab;
|
|
|
|
* SLOB won't set PG_slab at all on compound pages.
|
2009-06-17 02:32:24 +04:00
|
|
|
*/
|
2011-01-14 02:47:00 +03:00
|
|
|
if (PageBuddy(page))
|
|
|
|
u |= 1 << KPF_BUDDY;
|
|
|
|
|
|
|
|
u |= kpf_copy_bit(k, KPF_LOCKED, PG_locked);
|
|
|
|
|
2009-06-17 02:32:24 +04:00
|
|
|
u |= kpf_copy_bit(k, KPF_SLAB, PG_slab);
|
|
|
|
|
|
|
|
u |= kpf_copy_bit(k, KPF_ERROR, PG_error);
|
|
|
|
u |= kpf_copy_bit(k, KPF_DIRTY, PG_dirty);
|
|
|
|
u |= kpf_copy_bit(k, KPF_UPTODATE, PG_uptodate);
|
|
|
|
u |= kpf_copy_bit(k, KPF_WRITEBACK, PG_writeback);
|
|
|
|
|
|
|
|
u |= kpf_copy_bit(k, KPF_LRU, PG_lru);
|
|
|
|
u |= kpf_copy_bit(k, KPF_REFERENCED, PG_referenced);
|
|
|
|
u |= kpf_copy_bit(k, KPF_ACTIVE, PG_active);
|
|
|
|
u |= kpf_copy_bit(k, KPF_RECLAIM, PG_reclaim);
|
|
|
|
|
|
|
|
u |= kpf_copy_bit(k, KPF_SWAPCACHE, PG_swapcache);
|
|
|
|
u |= kpf_copy_bit(k, KPF_SWAPBACKED, PG_swapbacked);
|
|
|
|
|
|
|
|
u |= kpf_copy_bit(k, KPF_UNEVICTABLE, PG_unevictable);
|
|
|
|
u |= kpf_copy_bit(k, KPF_MLOCKED, PG_mlocked);
|
|
|
|
|
2009-10-08 03:32:27 +04:00
|
|
|
#ifdef CONFIG_MEMORY_FAILURE
|
|
|
|
u |= kpf_copy_bit(k, KPF_HWPOISON, PG_hwpoison);
|
|
|
|
#endif
|
|
|
|
|
2010-09-10 03:37:36 +04:00
|
|
|
#ifdef CONFIG_ARCH_USES_PG_UNCACHED
|
2009-06-17 02:32:24 +04:00
|
|
|
u |= kpf_copy_bit(k, KPF_UNCACHED, PG_uncached);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
u |= kpf_copy_bit(k, KPF_RESERVED, PG_reserved);
|
|
|
|
u |= kpf_copy_bit(k, KPF_MAPPEDTODISK, PG_mappedtodisk);
|
|
|
|
u |= kpf_copy_bit(k, KPF_PRIVATE, PG_private);
|
|
|
|
u |= kpf_copy_bit(k, KPF_PRIVATE_2, PG_private_2);
|
|
|
|
u |= kpf_copy_bit(k, KPF_OWNER_PRIVATE, PG_owner_priv_1);
|
|
|
|
u |= kpf_copy_bit(k, KPF_ARCH, PG_arch_1);
|
|
|
|
|
|
|
|
return u;
|
|
|
|
};
|
2008-10-06 14:26:12 +04:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
pfn = src / KPMSIZE;
|
|
|
|
count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src);
|
|
|
|
if (src & KPMMASK || count & KPMMASK)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
while (count > 0) {
|
|
|
|
if (pfn_valid(pfn))
|
|
|
|
ppage = pfn_to_page(pfn);
|
2009-06-17 02:32:23 +04:00
|
|
|
else
|
|
|
|
ppage = NULL;
|
2009-06-17 02:32:24 +04:00
|
|
|
|
2009-12-16 14:19:59 +03:00
|
|
|
if (put_user(stable_page_flags(ppage), out)) {
|
2008-10-06 14:26:12 +04:00
|
|
|
ret = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-06-17 02:32:23 +04:00
|
|
|
pfn++;
|
|
|
|
out++;
|
2008-10-06 14:26:12 +04:00
|
|
|
count -= KPMSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ppos += (char __user *)out - buf;
|
|
|
|
if (!ret)
|
|
|
|
ret = (char __user *)out - buf;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct file_operations proc_kpageflags_operations = {
|
|
|
|
.llseek = mem_lseek,
|
|
|
|
.read = kpageflags_read,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init proc_page_init(void)
|
|
|
|
{
|
|
|
|
proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations);
|
|
|
|
proc_create("kpageflags", S_IRUSR, NULL, &proc_kpageflags_operations);
|
|
|
|
return 0;
|
|
|
|
}
|
2014-01-24 03:55:45 +04:00
|
|
|
fs_initcall(proc_page_init);
|