Skip to content

Commit e34e744

Browse files
Yang Shigregkh
authored andcommitted
mm: check the return value of lookup_page_ext for all call sites
commit f86e4271978bd93db466d6a95dad4b0fdcdb04f6 upstream. Per the discussion with Joonsoo Kim [1], we need check the return value of lookup_page_ext() for all call sites since it might return NULL in some cases, although it is unlikely, i.e. memory hotplug. Tested with ltp with "page_owner=0". [1] http://lkml.kernel.org/r/20160519002809.GA10245@js1304-P5Q-DELUXE [akpm@linux-foundation.org: fix build-breaking typos] [arnd@arndb.de: fix build problems from lookup_page_ext] Link: http://lkml.kernel.org/r/6285269.2CksypHdYp@wuerfel [akpm@linux-foundation.org: coding-style fixes] Link: http://lkml.kernel.org/r/1464023768-31025-1-git-send-email-yang.shi@linaro.org Signed-off-by: Yang Shi <yang.shi@linaro.org> Signed-off-by: Arnd Bergmann <arnd@arndb.de> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Michal Hocko <mhocko@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 7b7a1c3 commit e34e744

5 files changed

Lines changed: 66 additions & 7 deletions

File tree

include/linux/page_idle.h

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,33 +46,62 @@ extern struct page_ext_operations page_idle_ops;
4646

4747
static inline bool page_is_young(struct page *page)
4848
{
49-
return test_bit(PAGE_EXT_YOUNG, &lookup_page_ext(page)->flags);
49+
struct page_ext *page_ext = lookup_page_ext(page);
50+
51+
if (unlikely(!page_ext))
52+
return false;
53+
54+
return test_bit(PAGE_EXT_YOUNG, &page_ext->flags);
5055
}
5156

5257
static inline void set_page_young(struct page *page)
5358
{
54-
set_bit(PAGE_EXT_YOUNG, &lookup_page_ext(page)->flags);
59+
struct page_ext *page_ext = lookup_page_ext(page);
60+
61+
if (unlikely(!page_ext))
62+
return;
63+
64+
set_bit(PAGE_EXT_YOUNG, &page_ext->flags);
5565
}
5666

5767
static inline bool test_and_clear_page_young(struct page *page)
5868
{
59-
return test_and_clear_bit(PAGE_EXT_YOUNG,
60-
&lookup_page_ext(page)->flags);
69+
struct page_ext *page_ext = lookup_page_ext(page);
70+
71+
if (unlikely(!page_ext))
72+
return false;
73+
74+
return test_and_clear_bit(PAGE_EXT_YOUNG, &page_ext->flags);
6175
}
6276

6377
static inline bool page_is_idle(struct page *page)
6478
{
65-
return test_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags);
79+
struct page_ext *page_ext = lookup_page_ext(page);
80+
81+
if (unlikely(!page_ext))
82+
return false;
83+
84+
return test_bit(PAGE_EXT_IDLE, &page_ext->flags);
6685
}
6786

6887
static inline void set_page_idle(struct page *page)
6988
{
70-
set_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags);
89+
struct page_ext *page_ext = lookup_page_ext(page);
90+
91+
if (unlikely(!page_ext))
92+
return;
93+
94+
set_bit(PAGE_EXT_IDLE, &page_ext->flags);
7195
}
7296

7397
static inline void clear_page_idle(struct page *page)
7498
{
75-
clear_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags);
99+
struct page_ext *page_ext = lookup_page_ext(page);
100+
101+
if (unlikely(!page_ext))
102+
return;
103+
104+
clear_bit(PAGE_EXT_IDLE, &page_ext->flags);
76105
}
77106
#endif /* CONFIG_64BIT */
78107

mm/debug-pagealloc.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ static inline void set_page_poison(struct page *page)
3434
struct page_ext *page_ext;
3535

3636
page_ext = lookup_page_ext(page);
37+
if (page_ext)
38+
return;
3739
__set_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
3840
}
3941

@@ -42,6 +44,8 @@ static inline void clear_page_poison(struct page *page)
4244
struct page_ext *page_ext;
4345

4446
page_ext = lookup_page_ext(page);
47+
if (page_ext)
48+
return;
4549
__clear_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
4650
}
4751

@@ -50,6 +54,8 @@ static inline bool page_poison(struct page *page)
5054
struct page_ext *page_ext;
5155

5256
page_ext = lookup_page_ext(page);
57+
if (page_ext)
58+
return false;
5359
return test_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
5460
}
5561

mm/page_alloc.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,9 @@ static inline void set_page_guard(struct zone *zone, struct page *page,
569569
return;
570570

571571
page_ext = lookup_page_ext(page);
572+
if (unlikely(!page_ext))
573+
return;
574+
572575
__set_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags);
573576

574577
INIT_LIST_HEAD(&page->lru);
@@ -586,6 +589,9 @@ static inline void clear_page_guard(struct zone *zone, struct page *page,
586589
return;
587590

588591
page_ext = lookup_page_ext(page);
592+
if (unlikely(!page_ext))
593+
return;
594+
589595
__clear_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags);
590596

591597
set_page_private(page, 0);

mm/page_owner.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,26 @@ void __reset_page_owner(struct page *page, unsigned int order)
5353

5454
for (i = 0; i < (1 << order); i++) {
5555
page_ext = lookup_page_ext(page + i);
56+
if (unlikely(!page_ext))
57+
continue;
5658
__clear_bit(PAGE_EXT_OWNER, &page_ext->flags);
5759
}
5860
}
5961

6062
void __set_page_owner(struct page *page, unsigned int order, gfp_t gfp_mask)
6163
{
6264
struct page_ext *page_ext = lookup_page_ext(page);
65+
6366
struct stack_trace trace = {
6467
.nr_entries = 0,
6568
.max_entries = ARRAY_SIZE(page_ext->trace_entries),
6669
.entries = &page_ext->trace_entries[0],
6770
.skip = 3,
6871
};
6972

73+
if (unlikely(!page_ext))
74+
return;
75+
7076
save_stack_trace(&trace);
7177

7278
page_ext->order = order;
@@ -79,6 +85,12 @@ void __set_page_owner(struct page *page, unsigned int order, gfp_t gfp_mask)
7985
gfp_t __get_page_owner_gfp(struct page *page)
8086
{
8187
struct page_ext *page_ext = lookup_page_ext(page);
88+
if (unlikely(!page_ext))
89+
/*
90+
* The caller just returns 0 if no valid gfp
91+
* So return 0 here too.
92+
*/
93+
return 0;
8294

8395
return page_ext->gfp_mask;
8496
}
@@ -194,6 +206,8 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
194206
}
195207

196208
page_ext = lookup_page_ext(page);
209+
if (unlikely(!page_ext))
210+
continue;
197211

198212
/*
199213
* Some pages could be missed by concurrent allocation or free,
@@ -257,6 +271,8 @@ static void init_pages_in_zone(pg_data_t *pgdat, struct zone *zone)
257271
continue;
258272

259273
page_ext = lookup_page_ext(page);
274+
if (unlikely(!page_ext))
275+
continue;
260276

261277
/* Maybe overraping zone */
262278
if (test_bit(PAGE_EXT_OWNER, &page_ext->flags))

mm/vmstat.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,8 @@ static void pagetypeinfo_showmixedcount_print(struct seq_file *m,
10911091
continue;
10921092

10931093
page_ext = lookup_page_ext(page);
1094+
if (unlikely(!page_ext))
1095+
continue;
10941096

10951097
if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags))
10961098
continue;

0 commit comments

Comments
 (0)