anolis: mm: avoid lru_gen_del_page if kidled is enabled
ANBZ: #6676 If LRU_GEN is disabled and kidled is enabled, the page flags of mglru has been reused by kidled. However, lru_gen_del_page is not covered by lru_gen_enabled(), thus it might change the page state. Reviewed-by: Xu Yu <xuyu@linux.alibaba.com> Link: https://gitee.com/anolis/cloud-kernel/pulls/2232
This commit is contained in:
parent
4cf29028de
commit
80a5f6c8fc
|
@ -96,6 +96,8 @@ enum kidled_scan_type {
|
|||
#define KIDLED_IS_BUCKET_INVALID(buckets) \
|
||||
(buckets[0] == KIDLED_INVALID_BUCKET)
|
||||
|
||||
DECLARE_STATIC_KEY_FALSE(kidled_enabled_key);
|
||||
|
||||
static inline bool kidled_is_slab_scanned(unsigned short slab_age,
|
||||
unsigned long scan_rounds)
|
||||
{
|
||||
|
@ -304,6 +306,11 @@ static inline void kidled_set_scan_duration(u16 duration)
|
|||
duration, NULL);
|
||||
}
|
||||
|
||||
static inline bool is_kidled_enabled(void)
|
||||
{
|
||||
return static_branch_unlikely(&kidled_enabled_key);
|
||||
}
|
||||
|
||||
/*
|
||||
* Caller must specify the original scan period, avoid the race between
|
||||
* the double operation and user's updates through sysfs interface.
|
||||
|
@ -423,8 +430,11 @@ static inline unsigned int kidled_get_current_scan_duration(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline bool is_kidled_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_KIDLED */
|
||||
|
||||
#define is_kidled_enabled() kidled_get_current_scan_duration()
|
||||
|
||||
#endif /* _LINUX_MM_KIDLED_H */
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <linux/huge_mm.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/kidled.h>
|
||||
|
||||
/**
|
||||
* page_is_file_lru - should the page be on a file LRU or anon LRU?
|
||||
|
@ -273,7 +274,7 @@ static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bo
|
|||
unsigned long flags;
|
||||
int gen = page_lru_gen(page);
|
||||
|
||||
if (gen < 0)
|
||||
if (gen < 0 || is_kidled_enabled())
|
||||
return false;
|
||||
|
||||
VM_WARN_ON_ONCE_PAGE(PageActive(page), page);
|
||||
|
|
|
@ -1004,6 +1004,8 @@ static inline void ClearPageSlabPfmemalloc(struct page *page)
|
|||
/*
|
||||
* Flags checked when a page is freed. Pages being freed should not have
|
||||
* these flags set. It they are, there is a problem.
|
||||
*
|
||||
* To avoid conflict with kidled, we skip to check LRU_GEN_MASK.
|
||||
*/
|
||||
#define PAGE_FLAGS_CHECK_AT_FREE \
|
||||
(1UL << PG_lru | 1UL << PG_locked | \
|
||||
|
@ -1011,7 +1013,7 @@ static inline void ClearPageSlabPfmemalloc(struct page *page)
|
|||
1UL << PG_writeback | 1UL << PG_reserved | \
|
||||
1UL << PG_slab | 1UL << PG_active | \
|
||||
1UL << PG_unevictable | __PG_MLOCKED | \
|
||||
__PG_DUP | LRU_GEN_MASK)
|
||||
__PG_DUP)
|
||||
|
||||
/*
|
||||
* Flags checked when a page is prepped for return by the page allocator.
|
||||
|
|
13
mm/kidled.c
13
mm/kidled.c
|
@ -68,6 +68,8 @@
|
|||
#define __kidled_ref __ref
|
||||
#endif
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(kidled_enabled_key);
|
||||
|
||||
unsigned int kidled_scan_target __read_mostly = KIDLED_SCAN_PAGE;
|
||||
struct kidled_scan_control kidled_scan_control;
|
||||
/*
|
||||
|
@ -785,6 +787,10 @@ static inline bool kidled_should_run(struct kidled_scan_control *p,
|
|||
kidled_reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!scan_control.duration)
|
||||
static_branch_disable(&kidled_enabled_key);
|
||||
|
||||
*p = scan_control;
|
||||
*new = true;
|
||||
} else if (unlikely(!kidled_is_scan_target_equal(p))) {
|
||||
|
@ -1078,6 +1084,13 @@ static ssize_t kidled_scan_period_store(struct kobject *kobj,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* To avoid situation like lru_gen >= 0 && kidled disabled, disable
|
||||
* enabled_key after reset.
|
||||
*/
|
||||
if (secs)
|
||||
static_branch_enable(&kidled_enabled_key);
|
||||
|
||||
kidled_set_scan_duration(secs);
|
||||
wake_up_interruptible(&kidled_wait);
|
||||
kidled_slab_scan_enabled();
|
||||
|
|
Loading…
Reference in New Issue