From patchwork Mon Apr 10 08:46:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "zhaoyang.huang" X-Patchwork-Id: 81423 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp1762058vqo; Mon, 10 Apr 2023 01:57:02 -0700 (PDT) X-Google-Smtp-Source: AKy350blGLgMTSEThQE1I3XIOZ9MgVX5dXw1SlHhbhtqxa+cd5HF7UL4QrE0bZ6lqS2vm3z+/QKT X-Received: by 2002:a17:90b:3a86:b0:240:3ee4:d2d1 with SMTP id om6-20020a17090b3a8600b002403ee4d2d1mr12599143pjb.13.1681117022115; Mon, 10 Apr 2023 01:57:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1681117022; cv=none; d=google.com; s=arc-20160816; b=Yikzqm7Kp5uSQxtITiGcH2ZbrwRa3CnidncWnLvHUUwm1FFV8Qu8ZmNIs5qZKBku2y ScMjthpZWF3FSHhud5Dnk9W6CaJLd4MU60eCQ/aec1G7QVkUpsZQ0Wy9H433eSmY2bWY Aj4LNKJqJk6A7oMEh36l77PHNCEAcT6VX3pcufzTgvwv41WNIXlQTFSgXsddOcyjIR6x g9JFQrQpZ28zlH3DAWsYCWUrZ6XPhEguBNDqSXHGfkW/9Yvpa+izW3xDmMpsCd0Wyb+z U0sD9lh55WfeDkt5kX5tqkMydx8xgjeuWnqz8CkPlvzRHd6LNi4aUCyjDWuyiIabKRv+ 3zfw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:message-id:date:subject:to:from; bh=RpsPoJZeo3673tgyArEa9y/kXzGIl+uRGEifWWA+y/g=; b=PQSgC4Y5R+6J4cE+MWhxHxHaEJ1LxDdqVm/0KQNCXBaRuvTOYEMu+6k1TVJBkvsYUR XkS3mRguk8uOuvTy54V3VWtXQ2Iq+QaAfiOeUGFYOu1oC4rv4gekW93JsktV+u2JVtTh YG/s22TTNki8ZOhVDFsoYkZjoCO8++dteyW13jHTWtNp4uJFzFXvVMLe3s+nNmN/ikaf 0pSjKi++UABrtBe8zVlxG3hOfOGJ30SSB52tTyzb2v+ctOwkFwm84pORzxy2GlVL0jwa xrvHrWc8GzVPtPR8EDH8aS/VTwBkkPUdvmcELRvw5PpwH/WYcTJAIdFkRrqy1bdM0pxF 6uSA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id 90-20020a17090a0fe300b002466d549574si6501105pjz.26.2023.04.10.01.56.50; Mon, 10 Apr 2023 01:57:02 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229796AbjDJIvs (ORCPT + 99 others); Mon, 10 Apr 2023 04:51:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44512 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229685AbjDJIvq (ORCPT ); Mon, 10 Apr 2023 04:51:46 -0400 Received: from SHSQR01.spreadtrum.com (unknown [222.66.158.135]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7BAF340D9 for ; Mon, 10 Apr 2023 01:51:22 -0700 (PDT) Received: from SHSQR01.spreadtrum.com (localhost [127.0.0.2] (may be forged)) by SHSQR01.spreadtrum.com with ESMTP id 33A8oOjo049296 for ; Mon, 10 Apr 2023 16:50:24 +0800 (+08) (envelope-from zhaoyang.huang@unisoc.com) Received: from SHSend.spreadtrum.com (bjmbx01.spreadtrum.com [10.0.64.7]) by SHSQR01.spreadtrum.com with ESMTP id 33A8krjN036709; Mon, 10 Apr 2023 16:46:53 +0800 (+08) (envelope-from zhaoyang.huang@unisoc.com) Received: from bj03382pcu.spreadtrum.com (10.0.74.65) by BJMBX01.spreadtrum.com (10.0.64.7) with Microsoft SMTP Server (TLS) id 15.0.1497.23; Mon, 10 Apr 2023 16:46:50 +0800 From: "zhaoyang.huang" To: Andrew Morton , Minchan Kim , Joonsoo Kim , , , Zhaoyang Huang , Subject: [RFC PATCHv2] mm: introduce defer free for cma Date: Mon, 10 Apr 2023 16:46:35 +0800 Message-ID: <1681116395-18633-1-git-send-email-zhaoyang.huang@unisoc.com> X-Mailer: git-send-email 1.9.1 MIME-Version: 1.0 X-Originating-IP: [10.0.74.65] X-ClientProxiedBy: SHCAS03.spreadtrum.com (10.0.1.207) To BJMBX01.spreadtrum.com (10.0.64.7) X-MAIL: SHSQR01.spreadtrum.com 33A8krjN036709 X-Spam-Status: No, score=0.0 required=5.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762778962568002994?= X-GMAIL-MSGID: =?utf-8?q?1762778962568002994?= From: Zhaoyang Huang Continues page blocks are expensive for the system. Introducing defer free mechanism to buffer some which make the allocation easier. The shrinker will ensure the page block can be reclaimed when there is memory pressure. Signed-off-by: Zhaoyang Huang --- v2: fix build warning and regist shrinker --- --- mm/cma.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- mm/cma.h | 11 +++++ 2 files changed, 160 insertions(+), 2 deletions(-) diff --git a/mm/cma.c b/mm/cma.c index 4a978e0..6d2fd24 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -39,6 +39,10 @@ unsigned cma_area_count; static DEFINE_MUTEX(cma_mutex); +static unsigned long cma_defer_free_count(struct shrinker *shrinker, + struct shrink_control *sc); +static unsigned long cma_defer_free_scan(struct shrinker *shrinker, + struct shrink_control *sc); phys_addr_t cma_get_base(const struct cma *cma) { return PFN_PHYS(cma->base_pfn); @@ -153,6 +157,20 @@ static int __init cma_init_reserved_areas(void) } core_initcall(cma_init_reserved_areas); +static unsigned long cma_free_get(struct cma *cma) +{ + unsigned long used; + unsigned long val; + + spin_lock_irq(&cma->lock); + /* pages counter is smaller than sizeof(int) */ + used = bitmap_weight(cma->bitmap, (int)cma_bitmap_maxno(cma)); + val = cma->count - ((u64)used << cma->order_per_bit); + spin_unlock_irq(&cma->lock); + + return val; +} + void __init cma_reserve_pages_on_error(struct cma *cma) { cma->reserve_pages_on_error = true; @@ -212,6 +230,13 @@ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, cma_area_count++; totalcma_pages += (size / PAGE_SIZE); + cma->batch = cma->count >> 1; + cma->shrinker.count_objects = cma_defer_free_count; + cma->shrinker.scan_objects = cma_defer_free_scan; + cma->shrinker.seeks = DEFAULT_SEEKS; + cma->shrinker.batch = 0; + + register_shrinker(&cma->shrinker, "cma-shrinker"); return 0; } @@ -411,6 +436,46 @@ static void cma_debug_show_areas(struct cma *cma) static inline void cma_debug_show_areas(struct cma *cma) { } #endif +static int cma_defer_area_fetch(struct cma *cma, unsigned long pfn, + unsigned long count) +{ + struct cma_defer_free_area *area; + unsigned long new_pfn; + int ret = -1; + + if (!atomic64_read(&cma->defer_count)) + return ret; + if (count <= atomic64_read(&cma->defer_count)) { + spin_lock_irq(&cma->lock); + list_for_each_entry(area, &cma->defer_free, list) { + /*area found for given pfn and count*/ + if (pfn >= area->pfn && count <= area->count) { + list_del(&area->list); + /*set bits for allocated pfn*/ + bitmap_set(cma->bitmap, pfn - cma->base_pfn, count); + kfree(area); + atomic64_sub(count, &cma->defer_count); + /*release the rest pfn to cma*/ + if (!list_empty(&cma->defer_free) && (pfn == area->pfn)) { + new_pfn = pfn + count; + cma_release(cma, pfn_to_page(new_pfn), area->count - count); + } + ret = 0; + spin_unlock_irq(&cma->lock); + return ret; + } + } + } + /*no area found, release all to buddy*/ + list_for_each_entry(area, &cma->defer_free, list) { + list_del(&area->list); + free_contig_range(area->pfn, area->count); + cma_clear_bitmap(cma, area->pfn, area->count); + kfree(area); + } + spin_unlock_irq(&cma->lock); + return ret; +} /** * cma_alloc() - allocate pages from contiguous area * @cma: Contiguous memory region for which the allocation is performed. @@ -469,9 +534,11 @@ struct page *cma_alloc(struct cma *cma, unsigned long count, spin_unlock_irq(&cma->lock); pfn = cma->base_pfn + (bitmap_no << cma->order_per_bit); + mutex_lock(&cma_mutex); - ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA, - GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0)); + /*search defer area first*/ + ret = cma_defer_area_fetch(cma, pfn, count) ? alloc_contig_range(pfn, pfn + count, MIGRATE_CMA, + GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0)) : 0; mutex_unlock(&cma_mutex); if (ret == 0) { page = pfn_to_page(pfn); @@ -556,6 +623,8 @@ bool cma_release(struct cma *cma, const struct page *pages, unsigned long count) { unsigned long pfn; + unsigned long flags; + struct cma_defer_free_area *defer_area; if (!cma_pages_valid(cma, pages, count)) return false; @@ -566,6 +635,19 @@ bool cma_release(struct cma *cma, const struct page *pages, VM_BUG_ON(pfn + count > cma->base_pfn + cma->count); + if (atomic64_read(&cma->defer_count) < cma->batch) { + defer_area = kmalloc(sizeof(struct cma_defer_free_area), GFP_KERNEL); + if (defer_area) { + defer_area->pfn = pfn; + defer_area->count = count; + spin_lock_irqsave(&cma->lock, flags); + list_add(&defer_area->list, &cma->defer_free); + atomic64_add(count, &cma->defer_count); + spin_unlock_irqrestore(&cma->lock, flags); + cma_clear_bitmap(cma, pfn, count); + return true; + } + } free_contig_range(pfn, count); cma_clear_bitmap(cma, pfn, count); trace_cma_release(cma->name, pfn, pages, count); @@ -586,3 +668,68 @@ int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data) return 0; } + +static unsigned long cma_defer_free_count(struct shrinker *shrinker, + struct shrink_control *sc) +{ + struct cma *cma = container_of(shrinker, struct cma, shrinker); + unsigned long val; + + val = atomic64_read(&cma->defer_count); + return val; +} + +static unsigned long cma_defer_free_scan(struct shrinker *shrinker, + struct shrink_control *sc) +{ + struct cma *cma = container_of(shrinker, struct cma, shrinker); + unsigned long to_scan; + struct cma_defer_free_area *area; + unsigned long new_pfn; + unsigned long defer_count; + + if (sc->nr_to_scan < cma->batch) + return 0; + + to_scan = cma->batch - sc->nr_to_scan; + defer_count = atomic64_read(&cma->defer_count); + spin_lock_irq(&cma->lock); + + /*large to_scan, free all node*/ + if (to_scan >= defer_count) { + list_for_each_entry(area, &cma->defer_free, list) { + list_del(&area->list); + free_contig_range(area->pfn, area->count); + cma_clear_bitmap(cma, area->pfn, area->count); + kfree(area); + } + atomic64_set(&cma->defer_count, 0); + return defer_count; + } + /*iterate all defer_area*/ + list_for_each_entry(area, &cma->defer_free, list) { + if (to_scan <= area->count) { + list_del(&area->list); + free_contig_range(area->pfn, area->count); + cma_clear_bitmap(cma, area->pfn, area->count); + kfree(area); + atomic64_sub(to_scan, &cma->defer_count); + /*release the rest pfn to cma*/ + if (!list_empty(&cma->defer_free)) { + new_pfn = area->pfn + to_scan; + cma_release(cma, pfn_to_page(new_pfn), area->count - to_scan); + } + break; + } + else { + list_del(&area->list); + free_contig_range(area->pfn, area->count); + cma_clear_bitmap(cma, area->pfn, area->count); + kfree(area); + to_scan = to_scan - atomic64_read(&cma->defer_count); + continue; + } + } + spin_unlock_irq(&cma->lock); + return 0; +} diff --git a/mm/cma.h b/mm/cma.h index 88a0595..e1e3e2f 100644 --- a/mm/cma.h +++ b/mm/cma.h @@ -4,6 +4,7 @@ #include #include +#include struct cma_kobject { struct kobject kobj; @@ -31,6 +32,16 @@ struct cma { struct cma_kobject *cma_kobj; #endif bool reserve_pages_on_error; + struct list_head defer_free; + atomic64_t defer_count; + unsigned long batch; + struct shrinker shrinker; +}; + +struct cma_defer_free_area { + unsigned long pfn; + unsigned long count; + struct list_head list; }; extern struct cma cma_areas[MAX_CMA_AREAS];