hugetlbfs: dirty pages as they are added to pagecache
authorMike Kravetz <>
Fri, 26 Oct 2018 22:10:58 +0000 (15:10 -0700)
committerLinus Torvalds <>
Fri, 26 Oct 2018 23:38:16 +0000 (16:38 -0700)
Some test systems were experiencing negative huge page reserve counts and
incorrect file block counts.  This was traced to /proc/sys/vm/drop_caches
removing clean pages from hugetlbfs file pagecaches.  When non-hugetlbfs
explicit code removes the pages, the appropriate accounting is not

This can be recreated as follows:
 fallocate -l 2M /dev/hugepages/foo
 echo 1 > /proc/sys/vm/drop_caches
 fallocate -l 2M /dev/hugepages/foo
 grep -i huge /proc/meminfo
   AnonHugePages:         0 kB
   ShmemHugePages:        0 kB
   HugePages_Total:    2048
   HugePages_Free:     2047
   HugePages_Rsvd:    18446744073709551615
   HugePages_Surp:        0
   Hugepagesize:       2048 kB
   Hugetlb:         4194304 kB
 ls -lsh /dev/hugepages/foo
   4.0M -rw-r--r--. 1 root root 2.0M Oct 17 20:05 /dev/hugepages/foo

To address this issue, dirty pages as they are added to pagecache.  This
can easily be reproduced with fallocate as shown above.  Read faulted
pages will eventually end up being marked dirty.  But there is a window
where they are clean and could be impacted by code such as drop_caches.
So, just dirty them all as they are added to the pagecache.

Fixes: 6bda666a03f0 ("hugepages: fold find_or_alloc_pages into huge_no_page()")
Signed-off-by: Mike Kravetz <>
Acked-by: Mihcla Hocko <>
Reviewed-by: Khalid Aziz <>
Cc: Hugh Dickins <>
Cc: Naoya Horiguchi <>
Cc: "Aneesh Kumar K . V" <>
Cc: Andrea Arcangeli <>
Cc: "Kirill A . Shutemov" <>
Cc: Davidlohr Bueso <>
Cc: Alexander Viro <>
Cc: <>
Signed-off-by: Andrew Morton <>
Signed-off-by: Linus Torvalds <>

index 5c390f5a5207b5c0b4d1d55524d2f655c7edcae1..7b5c0ad9a6bd03909885334877a33f363c007b80 100644 (file)
@@ -3690,6 +3690,12 @@ int huge_add_to_page_cache(struct page *page, struct address_space *mapping,
                return err;
+       /*
+        * set page dirty so that it will not be removed from cache/file
+        * by non-hugetlbfs specific code paths.
+        */
+       set_page_dirty(page);
        inode->i_blocks += blocks_per_huge_page(h);