Skip to content

Commit a801752

Browse files
Muchun Songjfvogel
authored andcommitted
mm: thp: make split queue lock safe when LRU pages are reparented
Similar to the lruvec lock, we use the same approach to make the split queue lock safe when LRU pages are reparented. Signed-off-by: Muchun Song <[email protected]> Acked-by: Roman Gushchin <[email protected]> Link: https://lore.kernel.org/all/[email protected]/ Orabug: 37405594 Conflicts: mm/huge_memory.c (Due to presence of 'commit 3e9a13d huge_memory: convert split_huge_page_to_list() to use a folio'. Also in UEK-8, the names of some of the affected functions has changed as follows: free_transhuge_page --> folio_undo_large_rmappable deferred_split_huge_page --> deferred_split_folio So these equivalent functions were changed according to this patch.) Signed-off-by: Imran Khan <[email protected]> Reviewed-by: Kamalesh Babulal <[email protected]>
1 parent d6530a1 commit a801752

File tree

2 files changed

+96
-27
lines changed

2 files changed

+96
-27
lines changed

include/linux/memcontrol.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,6 +1678,11 @@ int alloc_shrinker_info(struct mem_cgroup *memcg);
16781678
void free_shrinker_info(struct mem_cgroup *memcg);
16791679
void set_shrinker_bit(struct mem_cgroup *memcg, int nid, int shrinker_id);
16801680
void reparent_shrinker_deferred(struct mem_cgroup *memcg);
1681+
1682+
static inline int shrinker_id(struct shrinker *shrinker)
1683+
{
1684+
return shrinker->id;
1685+
}
16811686
#else
16821687
#define mem_cgroup_sockets_enabled 0
16831688
static inline void mem_cgroup_sk_alloc(struct sock *sk) { };
@@ -1691,6 +1696,11 @@ static inline void set_shrinker_bit(struct mem_cgroup *memcg,
16911696
int nid, int shrinker_id)
16921697
{
16931698
}
1699+
1700+
static inline int shrinker_id(struct shrinker *shrinker)
1701+
{
1702+
return -1;
1703+
}
16941704
#endif
16951705

16961706
#ifdef CONFIG_MEMCG

mm/huge_memory.c

Lines changed: 86 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,27 +1040,90 @@ pmd_t maybe_pmd_mkwrite(pmd_t pmd, struct vm_area_struct *vma)
10401040
}
10411041

10421042
#ifdef CONFIG_MEMCG
1043-
static inline
1044-
struct deferred_split *get_deferred_split_queue(struct folio *folio)
1043+
static inline struct mem_cgroup *folio_split_queue_memcg(struct folio *folio,
1044+
struct deferred_split *queue)
1045+
{
1046+
if (mem_cgroup_disabled())
1047+
return NULL;
1048+
if (&NODE_DATA(folio_nid(folio))->deferred_split_queue == queue)
1049+
return NULL;
1050+
return container_of(queue, struct mem_cgroup, deferred_split_queue);
1051+
}
1052+
1053+
static inline struct deferred_split *folio_memcg_split_queue(struct folio *folio)
10451054
{
10461055
struct mem_cgroup *memcg = folio_memcg(folio);
1047-
struct pglist_data *pgdat = NODE_DATA(folio_nid(folio));
10481056

1049-
if (memcg)
1050-
return &memcg->deferred_split_queue;
1051-
else
1052-
return &pgdat->deferred_split_queue;
1057+
return memcg ? &memcg->deferred_split_queue : NULL;
10531058
}
10541059
#else
1055-
static inline
1056-
struct deferred_split *get_deferred_split_queue(struct folio *folio)
1060+
static inline struct mem_cgroup *folio_split_queue_memcg(struct folio *folio,
1061+
struct deferred_split *queue)
10571062
{
1058-
struct pglist_data *pgdat = NODE_DATA(folio_nid(folio));
1063+
return NULL;
1064+
}
10591065

