From 009c22bb86b3d6214e48d0e05a1648ebf62d8416 Mon Sep 17 00:00:00 2001 From: Yu Liao Date: Fri, 13 May 2022 08:34:34 +0000 Subject: [PATCH] mm: clear_freelist_page: Provide timeout mechanism for worker runtime hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I558LD CVE: NA -------------------------------- In the case of large memory, the clear freelist will hold zone lock for a long time. As a result, the process may be blocked unless clear freelist thread exit, and causing the system to be reset by the watchdog. Provide a mechanism to stop clear freelist threads when elapsed time exceeds cfp_timeout, which can be set by module_param(). Signed-off-by: Yu Liao Reviewed-by: Kefeng Wang Signed-off-by: Yongqiang Liu --- mm/clear_freelist_page.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mm/clear_freelist_page.c b/mm/clear_freelist_page.c index f0a13b8fdcdb..1ea59a3e527f 100644 --- a/mm/clear_freelist_page.c +++ b/mm/clear_freelist_page.c @@ -13,8 +13,10 @@ #include #include #include +#include #include +#define CFP_DEFAULT_TIMEOUT 2000 #define for_each_populated_zone_pgdat(pgdat, zone) \ for (zone = pgdat->node_zones; \ zone; \ @@ -32,6 +34,7 @@ static DECLARE_WAIT_QUEUE_HEAD(clear_freelist_wait); static DEFINE_MUTEX(clear_freelist_lock); static atomic_t clear_freelist_workers; static atomic_t clear_pages_num; +static ulong cfp_timeout_ms = CFP_DEFAULT_TIMEOUT; static int one = 1; /* @@ -51,15 +54,25 @@ static struct zone *next_pgdat_zone(struct zone *zone) static void clear_pgdat_freelist_pages(struct work_struct *work) { struct pgdat_entry *entry = container_of(work, struct pgdat_entry, work); + u64 cfp_timeout_ns = cfp_timeout_ms * NSEC_PER_MSEC; struct pglist_data *pgdat = entry->pgdat; unsigned long flags, order, t; struct page *page; struct zone *zone; + u64 start, now; + + start = sched_clock(); for_each_populated_zone_pgdat(pgdat, zone) { spin_lock_irqsave(&zone->lock, flags); for_each_migratetype_order(order, t) { list_for_each_entry(page, &zone->free_area[order].free_list[t], lru) { + now = sched_clock(); + if (unlikely(now - start > cfp_timeout_ns)) { + spin_unlock_irqrestore(&zone->lock, flags); + goto out; + } + #ifdef CONFIG_KMAP_LOCAL int i; @@ -77,6 +90,8 @@ static void clear_pgdat_freelist_pages(struct work_struct *work) cond_resched(); } + +out: kfree(entry); if (atomic_dec_and_test(&clear_freelist_workers)) @@ -170,3 +185,4 @@ static int __init clear_freelist_init(void) return 0; } module_init(clear_freelist_init); +module_param(cfp_timeout_ms, ulong, 0644); -- GitLab