diff options
author | Matthew Wilcox <mawilcox@microsoft.com> | 2018-04-20 17:56:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-20 20:18:36 -0400 |
commit | abc1be13fd113ddef5e2d807a466286b864caed3 (patch) | |
tree | 7991dabeeb9923fb7b055fd6b092463f5ef8e994 /mm/filemap.c | |
parent | c892fd82cc0632d425ae011a4dd75eb59e9f84ee (diff) |
mm/filemap.c: fix NULL pointer in page_cache_tree_insert()
f2fs specifies the __GFP_ZERO flag for allocating some of its pages.
Unfortunately, the page cache also uses the mapping's GFP flags for
allocating radix tree nodes. It always masked off the __GFP_HIGHMEM
flag, and masks off __GFP_ZERO in some paths, but not all. That causes
radix tree nodes to be allocated with a NULL list_head, which causes
backtraces like:
__list_del_entry+0x30/0xd0
list_lru_del+0xac/0x1ac
page_cache_tree_insert+0xd8/0x110
The __GFP_DMA and __GFP_DMA32 flags would also be able to sneak through
if they are ever used. Fix them all by using GFP_RECLAIM_MASK at the
innermost location, and remove it from earlier in the callchain.
Link: http://lkml.kernel.org/r/20180411060320.14458-2-willy@infradead.org
Fixes: 449dd6984d0e ("mm: keep page cache radix tree nodes in check")
Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com>
Reported-by: Chris Fries <cfries@google.com>
Debugged-by: Minchan Kim <minchan@kernel.org>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/filemap.c')
-rw-r--r-- | mm/filemap.c | 9 |
1 files changed, 4 insertions, 5 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 9276bdb2343c..0604cb02e6f3 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -786,7 +786,7 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask) | |||
786 | VM_BUG_ON_PAGE(!PageLocked(new), new); | 786 | VM_BUG_ON_PAGE(!PageLocked(new), new); |
787 | VM_BUG_ON_PAGE(new->mapping, new); | 787 | VM_BUG_ON_PAGE(new->mapping, new); |
788 | 788 | ||
789 | error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); | 789 | error = radix_tree_preload(gfp_mask & GFP_RECLAIM_MASK); |
790 | if (!error) { | 790 | if (!error) { |
791 | struct address_space *mapping = old->mapping; | 791 | struct address_space *mapping = old->mapping; |
792 | void (*freepage)(struct page *); | 792 | void (*freepage)(struct page *); |
@@ -842,7 +842,7 @@ static int __add_to_page_cache_locked(struct page *page, | |||
842 | return error; | 842 | return error; |
843 | } | 843 | } |
844 | 844 | ||
845 | error = radix_tree_maybe_preload(gfp_mask & ~__GFP_HIGHMEM); | 845 | error = radix_tree_maybe_preload(gfp_mask & GFP_RECLAIM_MASK); |
846 | if (error) { | 846 | if (error) { |
847 | if (!huge) | 847 | if (!huge) |
848 | mem_cgroup_cancel_charge(page, memcg, false); | 848 | mem_cgroup_cancel_charge(page, memcg, false); |
@@ -1585,8 +1585,7 @@ no_page: | |||
1585 | if (fgp_flags & FGP_ACCESSED) | 1585 | if (fgp_flags & FGP_ACCESSED) |
1586 | __SetPageReferenced(page); | 1586 | __SetPageReferenced(page); |
1587 | 1587 | ||
1588 | err = add_to_page_cache_lru(page, mapping, offset, | 1588 | err = add_to_page_cache_lru(page, mapping, offset, gfp_mask); |
1589 | gfp_mask & GFP_RECLAIM_MASK); | ||
1590 | if (unlikely(err)) { | 1589 | if (unlikely(err)) { |
1591 | put_page(page); | 1590 | put_page(page); |
1592 | page = NULL; | 1591 | page = NULL; |
@@ -2387,7 +2386,7 @@ static int page_cache_read(struct file *file, pgoff_t offset, gfp_t gfp_mask) | |||
2387 | if (!page) | 2386 | if (!page) |
2388 | return -ENOMEM; | 2387 | return -ENOMEM; |
2389 | 2388 | ||
2390 | ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask & GFP_KERNEL); | 2389 | ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask); |
2391 | if (ret == 0) | 2390 | if (ret == 0) |
2392 | ret = mapping->a_ops->readpage(file, page); | 2391 | ret = mapping->a_ops->readpage(file, page); |
2393 | else if (ret == -EEXIST) | 2392 | else if (ret == -EEXIST) |