Skip to content

Commit 8c1fe56

Browse files
gormanmhnaz
authored andcommitted
mm, vmscan: Update all zone LRU sizes before updating memcg
Minchan Kim reported setting the following warning on a 32-bit system although it can affect 64-bit systems. WARNING: CPU: 4 PID: 1322 at mm/memcontrol.c:998 mem_cgroup_update_lru_size+0x103/0x110 mem_cgroup_update_lru_size(f44b4000, 1, -7): zid 1 lru_size 1 but empty Modules linked in: CPU: 4 PID: 1322 Comm: cp Not tainted 4.7.0-rc4-mm1+ torvalds#143 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 00000086 00000086 c2bc5a10 db3e4a97 c2bc5a54 db9d4025 c2bc5a40 db07b82a db9d0594 c2bc5a70 0000052a db9d4025 000003e6 db208463 000003e6 00000001 f44b4000 00000001 c2bc5a5c db07b88b 00000009 00000000 c2bc5a54 db9d0594 Call Trace: [<db3e4a97>] dump_stack+0x76/0xaf [<db07b82a>] __warn+0xea/0x110 [<db208463>] ? mem_cgroup_update_lru_size+0x103/0x110 [<db07b88b>] warn_slowpath_fmt+0x3b/0x40 [<db208463>] mem_cgroup_update_lru_size+0x103/0x110 [<db1b52a2>] isolate_lru_pages.isra.61+0x2e2/0x360 [<db1b6ffc>] shrink_active_list+0xac/0x2a0 [<db3f136e>] ? __delay+0xe/0x10 [<db1b772c>] shrink_node_memcg+0x53c/0x7a0 [<db1b7a3b>] shrink_node+0xab/0x2a0 [<db1b7cf6>] do_try_to_free_pages+0xc6/0x390 [<db1b8205>] try_to_free_pages+0x245/0x590 LRU list contents and counts are updated separately. Counts are updated before pages are added to the LRU and updated after pages are removed. The warning above is from a check in mem_cgroup_update_lru_size that ensures that list sizes of zero are empty. The problem is that node-lru needs to account for highmem pages if CONFIG_HIGHMEM is set. One impact of the implementation is that the sizes are updated in multiple passes when pages from multiple zones were isolated. This happens whether HIGHMEM is set or not. When multiple zones are isolated, it's possible for a debugging check in memcg to be tripped. This patch forces all the zone counts to be updated before the memcg function is called. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Mel Gorman <[email protected]> Tested-by: Minchan Kim <[email protected]> Reported-by: Minchan Kim <[email protected]> Acked-by: Minchan Kim <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 4129592 commit 8c1fe56

File tree

4 files changed

+37
-15
lines changed

4 files changed

+37
-15
lines changed

include/linux/memcontrol.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ static inline bool mem_cgroup_online(struct mem_cgroup *memcg)
430430
int mem_cgroup_select_victim_node(struct mem_cgroup *memcg);
431431

432432
void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru,
433-
enum zone_type zid, int nr_pages);
433+
int nr_pages);
434434

435435
unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
436436
int nid, unsigned int lru_mask);

include/linux/mm_inline.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,9 @@ static __always_inline void update_lru_size(struct lruvec *lruvec,
5252
enum lru_list lru, enum zone_type zid,
5353
int nr_pages)
5454
{
55-
#ifdef CONFIG_MEMCG
56-
mem_cgroup_update_lru_size(lruvec, lru, zid, nr_pages);
57-
#else
5855
__update_lru_size(lruvec, lru, zid, nr_pages);
56+
#ifdef CONFIG_MEMCG
57+
mem_cgroup_update_lru_size(lruvec, lru, nr_pages);
5958
#endif
6059
}
6160

mm/memcontrol.c

+1-4
Original file line numberDiff line numberDiff line change
@@ -965,23 +965,20 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct pglist_data *pgd
965965
* mem_cgroup_update_lru_size - account for adding or removing an lru page
966966
* @lruvec: mem_cgroup per zone lru vector
967967
* @lru: index of lru list the page is sitting on
968-
* @zid: Zone ID of the zone pages have been added to
969968
* @nr_pages: positive when adding or negative when removing
970969
*
971970
* This function must be called under lru_lock, just before a page is added
972971
* to or just after a page is removed from an lru list (that ordering being
973972
* so as to allow it to check that lru_size 0 is consistent with list_empty).
974973
*/
975974
void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru,
976-
enum zone_type zid, int nr_pages)
975+
int nr_pages)
977976
{
978977
struct mem_cgroup_per_node *mz;
979978
unsigned long *lru_size;
980979
long size;
981980
bool empty;
982981

983-
__update_lru_size(lruvec, lru, zid, nr_pages);
984-
985982
if (mem_cgroup_disabled())
986983
return;
987984

mm/vmscan.c

+33-7
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,38 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode)
13501350
return ret;
13511351
}
13521352

1353+
1354+
/*
1355+
* Update LRU sizes after isolating pages. The LRU size updates must
1356+
* be complete before mem_cgroup_update_lru_size due to a santity check.
1357+
*/
1358+
static __always_inline void update_lru_sizes(struct lruvec *lruvec,
1359+
enum lru_list lru, unsigned long *nr_zone_taken,
1360+
unsigned long nr_taken)
1361+
{
1362+
#ifdef CONFIG_HIGHMEM
1363+
int zid;
1364+
1365+
/*
1366+
* Highmem has separate accounting for highmem pages so each zone
1367+
* is updated separately.
1368+
*/
1369+
for (zid = 0; zid < MAX_NR_ZONES; zid++) {
1370+
if (!nr_zone_taken[zid])
1371+
continue;
1372+
1373+
__update_lru_size(lruvec, lru, zid, -nr_zone_taken[zid]);
1374+
}
1375+
#else
1376+
/* Zone ID does not matter on !HIGHMEM */
1377+
__update_lru_size(lruvec, lru, 0, -nr_taken);
1378+
#endif
1379+
1380+
#ifdef CONFIG_MEMCG
1381+
mem_cgroup_update_lru_size(lruvec, lru, -nr_taken);
1382+
#endif
1383+
}
1384+
13531385
/*
13541386
* zone_lru_lock is heavily contended. Some of the functions that
13551387
* shrink the lists perform better by taking out a batch of pages
@@ -1436,13 +1468,7 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
14361468
*nr_scanned = scan;
14371469
trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan, scan,
14381470
nr_taken, mode, is_file_lru(lru));
1439-
for (scan = 0; scan < MAX_NR_ZONES; scan++) {
1440-
nr_pages = nr_zone_taken[scan];
1441-
if (!nr_pages)
1442-
continue;
1443-
1444-
update_lru_size(lruvec, lru, scan, -nr_pages);
1445-
}
1471+
update_lru_sizes(lruvec, lru, nr_zone_taken, nr_taken);
14461472
return nr_taken;
14471473
}
14481474

0 commit comments

Comments
 (0)