1060-
return &pgdat->deferred_split_queue;
1066+
static inline struct deferred_split *folio_memcg_split_queue(struct folio *folio)
1067+
{
1068+
return NULL;
10611069
}
10621070
#endif
10631071

1072+
static struct deferred_split *folio_split_queue(struct folio *folio)
1073+
{
1074+
struct deferred_split *queue = folio_memcg_split_queue(folio);
1075+
1076+
return queue ? : &NODE_DATA(folio_nid(folio))->deferred_split_queue;
1077+
}
1078+
1079+
static struct deferred_split *folio_split_queue_lock(struct folio *folio)
1080+
{
1081+
struct deferred_split *queue;
1082+
1083+
rcu_read_lock();
1084+
retry:
1085+
queue = folio_split_queue(folio);
1086+
spin_lock(&queue->split_queue_lock);
1087+
1088+
if (unlikely(folio_split_queue_memcg(folio, queue) != folio_memcg(folio))) {
1089+
spin_unlock(&queue->split_queue_lock);
1090+
goto retry;
1091+
}
1092+
rcu_read_unlock();
1093+
1094+
return queue;
1095+
}
1096+
1097+
static struct deferred_split *
1098+
folio_split_queue_lock_irqsave(struct folio *folio, unsigned long *flags)
1099+
{
1100+
struct deferred_split *queue;
1101+
1102+
rcu_read_lock();
1103+
retry:
1104+
queue = folio_split_queue(folio);
1105+
spin_lock_irqsave(&queue->split_queue_lock, *flags);
1106+
1107+
if (unlikely(folio_split_queue_memcg(folio, queue) != folio_memcg(folio))) {
1108+
spin_unlock_irqrestore(&queue->split_queue_lock, *flags);
1109+
goto retry;
1110+
}
1111+
rcu_read_unlock();
1112+
1113+
return queue;
1114+
}
1115+
1116+
static inline void split_queue_unlock(struct deferred_split *queue)
1117+
{
1118+
spin_unlock(&queue->split_queue_lock);
1119+
}
1120+
1121+
static inline void split_queue_unlock_irqrestore(struct deferred_split *queue,
1122+
unsigned long flags)
1123+
{
1124+
spin_unlock_irqrestore(&queue->split_queue_lock, flags);
1125+
}
1126+
10641127
static inline bool is_transparent_hugepage(const struct folio *folio)
10651128
{
10661129
if (!folio_test_large(folio))
@@ -3361,7 +3424,7 @@ int split_huge_page_to_list_to_order(struct page *page, struct list_head *list,
33613424
unsigned int new_order)
33623425
{
33633426
struct folio *folio = page_folio(page);
3364-
struct deferred_split *ds_queue = get_deferred_split_queue(folio);
3427+
struct deferred_split *ds_queue;
33653428
/* reset xarray order to new order after split */
33663429
XA_STATE_ORDER(xas, &folio->mapping->i_pages, folio->index, new_order);
33673430
bool is_anon = folio_test_anon(folio);
@@ -3509,7 +3572,7 @@ int split_huge_page_to_list_to_order(struct page *page, struct list_head *list,
35093572
}
35103573

35113574
/* Prevent deferred_split_scan() touching ->_refcount */
3512-
spin_lock(&ds_queue->split_queue_lock);
3575+
ds_queue = folio_split_queue_lock(folio);
35133576
if (folio_ref_freeze(folio, 1 + extra_pins)) {
35143577
if (folio_order(folio) > 1 &&
35153578
!list_empty(&folio->_deferred_list)) {
@@ -3527,7 +3590,7 @@ int split_huge_page_to_list_to_order(struct page *page, struct list_head *list,
35273590
*/
35283591
list_del_init(&folio->_deferred_list);
35293592
}
3530-
spin_unlock(&ds_queue->split_queue_lock);
3593+
split_queue_unlock(ds_queue);
35313594
if (mapping) {
35323595
int nr = folio_nr_pages(folio);
35333596

@@ -3552,7 +3615,7 @@ int split_huge_page_to_list_to_order(struct page *page, struct list_head *list,
35523615
__split_huge_page(page, list, end, new_order);
35533616
ret = 0;
35543617
} else {
3555-
spin_unlock(&ds_queue->split_queue_lock);
3618+
split_queue_unlock(ds_queue);
35563619
fail:
35573620
if (mapping)
35583621
xas_unlock(&xas);
@@ -3622,8 +3685,7 @@ bool __folio_unqueue_deferred_split(struct folio *folio)
36223685
WARN_ON_ONCE(folio_ref_count(folio));
36233686
WARN_ON_ONCE(!mem_cgroup_disabled() && !folio_memcg(folio));
36243687

3625-
ds_queue = get_deferred_split_queue(folio);
3626-
spin_lock_irqsave(&ds_queue->split_queue_lock, flags);
3688+
ds_queue = folio_split_queue_lock_irqsave(folio, &flags);
36273689
if (!list_empty(&folio->_deferred_list)) {
36283690
ds_queue->split_queue_len--;
36293691
if (folio_test_partially_mapped(folio)) {
@@ -3634,18 +3696,15 @@ bool __folio_unqueue_deferred_split(struct folio *folio)
36343696
list_del_init(&folio->_deferred_list);
36353697
unqueued = true;
36363698
}
3637-
spin_unlock_irqrestore(&ds_queue->split_queue_lock, flags);
3699+
split_queue_unlock_irqrestore(ds_queue, flags);
36383700

36393701
return unqueued; /* useful for debug warnings */
36403702
}
36413703

36423704
/* partially_mapped=false won't clear PG_partially_mapped folio flag */
36433705
void deferred_split_folio(struct folio *folio, bool partially_mapped)
36443706
{
3645-
struct deferred_split *ds_queue = get_deferred_split_queue(folio);
3646-
#ifdef CONFIG_MEMCG
3647-
struct mem_cgroup *memcg = folio_memcg(folio);
3648-
#endif
3707+
struct deferred_split *ds_queue;
36493708
unsigned long flags;
36503709

36513710
/*
@@ -3668,7 +3727,7 @@ void deferred_split_folio(struct folio *folio, bool partially_mapped)
36683727
if (folio_test_swapcache(folio))
36693728
return;
36703729

3671-
spin_lock_irqsave(&ds_queue->split_queue_lock, flags);
3730+
ds_queue = folio_split_queue_lock_irqsave(folio, &flags);
36723731
if (partially_mapped) {
36733732
if (!folio_test_partially_mapped(folio)) {
36743733
folio_set_partially_mapped(folio);
@@ -3683,15 +3742,15 @@ void deferred_split_folio(struct folio *folio, bool partially_mapped)
36833742
VM_WARN_ON_FOLIO(folio_test_partially_mapped(folio), folio);
36843743
}
36853744
if (list_empty(&folio->_deferred_list)) {
3745+
struct mem_cgroup *memcg;
3746+
memcg = folio_split_queue_memcg(folio, ds_queue);
36863747
list_add_tail(&folio->_deferred_list, &ds_queue->split_queue);
36873748
ds_queue->split_queue_len++;
3688-
#ifdef CONFIG_MEMCG
36893749
if (memcg)
36903750
set_shrinker_bit(memcg, folio_nid(folio),
3691-
deferred_split_shrinker->id);
3692-
#endif
3751+
shrinker_id(deferred_split_shrinker));
36933752
}
3694-
spin_unlock_irqrestore(&ds_queue->split_queue_lock, flags);
3753+
split_queue_unlock_irqrestore(ds_queue, flags);
36953754
}
36963755

36973756
static unsigned long deferred_split_count(struct shrinker *shrink,

0 commit comments

Comments
 (0)