From patchwork Fri Aug 23 15:00:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunsheng Lin X-Patchwork-Id: 13775384 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id B65E1C531DC for ; Fri, 23 Aug 2024 15:06:37 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 480AC800A2; Fri, 23 Aug 2024 11:06:37 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 42FD38009A; Fri, 23 Aug 2024 11:06:37 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 28257800A2; Fri, 23 Aug 2024 11:06:37 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0013.hostedemail.com [216.40.44.13]) by kanga.kvack.org (Postfix) with ESMTP id 04C998009A for ; Fri, 23 Aug 2024 11:06:36 -0400 (EDT) Received: from smtpin11.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id 4B4E8161B47 for ; Fri, 23 Aug 2024 15:06:36 +0000 (UTC) X-FDA: 82483836792.11.E3EE9C4 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by imf02.hostedemail.com (Postfix) with ESMTP id BF30A80006 for ; Fri, 23 Aug 2024 15:06:32 +0000 (UTC) Authentication-Results: imf02.hostedemail.com; dkim=none; spf=pass (imf02.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.188 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1724425511; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=iCZB6+2oKichAHsL37xoFdcpBzC+iN5BvIo02aS2kJY=; b=UJ2x8kKRQOXdYYaetYZhJIKTc1F+9JHyKa4ConkVjQxJfMxR62PdhEOL6wpiBVU+5OzcTw Pyf0LvJBEsL4nQFmrXVfFt1gP+qu1VM7AjVse/jv8U8BqSbIG8tyJblNAOrqGKn4GEEXZl WZoxUA3/H47m0c0uHp9DUfoAaQpHM7A= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1724425511; a=rsa-sha256; cv=none; b=EHORG3dBRiOH2ZVI9grvQvlupBJjGNoSzo0t1XVPD64gBiarIZSLE5TgKKJVgpWsfMblYc tMNaeNK3Ni/W8AweDBtSKX0o6AaTQDDN1g4ORPaicZjW5ejrasYmaNcPP8aqtUYCx4dbtl VvyPatMUSbwIxZXcqdHgqJ32udSspqA= ARC-Authentication-Results: i=1; imf02.hostedemail.com; dkim=none; spf=pass (imf02.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.188 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com Received: from mail.maildlp.com (unknown [172.19.163.174]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4Wr3J824CJzhY9y; Fri, 23 Aug 2024 23:04:24 +0800 (CST) Received: from dggpemf200006.china.huawei.com (unknown [7.185.36.61]) by mail.maildlp.com (Postfix) with ESMTPS id DC8ED140390; Fri, 23 Aug 2024 23:06:25 +0800 (CST) Received: from localhost.localdomain (10.90.30.45) by dggpemf200006.china.huawei.com (7.185.36.61) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Fri, 23 Aug 2024 23:06:25 +0800 From: Yunsheng Lin To: , , CC: , , Yunsheng Lin , Alexander Duyck , Andrew Morton , Shuah Khan , , Subject: [PATCH net-next v14 01/11] mm: page_frag: add a test module for page_frag Date: Fri, 23 Aug 2024 23:00:29 +0800 Message-ID: <20240823150040.1567062-2-linyunsheng@huawei.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20240823150040.1567062-1-linyunsheng@huawei.com> References: <20240823150040.1567062-1-linyunsheng@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.90.30.45] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To dggpemf200006.china.huawei.com (7.185.36.61) X-Rspam-User: X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: BF30A80006 X-Stat-Signature: py1scpgrh6frdcxxhwoncuencw5ow56b X-HE-Tag: 1724425592-359225 X-HE-Meta: U2FsdGVkX19u8ictmNNdfZu1w5AprW75WwcbV96TQkWyP0H+nEJaHjkVbo1DYkqroWQxzTywRZj9NiXnB462WwxVY4FlCvbBICasJigTAy6TUMK525xiw3GmauXamQYU9DwsOs4fRe7NkoKWj68S1tVYC4jfqEHrl0ebszX1Oh0kXowSDGb0aCR1VoHY1kOv47f+RvJnlZgE8th6NKBe5K9NpdUC3s+/QkE7fieZDUUEe3xfzNpoQkXoWscYVa9HpKpQBxwp27LuoVRzSUHKTECeXzpgm5nUMMrgd+FSP+yALEFe4CRAGXdR8lrhrGLSTgBSwj+s1TBhXxmmAimXCsquZLfg0a+C3OUNhxLZJOie0hDvFzTEIjzlTeFaKTdAxduO5MLR+2lGcyuxObSvBpaPrhaUgfH0e8e/koO/2kRMi2Kktw0bIZqCJqyoSIKtGBTZU16PMv5EWQ6zjlEtGqTP046bP3yc2QCNuKuJlujmiIDoe/0ZLSEZVZ5v3Vks3i0C6XeQcwvZsopvlT7lQt8Ek7/EyOWv+2dPO/9TolWLHektmQg23jFp7x/whtpwgS7mZxNqNOOd85bN+h6K7NRYWgdeGj7tU8UfZpQPQYZl/6yQmHsUcXZyT4ieO6Gc4fyN67O9WDPfvEZtz5L5LLpq/hCq8yCx6YQfoGf7vTDSi4q060Ou7GEfGz4esD77AE0pYpQqLUp3Lukoypf0f517GllvTRpW+nB6U9eNNmpgfZCmSgAngx4vOROdNVstBNCuyPCOjxJ/ysTXN+ea7G59ROkNnE6ab8n5Y5Clb+PhobMzzxaKBJDPXn9dCVYIRS1akqoaEEBWUzp9bnsIqPQNxsuXLwzrlfv347+Z52dgtrROTbiPb9ASRSnMW7StuCCZD+8HWfLgUHYfDfvSbaO+JyTyyH4hISqad6QubdqHlNqWfy4YzbQ7DGV2xA/gl5j1cv8vmqaGWIJhul+ 0wcARjaM HZ+AAgY3LRx62Tw3YwRTACd0QRFIQAWM3m+k56gYKv4lCGhIsiW363d51NF2sjNcm/mBVAaHsLBbTw40dmqu0cjQA8psVs9Zf348Kb9o+EjIUp4fiQ3Rc3haSDRuJZtkJjdmhMu8Wh+jannhInTny4QAamlpKbBEs2LzrgaHiRmV8S31bSbjisIU/kwT4zDWCXfba8Ww3dn1zQaQyLy076AU+7TwurABv0w71d+CfXBcp74cf+imnKCeOENfp7CvSgnik8RXqvSECeg/ZtdCkayXMFV+L1fOAsM61 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: The testing is done by ensuring that the fragment allocated from a frag_frag_cache instance is pushed into a ptr_ring instance in a kthread binded to a specified cpu, and a kthread binded to a specified cpu will pop the fragment from the ptr_ring and free the fragment. CC: Alexander Duyck Signed-off-by: Yunsheng Lin --- tools/testing/selftests/mm/Makefile | 2 + tools/testing/selftests/mm/page_frag/Makefile | 18 ++ .../selftests/mm/page_frag/page_frag_test.c | 170 ++++++++++++++++++ tools/testing/selftests/mm/run_vmtests.sh | 9 +- 4 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/mm/page_frag/Makefile create mode 100644 tools/testing/selftests/mm/page_frag/page_frag_test.c diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile index 7b8a5def54a1..a21572e81f1d 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -36,6 +36,8 @@ MAKEFLAGS += --no-builtin-rules CFLAGS = -Wall -I $(top_srcdir) $(EXTRA_CFLAGS) $(KHDR_INCLUDES) $(TOOLS_INCLUDES) LDLIBS = -lrt -lpthread -lm +TEST_GEN_MODS_DIR := page_frag + TEST_GEN_FILES = cow TEST_GEN_FILES += compaction_test TEST_GEN_FILES += gup_longterm diff --git a/tools/testing/selftests/mm/page_frag/Makefile b/tools/testing/selftests/mm/page_frag/Makefile new file mode 100644 index 000000000000..58dda74d50a3 --- /dev/null +++ b/tools/testing/selftests/mm/page_frag/Makefile @@ -0,0 +1,18 @@ +PAGE_FRAG_TEST_DIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))) +KDIR ?= $(abspath $(PAGE_FRAG_TEST_DIR)/../../../../..) + +ifeq ($(V),1) +Q = +else +Q = @ +endif + +MODULES = page_frag_test.ko + +obj-m += page_frag_test.o + +all: + +$(Q)make -C $(KDIR) M=$(PAGE_FRAG_TEST_DIR) modules + +clean: + +$(Q)make -C $(KDIR) M=$(PAGE_FRAG_TEST_DIR) clean diff --git a/tools/testing/selftests/mm/page_frag/page_frag_test.c b/tools/testing/selftests/mm/page_frag/page_frag_test.c new file mode 100644 index 000000000000..0e803db1ad79 --- /dev/null +++ b/tools/testing/selftests/mm/page_frag/page_frag_test.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Test module for page_frag cache + * + * Copyright: linyunsheng@huawei.com + */ + +#include +#include +#include +#include +#include +#include + +static struct ptr_ring ptr_ring; +static int nr_objs = 512; +static atomic_t nthreads; +static struct completion wait; +static struct page_frag_cache test_frag; + +static int nr_test = 5120000; +module_param(nr_test, int, 0); +MODULE_PARM_DESC(nr_test, "number of iterations to test"); + +static bool test_align; +module_param(test_align, bool, 0); +MODULE_PARM_DESC(test_align, "use align API for testing"); + +static int test_alloc_len = 2048; +module_param(test_alloc_len, int, 0); +MODULE_PARM_DESC(test_alloc_len, "alloc len for testing"); + +static int test_push_cpu; +module_param(test_push_cpu, int, 0); +MODULE_PARM_DESC(test_push_cpu, "test cpu for pushing fragment"); + +static int test_pop_cpu; +module_param(test_pop_cpu, int, 0); +MODULE_PARM_DESC(test_pop_cpu, "test cpu for popping fragment"); + +static int page_frag_pop_thread(void *arg) +{ + struct ptr_ring *ring = arg; + int nr = nr_test; + + pr_info("page_frag pop test thread begins on cpu %d\n", + smp_processor_id()); + + while (nr > 0) { + void *obj = __ptr_ring_consume(ring); + + if (obj) { + nr--; + page_frag_free(obj); + } else { + cond_resched(); + } + } + + if (atomic_dec_and_test(&nthreads)) + complete(&wait); + + pr_info("page_frag pop test thread exits on cpu %d\n", + smp_processor_id()); + + return 0; +} + +static int page_frag_push_thread(void *arg) +{ + struct ptr_ring *ring = arg; + int nr = nr_test; + + pr_info("page_frag push test thread begins on cpu %d\n", + smp_processor_id()); + + while (nr > 0) { + void *va; + int ret; + + if (test_align) { + va = page_frag_alloc_align(&test_frag, test_alloc_len, + GFP_KERNEL, SMP_CACHE_BYTES); + + WARN_ONCE((unsigned long)va & (SMP_CACHE_BYTES - 1), + "unaligned va returned\n"); + } else { + va = page_frag_alloc(&test_frag, test_alloc_len, GFP_KERNEL); + } + + if (!va) + continue; + + ret = __ptr_ring_produce(ring, va); + if (ret) { + page_frag_free(va); + cond_resched(); + } else { + nr--; + } + } + + pr_info("page_frag push test thread exits on cpu %d\n", + smp_processor_id()); + + if (atomic_dec_and_test(&nthreads)) + complete(&wait); + + return 0; +} + +static int __init page_frag_test_init(void) +{ + struct task_struct *tsk_push, *tsk_pop; + ktime_t start; + u64 duration; + int ret; + + test_frag.va = NULL; + atomic_set(&nthreads, 2); + init_completion(&wait); + + if (test_alloc_len > PAGE_SIZE || test_alloc_len <= 0 || + !cpu_active(test_push_cpu) || !cpu_active(test_pop_cpu)) + return -EINVAL; + + ret = ptr_ring_init(&ptr_ring, nr_objs, GFP_KERNEL); + if (ret) + return ret; + + tsk_push = kthread_create_on_cpu(page_frag_push_thread, &ptr_ring, + test_push_cpu, "page_frag_push"); + if (IS_ERR(tsk_push)) + return PTR_ERR(tsk_push); + + tsk_pop = kthread_create_on_cpu(page_frag_pop_thread, &ptr_ring, + test_pop_cpu, "page_frag_pop"); + if (IS_ERR(tsk_pop)) { + kthread_stop(tsk_push); + return PTR_ERR(tsk_pop); + } + + start = ktime_get(); + wake_up_process(tsk_push); + wake_up_process(tsk_pop); + + pr_info("waiting for test to complete\n"); + wait_for_completion(&wait); + + duration = (u64)ktime_us_delta(ktime_get(), start); + pr_info("%d of iterations for %s testing took: %lluus\n", nr_test, + test_align ? "aligned" : "non-aligned", duration); + + ptr_ring_cleanup(&ptr_ring, NULL); + page_frag_cache_drain(&test_frag); + + return -EAGAIN; +} + +static void __exit page_frag_test_exit(void) +{ +} + +module_init(page_frag_test_init); +module_exit(page_frag_test_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Yunsheng Lin "); +MODULE_DESCRIPTION("Test module for page_frag"); diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh index 03ac4f2e1cce..3636d984b786 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -75,6 +75,8 @@ separated by spaces: read-only VMAs - mdwe test prctl(PR_SET_MDWE, ...) +- page_frag + test handling of page fragment allocation and freeing example: ./run_vmtests.sh -t "hmm mmap ksm" EOF @@ -231,7 +233,8 @@ run_test() { ("$@" 2>&1) | tap_prefix local ret=${PIPESTATUS[0]} count_total=$(( count_total + 1 )) - if [ $ret -eq 0 ]; then + # page_frag_test.ko returns 11(EAGAIN) when insmod'ing to avoid rmmod + if [ $ret -eq 0 ] | [ $ret -eq 11 -a ${CATEGORY} == "page_frag" ]; then count_pass=$(( count_pass + 1 )) echo "[PASS]" | tap_prefix echo "ok ${count_total} ${test}" | tap_output @@ -453,6 +456,10 @@ CATEGORY="mkdirty" run_test ./mkdirty CATEGORY="mdwe" run_test ./mdwe_test +CATEGORY="page_frag" run_test insmod ./page_frag/page_frag_test.ko + +CATEGORY="page_frag" run_test insmod ./page_frag/page_frag_test.ko test_alloc_len=12 test_align=1 + echo "SUMMARY: PASS=${count_pass} SKIP=${count_skip} FAIL=${count_fail}" | tap_prefix echo "1..${count_total}" | tap_output From patchwork Fri Aug 23 15:00:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunsheng Lin X-Patchwork-Id: 13775386 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4CCF3C5321D for ; Fri, 23 Aug 2024 15:06:43 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id CBE658009A; Fri, 23 Aug 2024 11:06:42 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id BD0766B020A; Fri, 23 Aug 2024 11:06:42 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A247F8009A; Fri, 23 Aug 2024 11:06:42 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id 7C93F6B0204 for ; Fri, 23 Aug 2024 11:06:42 -0400 (EDT) Received: from smtpin23.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id F1A8041A68 for ; Fri, 23 Aug 2024 15:06:41 +0000 (UTC) X-FDA: 82483837002.23.4B594C2 Received: from szxga05-in.huawei.com (szxga05-in.huawei.com [45.249.212.191]) by imf18.hostedemail.com (Postfix) with ESMTP id 575021C001D for ; Fri, 23 Aug 2024 15:06:37 +0000 (UTC) Authentication-Results: imf18.hostedemail.com; dkim=none; spf=pass (imf18.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.191 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1724425516; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9cC01kgWstQUcZmaHYdkI+DDc8yFSslsPMD9o/pLIZo=; b=SfSBHEgXnTZRt6N9J8dCH88EepnFStJ1/nKw3aeMfI3zs1VZt2oUNDaPdA+hyn5IuA9k6i bu8uUtEQHZ7y2RbhVmgTuA92jh0qulx7BOmsIbkimkyl2+m8s9m+awRoVjcbNjrEIxaNPT wSnA9wO12FEw9ERELeRUHY+RAG3vH+w= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1724425516; a=rsa-sha256; cv=none; b=L2uIczvei8qxa9iVXHvfObML2yjmeWcrzwhsNstW2ErtaLFfBhCUT3vL1g+IP+Bn8m0YUU uiz3AI8cqR0zqXgJwikc0xhXA47lnmYpZ3f/MXWpPebM8B/6hNt+9uBwQZeJVrMrCzWOsb Qb0uU6j184jo1x/xa5BeqgTdnb6nGvg= ARC-Authentication-Results: i=1; imf18.hostedemail.com; dkim=none; spf=pass (imf18.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.191 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com Received: from mail.maildlp.com (unknown [172.19.88.234]) by szxga05-in.huawei.com (SkyGuard) with ESMTP id 4Wr3Gt5RZXz1HH3R; Fri, 23 Aug 2024 23:03:18 +0800 (CST) Received: from dggpemf200006.china.huawei.com (unknown [7.185.36.61]) by mail.maildlp.com (Postfix) with ESMTPS id AD72D1402E1; Fri, 23 Aug 2024 23:06:29 +0800 (CST) Received: from localhost.localdomain (10.90.30.45) by dggpemf200006.china.huawei.com (7.185.36.61) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Fri, 23 Aug 2024 23:06:29 +0800 From: Yunsheng Lin To: , , CC: , , Yunsheng Lin , David Howells , Alexander Duyck , Andrew Morton , Eric Dumazet , Shuah Khan , , Subject: [PATCH net-next v14 02/11] mm: move the page fragment allocator from page_alloc into its own file Date: Fri, 23 Aug 2024 23:00:30 +0800 Message-ID: <20240823150040.1567062-3-linyunsheng@huawei.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20240823150040.1567062-1-linyunsheng@huawei.com> References: <20240823150040.1567062-1-linyunsheng@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.90.30.45] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To dggpemf200006.china.huawei.com (7.185.36.61) X-Stat-Signature: tgwixntf7b8d8tnujeabh1ffwix7ya1g X-Rspamd-Queue-Id: 575021C001D X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1724425597-716977 X-HE-Meta: U2FsdGVkX1+4a5AoY7rwO0JjmKGOYvMG4xvsrq3jUeq4fTtKpcKmD0ei99V4d61+TF94R+21Yvn07QT1vhRx9QhvAtD/33Rwcq2iYW1uwwbB+OJ8mSYSyVQU1UK8FVeRMtMR8yiRQFJpqFxmBt9R58MqleLZJSv53KU6MtKSSScEDDzJ/FlBwIrQDhYbS2NnhyojDYZHKO7hSdonHQJk6HF+YBp9SeFFZBF6aTqYQfgdX2Pig6y13OcpCneS1PTCLIrXLqyFPuWpCuoRuwT8CIaXTAamsyaGOj2CT/fCCF8jDHbUtc5Jl+UJrj59PGVdGd7Lpw5LeDEHh7rHoLahh17rP7mOO1R3zCDxaanI30WnK6RQTYbVIrbH7sAMjqiVYkmYg1of1DUq3UV84gLSz24MvRtsq/uBtrHJpSYvsZM7aHCOYT3BldWte2GtEn+87kyBn0SLKeQpHuIPGodCT+Zgm/XWhS50QH8LiWFltLcwz8oJEeAXIOwtIp3F8hQwEbon3oVGsTYqxTJCZM6DS9irvNQv+SqMyn84GJMx6+0GJ4utdksV5Wp+AA35C539MTTaOWXKwMuK0Gdk6vukOUetBtGlEaU4ae9IjmDtVanfx3zV3+xWOHQ01+c0OnE6cYdnxt1yn8kZIgMI2oVYOmgtgJEKMXTglfmL6kNIqq8+zMrhVpRk3Vyi2MkdnlBktkPdmsn00VIvDm3hwzWZDcBRypmJxGXJ2pC/FgtTrQj0VsyE6KyZvKufMo91xRdeG78uSH/Ykac+qkmWeBM/IyZpZGuc9DtPlw4xbAMMFZAph6xJdED+gSvar9xeFNbe9muFjIVq07ef4NDJIw2EPMfmkLw637Dbs4POPuH//i1crNMJYQ2amcICn9zOjTC9pR3JgjgzNmcVRnb9IkSIt4lvHo84nix769698pbzrLdq7eBuKJV7//kbrAAhckbjIjd4rumksBcdrYeQwcn rjfIpCzQ VwVvY+6qZJVV8+3US/i7vN8rkBwHJrdtH9Zq/Zv6GwdO/xS0dEqMVhVCnsG2cIAYDqonGXQY8c2b11E9TYeKRx83fyYG8/Fa7dM0rL4nRWSkR4oXoTnEIsmmsL+hp+fTf3wq8VoHjDJQKsI6JjsyTOnCbHu1ct0dz/2EvppHEc2UQqc2Stcm/R/VK20cRR3SsdDOAX3C3Z/HlwXJkTSaMN7NYtd0ys4udsL03iC5P8SWmOaUBmhRPfnB0CMLAFz0PiqKmmM+9IRLW5FAzGxec793k1pBILHuBCDYdawiol7iUGNkgcE+Ro8unifMIHpv3PIYUEt+5XsfIYOu9JymN6BkxhMTRdTkgKnr/aBRv2h8C5mC+4jTQde98ChxUPKGiTn7FGQAk5VXKFTn36qADvWKNW6X8eHdwhXZ8wrxReACGei0= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Inspired by [1], move the page fragment allocator from page_alloc into its own c file and header file, as we are about to make more change for it to replace another page_frag implementation in sock.c As this patchset is going to replace 'struct page_frag' with 'struct page_frag_cache' in sched.h, including page_frag_cache.h in sched.h has a compiler error caused by interdependence between mm_types.h and mm.h for asm-offsets.c, see [2]. So avoid the compiler error by moving 'struct page_frag_cache' to mm_types_task.h as suggested by Alexander, see [3]. 1. https://lore.kernel.org/all/20230411160902.4134381-3-dhowells@redhat.com/ 2. https://lore.kernel.org/all/15623dac-9358-4597-b3ee-3694a5956920@gmail.com/ 3. https://lore.kernel.org/all/CAKgT0UdH1yD=LSCXFJ=YM_aiA4OomD-2wXykO42bizaWMt_HOA@mail.gmail.com/ CC: David Howells CC: Alexander Duyck Signed-off-by: Yunsheng Lin Acked-by: Andrew Morton --- include/linux/gfp.h | 22 --- include/linux/mm_types.h | 18 --- include/linux/mm_types_task.h | 18 +++ include/linux/page_frag_cache.h | 31 ++++ include/linux/skbuff.h | 1 + mm/Makefile | 1 + mm/page_alloc.c | 136 ---------------- mm/page_frag_cache.c | 145 ++++++++++++++++++ .../selftests/mm/page_frag/page_frag_test.c | 2 +- 9 files changed, 197 insertions(+), 177 deletions(-) create mode 100644 include/linux/page_frag_cache.h create mode 100644 mm/page_frag_cache.c diff --git a/include/linux/gfp.h b/include/linux/gfp.h index f53f76e0b17e..01a49be7c98d 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -371,28 +371,6 @@ __meminit void *alloc_pages_exact_nid_noprof(int nid, size_t size, gfp_t gfp_mas extern void __free_pages(struct page *page, unsigned int order); extern void free_pages(unsigned long addr, unsigned int order); -struct page_frag_cache; -void page_frag_cache_drain(struct page_frag_cache *nc); -extern void __page_frag_cache_drain(struct page *page, unsigned int count); -void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz, - gfp_t gfp_mask, unsigned int align_mask); - -static inline void *page_frag_alloc_align(struct page_frag_cache *nc, - unsigned int fragsz, gfp_t gfp_mask, - unsigned int align) -{ - WARN_ON_ONCE(!is_power_of_2(align)); - return __page_frag_alloc_align(nc, fragsz, gfp_mask, -align); -} - -static inline void *page_frag_alloc(struct page_frag_cache *nc, - unsigned int fragsz, gfp_t gfp_mask) -{ - return __page_frag_alloc_align(nc, fragsz, gfp_mask, ~0u); -} - -extern void page_frag_free(void *addr); - #define __free_page(page) __free_pages((page), 0) #define free_page(addr) free_pages((addr), 0) diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 485424979254..843d75412105 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -521,9 +521,6 @@ static_assert(sizeof(struct ptdesc) <= sizeof(struct page)); */ #define STRUCT_PAGE_MAX_SHIFT (order_base_2(sizeof(struct page))) -#define PAGE_FRAG_CACHE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK) -#define PAGE_FRAG_CACHE_MAX_ORDER get_order(PAGE_FRAG_CACHE_MAX_SIZE) - /* * page_private can be used on tail pages. However, PagePrivate is only * checked by the VM on the head page. So page_private on the tail pages @@ -542,21 +539,6 @@ static inline void *folio_get_private(struct folio *folio) return folio->private; } -struct page_frag_cache { - void * va; -#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) - __u16 offset; - __u16 size; -#else - __u32 offset; -#endif - /* we maintain a pagecount bias, so that we dont dirty cache line - * containing page->_refcount every time we allocate a fragment. - */ - unsigned int pagecnt_bias; - bool pfmemalloc; -}; - typedef unsigned long vm_flags_t; /* diff --git a/include/linux/mm_types_task.h b/include/linux/mm_types_task.h index a2f6179b672b..cdc1e3696439 100644 --- a/include/linux/mm_types_task.h +++ b/include/linux/mm_types_task.h @@ -8,6 +8,7 @@ * (These are defined separately to decouple sched.h from mm_types.h as much as possible.) */ +#include #include #include @@ -46,6 +47,23 @@ struct page_frag { #endif }; +#define PAGE_FRAG_CACHE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK) +#define PAGE_FRAG_CACHE_MAX_ORDER get_order(PAGE_FRAG_CACHE_MAX_SIZE) +struct page_frag_cache { + void *va; +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) + __u16 offset; + __u16 size; +#else + __u32 offset; +#endif + /* we maintain a pagecount bias, so that we dont dirty cache line + * containing page->_refcount every time we allocate a fragment. + */ + unsigned int pagecnt_bias; + bool pfmemalloc; +}; + /* Track pages that require TLB flushes */ struct tlbflush_unmap_batch { #ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH diff --git a/include/linux/page_frag_cache.h b/include/linux/page_frag_cache.h new file mode 100644 index 000000000000..67ac8626ed9b --- /dev/null +++ b/include/linux/page_frag_cache.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _LINUX_PAGE_FRAG_CACHE_H +#define _LINUX_PAGE_FRAG_CACHE_H + +#include +#include +#include + +void page_frag_cache_drain(struct page_frag_cache *nc); +void __page_frag_cache_drain(struct page *page, unsigned int count); +void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz, + gfp_t gfp_mask, unsigned int align_mask); + +static inline void *page_frag_alloc_align(struct page_frag_cache *nc, + unsigned int fragsz, gfp_t gfp_mask, + unsigned int align) +{ + WARN_ON_ONCE(!is_power_of_2(align)); + return __page_frag_alloc_align(nc, fragsz, gfp_mask, -align); +} + +static inline void *page_frag_alloc(struct page_frag_cache *nc, + unsigned int fragsz, gfp_t gfp_mask) +{ + return __page_frag_alloc_align(nc, fragsz, gfp_mask, ~0u); +} + +void page_frag_free(void *addr); + +#endif diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index cf8f6ce06742..7482997c719f 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #if IS_ENABLED(CONFIG_NF_CONNTRACK) #include diff --git a/mm/Makefile b/mm/Makefile index d2915f8c9dc0..e9d342fa8058 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -65,6 +65,7 @@ page-alloc-$(CONFIG_SHUFFLE_PAGE_ALLOCATOR) += shuffle.o memory-hotplug-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o obj-y += page-alloc.o +obj-y += page_frag_cache.o obj-y += init-mm.o obj-y += memblock.o obj-y += $(memory-hotplug-y) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 28f80daf5c04..7e830613da1b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4803,142 +4803,6 @@ void free_pages(unsigned long addr, unsigned int order) EXPORT_SYMBOL(free_pages); -/* - * Page Fragment: - * An arbitrary-length arbitrary-offset area of memory which resides - * within a 0 or higher order page. Multiple fragments within that page - * are individually refcounted, in the page's reference counter. - * - * The page_frag functions below provide a simple allocation framework for - * page fragments. This is used by the network stack and network device - * drivers to provide a backing region of memory for use as either an - * sk_buff->head, or to be used in the "frags" portion of skb_shared_info. - */ -static struct page *__page_frag_cache_refill(struct page_frag_cache *nc, - gfp_t gfp_mask) -{ - struct page *page = NULL; - gfp_t gfp = gfp_mask; - -#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) - gfp_mask = (gfp_mask & ~__GFP_DIRECT_RECLAIM) | __GFP_COMP | - __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC; - page = alloc_pages_node(NUMA_NO_NODE, gfp_mask, - PAGE_FRAG_CACHE_MAX_ORDER); - nc->size = page ? PAGE_FRAG_CACHE_MAX_SIZE : PAGE_SIZE; -#endif - if (unlikely(!page)) - page = alloc_pages_node(NUMA_NO_NODE, gfp, 0); - - nc->va = page ? page_address(page) : NULL; - - return page; -} - -void page_frag_cache_drain(struct page_frag_cache *nc) -{ - if (!nc->va) - return; - - __page_frag_cache_drain(virt_to_head_page(nc->va), nc->pagecnt_bias); - nc->va = NULL; -} -EXPORT_SYMBOL(page_frag_cache_drain); - -void __page_frag_cache_drain(struct page *page, unsigned int count) -{ - VM_BUG_ON_PAGE(page_ref_count(page) == 0, page); - - if (page_ref_sub_and_test(page, count)) - free_unref_page(page, compound_order(page)); -} -EXPORT_SYMBOL(__page_frag_cache_drain); - -void *__page_frag_alloc_align(struct page_frag_cache *nc, - unsigned int fragsz, gfp_t gfp_mask, - unsigned int align_mask) -{ - unsigned int size = PAGE_SIZE; - struct page *page; - int offset; - - if (unlikely(!nc->va)) { -refill: - page = __page_frag_cache_refill(nc, gfp_mask); - if (!page) - return NULL; - -#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) - /* if size can vary use size else just use PAGE_SIZE */ - size = nc->size; -#endif - /* Even if we own the page, we do not use atomic_set(). - * This would break get_page_unless_zero() users. - */ - page_ref_add(page, PAGE_FRAG_CACHE_MAX_SIZE); - - /* reset page count bias and offset to start of new frag */ - nc->pfmemalloc = page_is_pfmemalloc(page); - nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1; - nc->offset = size; - } - - offset = nc->offset - fragsz; - if (unlikely(offset < 0)) { - page = virt_to_page(nc->va); - - if (!page_ref_sub_and_test(page, nc->pagecnt_bias)) - goto refill; - - if (unlikely(nc->pfmemalloc)) { - free_unref_page(page, compound_order(page)); - goto refill; - } - -#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) - /* if size can vary use size else just use PAGE_SIZE */ - size = nc->size; -#endif - /* OK, page count is 0, we can safely set it */ - set_page_count(page, PAGE_FRAG_CACHE_MAX_SIZE + 1); - - /* reset page count bias and offset to start of new frag */ - nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1; - offset = size - fragsz; - if (unlikely(offset < 0)) { - /* - * The caller is trying to allocate a fragment - * with fragsz > PAGE_SIZE but the cache isn't big - * enough to satisfy the request, this may - * happen in low memory conditions. - * We don't release the cache page because - * it could make memory pressure worse - * so we simply return NULL here. - */ - return NULL; - } - } - - nc->pagecnt_bias--; - offset &= align_mask; - nc->offset = offset; - - return nc->va + offset; -} -EXPORT_SYMBOL(__page_frag_alloc_align); - -/* - * Frees a page fragment allocated out of either a compound or order 0 page. - */ -void page_frag_free(void *addr) -{ - struct page *page = virt_to_head_page(addr); - - if (unlikely(put_page_testzero(page))) - free_unref_page(page, compound_order(page)); -} -EXPORT_SYMBOL(page_frag_free); - static void *make_alloc_exact(unsigned long addr, unsigned int order, size_t size) { diff --git a/mm/page_frag_cache.c b/mm/page_frag_cache.c new file mode 100644 index 000000000000..609a485cd02a --- /dev/null +++ b/mm/page_frag_cache.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Page fragment allocator + * + * Page Fragment: + * An arbitrary-length arbitrary-offset area of memory which resides within a + * 0 or higher order page. Multiple fragments within that page are + * individually refcounted, in the page's reference counter. + * + * The page_frag functions provide a simple allocation framework for page + * fragments. This is used by the network stack and network device drivers to + * provide a backing region of memory for use as either an sk_buff->head, or to + * be used in the "frags" portion of skb_shared_info. + */ + +#include +#include +#include +#include +#include +#include "internal.h" + +static struct page *__page_frag_cache_refill(struct page_frag_cache *nc, + gfp_t gfp_mask) +{ + struct page *page = NULL; + gfp_t gfp = gfp_mask; + +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) + gfp_mask = (gfp_mask & ~__GFP_DIRECT_RECLAIM) | __GFP_COMP | + __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC; + page = alloc_pages_node(NUMA_NO_NODE, gfp_mask, + PAGE_FRAG_CACHE_MAX_ORDER); + nc->size = page ? PAGE_FRAG_CACHE_MAX_SIZE : PAGE_SIZE; +#endif + if (unlikely(!page)) + page = alloc_pages_node(NUMA_NO_NODE, gfp, 0); + + nc->va = page ? page_address(page) : NULL; + + return page; +} + +void page_frag_cache_drain(struct page_frag_cache *nc) +{ + if (!nc->va) + return; + + __page_frag_cache_drain(virt_to_head_page(nc->va), nc->pagecnt_bias); + nc->va = NULL; +} +EXPORT_SYMBOL(page_frag_cache_drain); + +void __page_frag_cache_drain(struct page *page, unsigned int count) +{ + VM_BUG_ON_PAGE(page_ref_count(page) == 0, page); + + if (page_ref_sub_and_test(page, count)) + free_unref_page(page, compound_order(page)); +} +EXPORT_SYMBOL(__page_frag_cache_drain); + +void *__page_frag_alloc_align(struct page_frag_cache *nc, + unsigned int fragsz, gfp_t gfp_mask, + unsigned int align_mask) +{ + unsigned int size = PAGE_SIZE; + struct page *page; + int offset; + + if (unlikely(!nc->va)) { +refill: + page = __page_frag_cache_refill(nc, gfp_mask); + if (!page) + return NULL; + +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) + /* if size can vary use size else just use PAGE_SIZE */ + size = nc->size; +#endif + /* Even if we own the page, we do not use atomic_set(). + * This would break get_page_unless_zero() users. + */ + page_ref_add(page, PAGE_FRAG_CACHE_MAX_SIZE); + + /* reset page count bias and offset to start of new frag */ + nc->pfmemalloc = page_is_pfmemalloc(page); + nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1; + nc->offset = size; + } + + offset = nc->offset - fragsz; + if (unlikely(offset < 0)) { + page = virt_to_page(nc->va); + + if (!page_ref_sub_and_test(page, nc->pagecnt_bias)) + goto refill; + + if (unlikely(nc->pfmemalloc)) { + free_unref_page(page, compound_order(page)); + goto refill; + } + +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) + /* if size can vary use size else just use PAGE_SIZE */ + size = nc->size; +#endif + /* OK, page count is 0, we can safely set it */ + set_page_count(page, PAGE_FRAG_CACHE_MAX_SIZE + 1); + + /* reset page count bias and offset to start of new frag */ + nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1; + offset = size - fragsz; + if (unlikely(offset < 0)) { + /* + * The caller is trying to allocate a fragment + * with fragsz > PAGE_SIZE but the cache isn't big + * enough to satisfy the request, this may + * happen in low memory conditions. + * We don't release the cache page because + * it could make memory pressure worse + * so we simply return NULL here. + */ + return NULL; + } + } + + nc->pagecnt_bias--; + offset &= align_mask; + nc->offset = offset; + + return nc->va + offset; +} +EXPORT_SYMBOL(__page_frag_alloc_align); + +/* + * Frees a page fragment allocated out of either a compound or order 0 page. + */ +void page_frag_free(void *addr) +{ + struct page *page = virt_to_head_page(addr); + + if (unlikely(put_page_testzero(page))) + free_unref_page(page, compound_order(page)); +} +EXPORT_SYMBOL(page_frag_free); diff --git a/tools/testing/selftests/mm/page_frag/page_frag_test.c b/tools/testing/selftests/mm/page_frag/page_frag_test.c index 0e803db1ad79..4a009122991e 100644 --- a/tools/testing/selftests/mm/page_frag/page_frag_test.c +++ b/tools/testing/selftests/mm/page_frag/page_frag_test.c @@ -6,12 +6,12 @@ * Copyright: linyunsheng@huawei.com */ -#include #include #include #include #include #include +#include static struct ptr_ring ptr_ring; static int nr_objs = 512; From patchwork Fri Aug 23 15:00:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunsheng Lin X-Patchwork-Id: 13775385 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4A564C52D7C for ; Fri, 23 Aug 2024 15:06:41 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id B36B7800A3; Fri, 23 Aug 2024 11:06:40 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id AE64C8009A; Fri, 23 Aug 2024 11:06:40 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 9AE16800A3; Fri, 23 Aug 2024 11:06:40 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 7E2628009A for ; Fri, 23 Aug 2024 11:06:40 -0400 (EDT) Received: from smtpin11.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 359241C4B68 for ; Fri, 23 Aug 2024 15:06:40 +0000 (UTC) X-FDA: 82483836960.11.EB92121 Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) by imf20.hostedemail.com (Postfix) with ESMTP id A65861C0028 for ; Fri, 23 Aug 2024 15:06:36 +0000 (UTC) Authentication-Results: imf20.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf20.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.187 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1724425530; a=rsa-sha256; cv=none; b=IUgOfk6avBQml0Eb/Je2jFwBPwJP78YNm55dKvhdZMI55MKycJkQzW4ihW2GfV37HnlAMa 6pjx0R9SjvixwjF/BjDLgyCMGJZVuoUPQJfhrmtYdj7aAi4GZUrEsclDIuwr1A72D3Ecx4 4WYIJhIEQlM0nenpoj9OotIsFFjLz+Q= ARC-Authentication-Results: i=1; imf20.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf20.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.187 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1724425530; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kPIYPG/OrE/t2+FUNllMox/LOqC+P4YoIlou5mKg7a8=; b=1F3qEeiEixeBi82tYirsI6u1RGVGGThNAh4Y2uzWuWhRwwoIml9ilgwMQW/beBRNuGR7Du ewRq44CxcI7VirFsof+AyZKqlcbI6QYeR7mXCt2yRehpxU3kAsNARFB2TbUtsfmQairJp6 iYXfH//la2ir8HxdOzET0NReCgsIVig= Received: from mail.maildlp.com (unknown [172.19.88.194]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4Wr3L63s6TzyR7y; Fri, 23 Aug 2024 23:06:06 +0800 (CST) Received: from dggpemf200006.china.huawei.com (unknown [7.185.36.61]) by mail.maildlp.com (Postfix) with ESMTPS id 8F347140133; Fri, 23 Aug 2024 23:06:31 +0800 (CST) Received: from localhost.localdomain (10.90.30.45) by dggpemf200006.china.huawei.com (7.185.36.61) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Fri, 23 Aug 2024 23:06:31 +0800 From: Yunsheng Lin To: , , CC: , , Yunsheng Lin , Alexander Duyck , Andrew Morton , Subject: [PATCH net-next v14 03/11] mm: page_frag: use initial zero offset for page_frag_alloc_align() Date: Fri, 23 Aug 2024 23:00:31 +0800 Message-ID: <20240823150040.1567062-4-linyunsheng@huawei.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20240823150040.1567062-1-linyunsheng@huawei.com> References: <20240823150040.1567062-1-linyunsheng@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.90.30.45] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To dggpemf200006.china.huawei.com (7.185.36.61) X-Rspamd-Server: rspam12 X-Rspamd-Queue-Id: A65861C0028 X-Stat-Signature: 7soa3tyewoz4yfnej1d3wjgnfyyo7bow X-Rspam-User: X-HE-Tag: 1724425596-986135 X-HE-Meta: U2FsdGVkX1+MvlO5mOXE1G68uJnZARaJ2bvTg7fmldZJ2Q/1YYZAdo/XAn96vFJTUdonz4nOMh8z2a34orD520w3zis/jcZSsOpOlLTcPIN5hLOf2GpWXNJZxnoIbROmrIaz6mug/v1h1CWmT4P0pYVjGZ16Ypvn+oPy7G5kz4VQ/z21j0BhunDmUJ023retribqrB8YkzC9haBpVKBTYLONayO8t3bfjRVa9idLidqR0I631D40ZJOyBPNowOgWNRiRTIT30T89B9vhu45yaOsMPrt/C+i15jLeA6klOaNQeUcEKDCqnam/7CSuDgYDIAiIwcGNqs6/Z6lB42PkKVYBW3IdUaE4LWrVmN0f2M6lKZ1rEsf+QeJ7CqhzVSvbFysDWzCPzleL9hnKl7sNRhhgsaxe/yMhwZl4rLd1+geEgnssNF/sYEmZrQq3ynI8oTQhZXeqqxeOLIr1KCpZHcsiIq7/A6roRXMnHuRu+mXy3WpWL3WpCPProIiPNB0M/G6xCTZAs0b6ClRXb5te8WJbPkdDZboDGqIPwisFmIC7nif+F/nsyXsMiagDtjlvS8QRs7R4egtyouHVYo5VynNXTVWqSsxIvleznRd8JIRbBHIFFWjISXsOsi/LqVtvkwkJEPyt7Kv/V7RqAFUuDHN1v7duIzMalwdI1YR81aANGidyjwAx+lxaVOPsDpp5NoyGwBj8xEebIj4ChoyL5FEn8xWUQrhlTUOJ0htFR492NuYveBLMZ7j7BK7izwQKgEZmSy4xJRI32PCWHUYN9g2TLpxRZhlBXgVhtQotf7Ad9IzHp+2MeC78DYkiJPGqR8ep/cONadLY6sEQLSYx1IX8IPt6PECHv6QnTZLk785M28wBLtyU2Bdv+/V+7L+QL9mFd45PG8G1LvAQgocnayu0W4ckmcC3VroCyX1Xq0VS6Cl3Gp+hUloQQ29Xc8GUyKg2mNpIVzGfZKkCo4H PahbFEfw Dm7focbta++gkU0mAFJhD1yGZD22cf78AEKo+Z0UCsGBfnwqYj5WinJtKnGwpZDQkZ98yoFp0R2zG7DD81Ucp9VxuJGmIdJvYUug7P1+GhVzu4KtlkJD6qZ9vw23N9MEsifOdrVt03264H76pdZaIXRyqSl0Ht4G5t4hZs05OxYrKWddLmz9FDb2Ur+doVmqevCRVuCmyTNL6xJ89KBHfPBLuchvKsVifLdC8RoNuIqX1M9AoSWwp448Ckp2q+erEG9imZjHIuoxeWYzZaWp9PWXU9qHlaqKZpgokijiUQX6lSRfa+ZXDuFm417NJgP7SUBAeYlHkv3Ie5ZbBqVbYbOK1cQ== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: We are about to use page_frag_alloc_*() API to not just allocate memory for skb->data, but also use them to do the memory allocation for skb frag too. Currently the implementation of page_frag in mm subsystem is running the offset as a countdown rather than count-up value, there may have several advantages to that as mentioned in [1], but it may have some disadvantages, for example, it may disable skb frag coalescing and more correct cache prefetching We have a trade-off to make in order to have a unified implementation and API for page_frag, so use a initial zero offset in this patch, and the following patch will try to make some optimization to avoid the disadvantages as much as possible. 1. https://lore.kernel.org/all/f4abe71b3439b39d17a6fb2d410180f367cadf5c.camel@gmail.com/ CC: Alexander Duyck Signed-off-by: Yunsheng Lin --- mm/page_frag_cache.c | 46 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/mm/page_frag_cache.c b/mm/page_frag_cache.c index 609a485cd02a..4c8e04379cb3 100644 --- a/mm/page_frag_cache.c +++ b/mm/page_frag_cache.c @@ -63,9 +63,13 @@ void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask, unsigned int align_mask) { +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) + unsigned int size = nc->size; +#else unsigned int size = PAGE_SIZE; +#endif + unsigned int offset; struct page *page; - int offset; if (unlikely(!nc->va)) { refill: @@ -85,11 +89,24 @@ void *__page_frag_alloc_align(struct page_frag_cache *nc, /* reset page count bias and offset to start of new frag */ nc->pfmemalloc = page_is_pfmemalloc(page); nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1; - nc->offset = size; + nc->offset = 0; } - offset = nc->offset - fragsz; - if (unlikely(offset < 0)) { + offset = __ALIGN_KERNEL_MASK(nc->offset, ~align_mask); + if (unlikely(offset + fragsz > size)) { + if (unlikely(fragsz > PAGE_SIZE)) { + /* + * The caller is trying to allocate a fragment + * with fragsz > PAGE_SIZE but the cache isn't big + * enough to satisfy the request, this may + * happen in low memory conditions. + * We don't release the cache page because + * it could make memory pressure worse + * so we simply return NULL here. + */ + return NULL; + } + page = virt_to_page(nc->va); if (!page_ref_sub_and_test(page, nc->pagecnt_bias)) @@ -100,33 +117,16 @@ void *__page_frag_alloc_align(struct page_frag_cache *nc, goto refill; } -#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) - /* if size can vary use size else just use PAGE_SIZE */ - size = nc->size; -#endif /* OK, page count is 0, we can safely set it */ set_page_count(page, PAGE_FRAG_CACHE_MAX_SIZE + 1); /* reset page count bias and offset to start of new frag */ nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1; - offset = size - fragsz; - if (unlikely(offset < 0)) { - /* - * The caller is trying to allocate a fragment - * with fragsz > PAGE_SIZE but the cache isn't big - * enough to satisfy the request, this may - * happen in low memory conditions. - * We don't release the cache page because - * it could make memory pressure worse - * so we simply return NULL here. - */ - return NULL; - } + offset = 0; } nc->pagecnt_bias--; - offset &= align_mask; - nc->offset = offset; + nc->offset = offset + fragsz; return nc->va + offset; } From patchwork Fri Aug 23 15:00:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunsheng Lin X-Patchwork-Id: 13775387 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3A464C52D7C for ; Fri, 23 Aug 2024 15:06:52 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id C6E95800A5; Fri, 23 Aug 2024 11:06:51 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id C1F28800A4; Fri, 23 Aug 2024 11:06:51 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id B34A4800A5; Fri, 23 Aug 2024 11:06:51 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id 95E13800A4 for ; Fri, 23 Aug 2024 11:06:51 -0400 (EDT) Received: from smtpin21.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay09.hostedemail.com (Postfix) with ESMTP id 5703F81A47 for ; Fri, 23 Aug 2024 15:06:51 +0000 (UTC) X-FDA: 82483837422.21.2BBC79A Received: from szxga03-in.huawei.com (szxga03-in.huawei.com [45.249.212.189]) by imf26.hostedemail.com (Postfix) with ESMTP id 6B5C514001A for ; Fri, 23 Aug 2024 15:06:47 +0000 (UTC) Authentication-Results: imf26.hostedemail.com; dkim=none; spf=pass (imf26.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.189 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1724425567; a=rsa-sha256; cv=none; b=AkEr+5MpxG9MbdxJUR2YBEB8vH45+yuWysyIEqD4y+FBh6DjxcOcfDg8V/HmbN7dsSjpvM ZiarMsBjEJG3uLzY0iD0fWhtvnL/WvprreyPj7Gy+0FksC+Jcj+tzXlDB5/vRGSL3Pmw/v knbANXFLiwKXRRmHAjUn/KiFoB+cGWs= ARC-Authentication-Results: i=1; imf26.hostedemail.com; dkim=none; spf=pass (imf26.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.189 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1724425567; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=srJHYmktV8Fuy88vTRRFr1X/R6V1yXGJsFP6jFbGahQ=; b=iHp2eT36PbAjv6vWZrhd2AKZCmMVp2YjbXDToQ9UrzyqXkM1O9zQXyY6Om++7o8FnOcfxP UBm0TXgme1L76Ly65xUjmtFwcvxchwHE8Q+s2+t7I+MBghqlvj3AK6cMsi8WDfNY6ocFrA bvceD/EejmhOntO1Kzx4n3orTKuDwcs= Received: from mail.maildlp.com (unknown [172.19.163.174]) by szxga03-in.huawei.com (SkyGuard) with ESMTP id 4Wr3FM5gwqzQqQb; Fri, 23 Aug 2024 23:01:59 +0800 (CST) Received: from dggpemf200006.china.huawei.com (unknown [7.185.36.61]) by mail.maildlp.com (Postfix) with ESMTPS id 44ECD140390; Fri, 23 Aug 2024 23:06:44 +0800 (CST) Received: from localhost.localdomain (10.90.30.45) by dggpemf200006.china.huawei.com (7.185.36.61) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Fri, 23 Aug 2024 23:06:43 +0800 From: Yunsheng Lin To: , , CC: , , Yunsheng Lin , Alexander Duyck , Alexander Duyck , Chuck Lever , "Michael S. Tsirkin" , Jason Wang , =?utf-8?q?Eugenio_P=C3=A9rez?= , Andrew Morton , Eric Dumazet , David Howells , Marc Dionne , Jeff Layton , Neil Brown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Shuah Khan , , , , , , Subject: [PATCH net-next v14 04/11] mm: page_frag: avoid caller accessing 'page_frag_cache' directly Date: Fri, 23 Aug 2024 23:00:32 +0800 Message-ID: <20240823150040.1567062-5-linyunsheng@huawei.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20240823150040.1567062-1-linyunsheng@huawei.com> References: <20240823150040.1567062-1-linyunsheng@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.90.30.45] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To dggpemf200006.china.huawei.com (7.185.36.61) X-Stat-Signature: da5uxm7hza1swwzy7p1dc8fcsnbc3top X-Rspamd-Queue-Id: 6B5C514001A X-Rspam-User: X-Rspamd-Server: rspam10 X-HE-Tag: 1724425607-94793 X-HE-Meta: U2FsdGVkX18xk/LsCniljcpmFms7ASwKXP3zzcwpNlLed0/CtE2EhvRw3XIOMaCGwpdcJa1W043A8Ls03gS3Bnhu1NAGPvKgk6rZE7VJLJfsrBX/tAXLKieiukWBJWDsJSDhZG7Hn2aI5+dFIRN0ZRTgR6JjSeb5KqDlVB75fbZvifhvEX5fFh1LTGWJPd9Cb/2ektG+hJzUO4oRFA4UPz+RBrosnSInTtmzP3qmzAPcHRPeHS4RZtECVAHw1bpbbkN/uKlSaubC2YJ0Hf/895mK/di8ajr9S1fcybWlx2e2qzlWo81zm4C9nqaM1vyJyZUQ41ho+iAlogDFru8IJmWoiTfJPmzT85D8OZIQ4/Xe2OYtm8oBybEQn2jDMBmRifSoKSbQZ545To4DqlFyR3cSBu1cUfD+LQgzZX0eppSfz3ws2ulEKuwOvRgTT9xDAsDj4ofMfJROONuobri7WbO5ZCjTLSeNBJFc1rCe4rNQy7ffALOVu+wwqR3VLqTw8JZ+fM3GR//bOaw/B2DgA/G4a2p1BiM0xP5rm3UfDrIOQtkb2e6K/r/7RMHltwef/cnCQTdMNvgXfY511Hm0hJI95kHDciIL1cfNEmI1yNUd+Y8/IAzMuiNb8wyPudqVSV6uuyBBQekiBfUZuw5M1tnzFz1+4XQ6Jncr2OiFAjjR9WUVjQa0zFtZ1QkUe+Y60TvSgoITV8xCXB3N6aZRsuHfnETLhsn3xAGRUcJIKhjpDFx08gasw78SYwq5Q5d/NLnHAyLy4bw/1w8uE81twI/MU81NDGtWeuhq2Qees0CHJrHNIFR7/+GNJYdin9OnUFh9zkIMXP+eB3wyP+e1eix5h4jOgyZUhEOPr7EU9XYzSBnv52WehPGnhruruLNkc+d/ul+LOSpgB6ZAHx78c2LabSmLSSCRhOcYp+7VLgDFG66Fa6k+tCp3O58d5tRdgq8AnAxiTUDKEuPMeWW M8SBicBL +bjmn2td6P+qf+UJ7HUM6BuCGY/dNwWYnOnEnylt89epTbApvs3XgxWNA08g5WW2Zx1E5dDO01Dku1Ud5Io1Hkov0wx6IId3nb26Obu6KcKeM2wjAsRc8cGG0q3rUJh/AZg7glXosN/hVTPfWu0rhRvB45ACSOVG61xzaZPKAEtW/HBeL+4AvxpX4ycFQMQoQibEgJjptFK8mM/DQvPteKRXwHuZwCUbqCgzh0auLwQvqnXwEGLLj7UYuI9WomiXoLOhVbdRHMLCYOweJw+DgXkEqRdPtrfF0CgmIiVRyXUyzZAPwXiqd0l6UJtxV0o6Eqd8io/Lb5vJ3YQ1OJowv2rDc1Bn4vs8h+DrYF+Szxv5CHUG85LPstcipBQ== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Use appropriate frag_page API instead of caller accessing 'page_frag_cache' directly. CC: Alexander Duyck Signed-off-by: Yunsheng Lin Reviewed-by: Alexander Duyck Acked-by: Chuck Lever --- drivers/vhost/net.c | 2 +- include/linux/page_frag_cache.h | 10 ++++++++++ net/core/skbuff.c | 6 +++--- net/rxrpc/conn_object.c | 4 +--- net/rxrpc/local_object.c | 4 +--- net/sunrpc/svcsock.c | 6 ++---- tools/testing/selftests/mm/page_frag/page_frag_test.c | 2 +- 7 files changed, 19 insertions(+), 15 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index f16279351db5..9ad37c012189 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -1325,7 +1325,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) vqs[VHOST_NET_VQ_RX]); f->private_data = n; - n->pf_cache.va = NULL; + page_frag_cache_init(&n->pf_cache); return 0; } diff --git a/include/linux/page_frag_cache.h b/include/linux/page_frag_cache.h index 67ac8626ed9b..0a52f7a179c8 100644 --- a/include/linux/page_frag_cache.h +++ b/include/linux/page_frag_cache.h @@ -7,6 +7,16 @@ #include #include +static inline void page_frag_cache_init(struct page_frag_cache *nc) +{ + nc->va = NULL; +} + +static inline bool page_frag_cache_is_pfmemalloc(struct page_frag_cache *nc) +{ + return !!nc->pfmemalloc; +} + void page_frag_cache_drain(struct page_frag_cache *nc); void __page_frag_cache_drain(struct page *page, unsigned int count); void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz, diff --git a/net/core/skbuff.c b/net/core/skbuff.c index de2a044cc665..969e345b0f9c 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -752,14 +752,14 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len, if (in_hardirq() || irqs_disabled()) { nc = this_cpu_ptr(&netdev_alloc_cache); data = page_frag_alloc(nc, len, gfp_mask); - pfmemalloc = nc->pfmemalloc; + pfmemalloc = page_frag_cache_is_pfmemalloc(nc); } else { local_bh_disable(); local_lock_nested_bh(&napi_alloc_cache.bh_lock); nc = this_cpu_ptr(&napi_alloc_cache.page); data = page_frag_alloc(nc, len, gfp_mask); - pfmemalloc = nc->pfmemalloc; + pfmemalloc = page_frag_cache_is_pfmemalloc(nc); local_unlock_nested_bh(&napi_alloc_cache.bh_lock); local_bh_enable(); @@ -849,7 +849,7 @@ struct sk_buff *napi_alloc_skb(struct napi_struct *napi, unsigned int len) len = SKB_HEAD_ALIGN(len); data = page_frag_alloc(&nc->page, len, gfp_mask); - pfmemalloc = nc->page.pfmemalloc; + pfmemalloc = page_frag_cache_is_pfmemalloc(&nc->page); } local_unlock_nested_bh(&napi_alloc_cache.bh_lock); diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c index 1539d315afe7..694c4df7a1a3 100644 --- a/net/rxrpc/conn_object.c +++ b/net/rxrpc/conn_object.c @@ -337,9 +337,7 @@ static void rxrpc_clean_up_connection(struct work_struct *work) */ rxrpc_purge_queue(&conn->rx_queue); - if (conn->tx_data_alloc.va) - __page_frag_cache_drain(virt_to_page(conn->tx_data_alloc.va), - conn->tx_data_alloc.pagecnt_bias); + page_frag_cache_drain(&conn->tx_data_alloc); call_rcu(&conn->rcu, rxrpc_rcu_free_connection); } diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c index 504453c688d7..a8cffe47cf01 100644 --- a/net/rxrpc/local_object.c +++ b/net/rxrpc/local_object.c @@ -452,9 +452,7 @@ void rxrpc_destroy_local(struct rxrpc_local *local) #endif rxrpc_purge_queue(&local->rx_queue); rxrpc_purge_client_connections(local); - if (local->tx_alloc.va) - __page_frag_cache_drain(virt_to_page(local->tx_alloc.va), - local->tx_alloc.pagecnt_bias); + page_frag_cache_drain(&local->tx_alloc); } /* diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 6b3f01beb294..dcfd84cf0694 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1609,7 +1609,6 @@ static void svc_tcp_sock_detach(struct svc_xprt *xprt) static void svc_sock_free(struct svc_xprt *xprt) { struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); - struct page_frag_cache *pfc = &svsk->sk_frag_cache; struct socket *sock = svsk->sk_sock; trace_svcsock_free(svsk, sock); @@ -1619,8 +1618,7 @@ static void svc_sock_free(struct svc_xprt *xprt) sockfd_put(sock); else sock_release(sock); - if (pfc->va) - __page_frag_cache_drain(virt_to_head_page(pfc->va), - pfc->pagecnt_bias); + + page_frag_cache_drain(&svsk->sk_frag_cache); kfree(svsk); } diff --git a/tools/testing/selftests/mm/page_frag/page_frag_test.c b/tools/testing/selftests/mm/page_frag/page_frag_test.c index 4a009122991e..c52598eaf7e7 100644 --- a/tools/testing/selftests/mm/page_frag/page_frag_test.c +++ b/tools/testing/selftests/mm/page_frag/page_frag_test.c @@ -117,7 +117,7 @@ static int __init page_frag_test_init(void) u64 duration; int ret; - test_frag.va = NULL; + page_frag_cache_init(&test_frag); atomic_set(&nthreads, 2); init_completion(&wait); From patchwork Fri Aug 23 15:00:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunsheng Lin X-Patchwork-Id: 13775388 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id E64CBC531DC for ; Fri, 23 Aug 2024 15:06:53 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 768C9800A6; Fri, 23 Aug 2024 11:06:53 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 6A0C7800A4; Fri, 23 Aug 2024 11:06:53 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 5691B800A6; Fri, 23 Aug 2024 11:06:53 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id 3313C800A4 for ; Fri, 23 Aug 2024 11:06:53 -0400 (EDT) Received: from smtpin21.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id 7B67E1A1DAD for ; Fri, 23 Aug 2024 15:06:52 +0000 (UTC) X-FDA: 82483837464.21.60AB209 Received: from szxga04-in.huawei.com (szxga04-in.huawei.com [45.249.212.190]) by imf21.hostedemail.com (Postfix) with ESMTP id AD42C1C0018 for ; Fri, 23 Aug 2024 15:06:49 +0000 (UTC) Authentication-Results: imf21.hostedemail.com; dkim=none; spf=pass (imf21.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.190 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1724425569; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=M+oJdhvQe/thRshkN9bincoLoylmm36nwUI5xuJ37QE=; b=UpzxGCK1Lwj3SSNaBRoPNH/h4G73+WyV1biiuTd7nmE8H14bWMgyZq/BiDVI0mHXMVXExJ tsyNYqbLGhIjpfNElIpMaT9t5CA0iLldRvjruWVlDNbibS5/XzFWmgMUtI2YaL75+9hWLW 4dsv5Zjmq2RzcNuTbKePaUyrWocfNmo= ARC-Authentication-Results: i=1; imf21.hostedemail.com; dkim=none; spf=pass (imf21.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.190 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1724425569; a=rsa-sha256; cv=none; b=2GanUP3dJx+EVdKth6cAw8BS5ymoRRhhBtwpQHR4iNCe2/2M4xwMZfBlajoinjHL9wa+Ku qt5HKiT4yBal6HXEyJWSd6g6CN7ijy38oZpFYox0pLS6xLTpuqs9va6HVWkXSF9+p7VfTI 7QYYYh5IkedjXxIGzsZM/Oi9qg6S+Nk= Received: from mail.maildlp.com (unknown [172.19.163.44]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4Wr3FQ2vzwz20mBR; Fri, 23 Aug 2024 23:02:02 +0800 (CST) Received: from dggpemf200006.china.huawei.com (unknown [7.185.36.61]) by mail.maildlp.com (Postfix) with ESMTPS id 7490C1402E1; Fri, 23 Aug 2024 23:06:46 +0800 (CST) Received: from localhost.localdomain (10.90.30.45) by dggpemf200006.china.huawei.com (7.185.36.61) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Fri, 23 Aug 2024 23:06:46 +0800 From: Yunsheng Lin To: , , CC: , , Yunsheng Lin , Alexander Duyck , Andrew Morton , Subject: [PATCH net-next v14 05/11] mm: page_frag: reuse existing space for 'size' and 'pfmemalloc' Date: Fri, 23 Aug 2024 23:00:33 +0800 Message-ID: <20240823150040.1567062-6-linyunsheng@huawei.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20240823150040.1567062-1-linyunsheng@huawei.com> References: <20240823150040.1567062-1-linyunsheng@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.90.30.45] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To dggpemf200006.china.huawei.com (7.185.36.61) X-Rspamd-Server: rspam03 X-Rspam-User: X-Rspamd-Queue-Id: AD42C1C0018 X-Stat-Signature: 9tt3rh9pthzi8aeqb54m75buoq1twcma X-HE-Tag: 1724425609-548746 X-HE-Meta: U2FsdGVkX18OZWSQ135ZR5nGxCHnLZ5wxUlCb4qCFNkPEt7eD9WHhJ8+2eex9sSEn4Jy8SHZ5Tk8XAGM+1jrsj47wJIbI6d9CFSSdOpBXDecBxdGhNDakytwvtMI1CA+o+9Cz9mDDQOMrps4nae1WTUj10jivRco6YgANg7mL9TgEx6tqwa0ZsU5kDZn7pwW32rl5CPhBb2Uc0mWkx/Ea2FJJZRR3eK7Cd8UdcSp9OyTcoasWu0skG69Wvgeh5PwJrSMvHA26Ps5INu0vegh6lzYK15v6FPQ45y9XgFupfAvQN2KO/PVCGZqj+ofjXNdL+TRTqugfdcoTnHM+c2IeHGIOBGWJ9sYsiZXPxK9KJ7qwX5YYt4UGfZayKYM2YyTBceQ/C5bX97kMRDTyfNKg8avZny/9dSqOEjiyGsD0rdDZYdHDlfeDYNssLUCNizkNKIYQ3ZUXHoaAxrjH+5iE09KiPzYkWswhRaWPubdyyKu/5cS9Osz8iaUozMFZeA96T6TOmEPjrCqHaN3V/pBPRlY8zcRvIB0tQVZslwf12RsiJ75yth3fsbdcl6ptMc/1BYtX8tr/z8l2ctNRFQB0oqpDImjsEF/ayEHTcHFjPnZCxj8pUuiZVkZJr6IjNRoP4iGgqnuT23uzJrhBXNGsCaY1rVn5R2mypvUIahPqKiIThc9YtYVL8hzaNw8g58a9vkgq7KlCWqvtxIdhAe9Vsp+6DL59eX1VizwoUHesSBwq0/QY11L1DkZsb3FbLf/u7+HU0b3Tlhb9PjC4MNBgfz/gdau3e+YwGDj30J7kAYdEDIYP3LTOIpPWKCcRLxC684hAoNHMPNdNnmjzlh1CSBwGlgc2WgzXd/+6XstT/s5PZrf/QmOYCq49Cf2cOKADgU2wK7oMxcWaflyl741vpWpfX3xgDWmCfD0Uoa2eyBU+L6Piq0ukFsEsm0K7Hjp7AOTm2z8WsXhC2y5ZfS 4l1BP9e6 3s1FTY2lLYZPecwp7g6RDzDDn4QDG+wkDKPjNAbB5XJFYXmGjaGpcO7vR5gbvx+H7ZuG6VQ7ZuRjD0TSVkUQ3YgGDe+0NJuuOtTdAMn6FWprBcAxLJDTzlUz502PXAcwHYbi1JIPA/0dS1PUfy7WjJjFCSFdD0XyNnfvxf0DizrtyplT4Nb+vC/3MEs33nMNUeE2eJy1TH0ylFc2VCfHA5yjJHnVyM5ZZYLvxGOjBBlJfbgZ20NlBFz7RHK/14FzGhxgOP0MJohggvgLDbHbPjTLDHoTkRKYz2xVJ X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Currently there is one 'struct page_frag' for every 'struct sock' and 'struct task_struct', we are about to replace the 'struct page_frag' with 'struct page_frag_cache' for them. Before begin the replacing, we need to ensure the size of 'struct page_frag_cache' is not bigger than the size of 'struct page_frag', as there may be tens of thousands of 'struct sock' and 'struct task_struct' instances in the system. By or'ing the page order & pfmemalloc with lower bits of 'va' instead of using 'u16' or 'u32' for page size and 'u8' for pfmemalloc, we are able to avoid 3 or 5 bytes space waste. And page address & pfmemalloc & order is unchanged for the same page in the same 'page_frag_cache' instance, it makes sense to fit them together. After this patch, the size of 'struct page_frag_cache' should be the same as the size of 'struct page_frag'. CC: Alexander Duyck Signed-off-by: Yunsheng Lin --- include/linux/mm_types_task.h | 19 ++++--- include/linux/page_frag_cache.h | 98 +++++++++++++++++++++++++++++++-- mm/page_frag_cache.c | 64 +++++++++++---------- 3 files changed, 140 insertions(+), 41 deletions(-) diff --git a/include/linux/mm_types_task.h b/include/linux/mm_types_task.h index cdc1e3696439..a8635460e027 100644 --- a/include/linux/mm_types_task.h +++ b/include/linux/mm_types_task.h @@ -50,18 +50,21 @@ struct page_frag { #define PAGE_FRAG_CACHE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK) #define PAGE_FRAG_CACHE_MAX_ORDER get_order(PAGE_FRAG_CACHE_MAX_SIZE) struct page_frag_cache { - void *va; -#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) + /* encoded_page consists of the virtual address, pfmemalloc bit and order + * of a page. + */ + unsigned long encoded_page; + + /* we maintain a pagecount bias, so that we dont dirty cache line + * containing page->_refcount every time we allocate a fragment. + */ +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) && (BITS_PER_LONG <= 32) __u16 offset; - __u16 size; + __u16 pagecnt_bias; #else __u32 offset; + __u32 pagecnt_bias; #endif - /* we maintain a pagecount bias, so that we dont dirty cache line - * containing page->_refcount every time we allocate a fragment. - */ - unsigned int pagecnt_bias; - bool pfmemalloc; }; /* Track pages that require TLB flushes */ diff --git a/include/linux/page_frag_cache.h b/include/linux/page_frag_cache.h index 0a52f7a179c8..1ed0d1b7014b 100644 --- a/include/linux/page_frag_cache.h +++ b/include/linux/page_frag_cache.h @@ -3,24 +3,114 @@ #ifndef _LINUX_PAGE_FRAG_CACHE_H #define _LINUX_PAGE_FRAG_CACHE_H +#include +#include #include +#include #include #include +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) +/* Use a full byte here to enable assembler optimization as the shift + * operation is usually expecting a byte. + */ +#define PAGE_FRAG_CACHE_ORDER_MASK GENMASK(7, 0) +#define PAGE_FRAG_CACHE_PFMEMALLOC_SHIFT 8 +#define PAGE_FRAG_CACHE_PFMEMALLOC_BIT BIT(PAGE_FRAG_CACHE_PFMEMALLOC_SHIFT) +#else +/* Compiler should be able to figure out we don't read things as any value + * ANDed with 0 is 0. + */ +#define PAGE_FRAG_CACHE_ORDER_MASK 0 +#define PAGE_FRAG_CACHE_PFMEMALLOC_SHIFT 0 +#define PAGE_FRAG_CACHE_PFMEMALLOC_BIT BIT(PAGE_FRAG_CACHE_PFMEMALLOC_SHIFT) +#endif + +static inline unsigned long page_pool_encode_page(struct page *page, + unsigned int order, + bool pfmemalloc) +{ + BUILD_BUG_ON(PAGE_FRAG_CACHE_MAX_ORDER > PAGE_FRAG_CACHE_ORDER_MASK); + BUILD_BUG_ON(PAGE_FRAG_CACHE_PFMEMALLOC_BIT >= PAGE_SIZE); + + return (unsigned long)page_address(page) | + (order & PAGE_FRAG_CACHE_ORDER_MASK) | + ((unsigned long)pfmemalloc << PAGE_FRAG_CACHE_PFMEMALLOC_SHIFT); +} + +static inline unsigned long page_pool_encoded_page_order(unsigned long encoded_page) +{ + return encoded_page & PAGE_FRAG_CACHE_ORDER_MASK; +} + +static inline bool page_pool_encoded_page_pfmemalloc(unsigned long encoded_page) +{ + return !!(encoded_page & PAGE_FRAG_CACHE_PFMEMALLOC_BIT); +} + +static inline void *page_pool_encoded_page_address(unsigned long encoded_page) +{ + return (void *)(encoded_page & PAGE_MASK); +} + +static inline struct page *page_pool_encoded_page_ptr(unsigned long encoded_page) +{ + return virt_to_page((void *)encoded_page); +} + static inline void page_frag_cache_init(struct page_frag_cache *nc) { - nc->va = NULL; + nc->encoded_page = 0; } static inline bool page_frag_cache_is_pfmemalloc(struct page_frag_cache *nc) { - return !!nc->pfmemalloc; + return page_pool_encoded_page_pfmemalloc(nc->encoded_page); +} + +static inline unsigned int page_frag_cache_page_size(unsigned long encoded_page) +{ + return PAGE_SIZE << page_pool_encoded_page_order(encoded_page); } void page_frag_cache_drain(struct page_frag_cache *nc); void __page_frag_cache_drain(struct page *page, unsigned int count); -void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz, - gfp_t gfp_mask, unsigned int align_mask); +void *__page_frag_cache_prepare(struct page_frag_cache *nc, unsigned int fragsz, + struct page_frag *pfrag, gfp_t gfp_mask, + unsigned int align_mask); + +static inline void __page_frag_cache_commit(struct page_frag_cache *nc, + struct page_frag *pfrag, bool referenced, + unsigned int used_sz) +{ + if (referenced) { + VM_BUG_ON(!nc->pagecnt_bias); + nc->pagecnt_bias--; + } + + /* Committed offset might be bigger than the current offset due to alignment */ + VM_BUG_ON(nc->offset > pfrag->offset); + + VM_BUG_ON(used_sz > pfrag->size); + VM_BUG_ON(pfrag->offset + pfrag->size > page_frag_cache_page_size(nc->encoded_page)); + + nc->offset = pfrag->offset + used_sz; +} + +static inline void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz, + gfp_t gfp_mask, unsigned int align_mask) +{ + struct page_frag page_frag; + void *va; + + va = __page_frag_cache_prepare(nc, fragsz, &page_frag, gfp_mask, align_mask); + if (unlikely(!va)) + return NULL; + + __page_frag_cache_commit(nc, &page_frag, true, fragsz); + + return va; +} static inline void *page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask, diff --git a/mm/page_frag_cache.c b/mm/page_frag_cache.c index 4c8e04379cb3..2865bff7199d 100644 --- a/mm/page_frag_cache.c +++ b/mm/page_frag_cache.c @@ -22,6 +22,7 @@ static struct page *__page_frag_cache_refill(struct page_frag_cache *nc, gfp_t gfp_mask) { + unsigned long order = PAGE_FRAG_CACHE_MAX_ORDER; struct page *page = NULL; gfp_t gfp = gfp_mask; @@ -30,23 +31,31 @@ static struct page *__page_frag_cache_refill(struct page_frag_cache *nc, __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC; page = alloc_pages_node(NUMA_NO_NODE, gfp_mask, PAGE_FRAG_CACHE_MAX_ORDER); - nc->size = page ? PAGE_FRAG_CACHE_MAX_SIZE : PAGE_SIZE; #endif - if (unlikely(!page)) + if (unlikely(!page)) { page = alloc_pages_node(NUMA_NO_NODE, gfp, 0); + if (unlikely(!page)) { + nc->encoded_page = 0; + return NULL; + } + + order = 0; + } - nc->va = page ? page_address(page) : NULL; + nc->encoded_page = page_pool_encode_page(page, order, + page_is_pfmemalloc(page)); return page; } void page_frag_cache_drain(struct page_frag_cache *nc) { - if (!nc->va) + if (!nc->encoded_page) return; - __page_frag_cache_drain(virt_to_head_page(nc->va), nc->pagecnt_bias); - nc->va = NULL; + __page_frag_cache_drain(page_pool_encoded_page_ptr(nc->encoded_page), + nc->pagecnt_bias); + nc->encoded_page = 0; } EXPORT_SYMBOL(page_frag_cache_drain); @@ -59,35 +68,32 @@ void __page_frag_cache_drain(struct page *page, unsigned int count) } EXPORT_SYMBOL(__page_frag_cache_drain); -void *__page_frag_alloc_align(struct page_frag_cache *nc, - unsigned int fragsz, gfp_t gfp_mask, - unsigned int align_mask) +void *__page_frag_cache_prepare(struct page_frag_cache *nc, unsigned int fragsz, + struct page_frag *pfrag, gfp_t gfp_mask, + unsigned int align_mask) { -#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) - unsigned int size = nc->size; -#else - unsigned int size = PAGE_SIZE; -#endif - unsigned int offset; + unsigned long encoded_page = nc->encoded_page; + unsigned int size, offset; struct page *page; - if (unlikely(!nc->va)) { + size = page_frag_cache_page_size(encoded_page); + page = page_pool_encoded_page_ptr(encoded_page); + + if (unlikely(!encoded_page)) { refill: page = __page_frag_cache_refill(nc, gfp_mask); if (!page) return NULL; -#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) - /* if size can vary use size else just use PAGE_SIZE */ - size = nc->size; -#endif + encoded_page = nc->encoded_page; + size = page_frag_cache_page_size(encoded_page); + /* Even if we own the page, we do not use atomic_set(). * This would break get_page_unless_zero() users. */ page_ref_add(page, PAGE_FRAG_CACHE_MAX_SIZE); /* reset page count bias and offset to start of new frag */ - nc->pfmemalloc = page_is_pfmemalloc(page); nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1; nc->offset = 0; } @@ -107,13 +113,12 @@ void *__page_frag_alloc_align(struct page_frag_cache *nc, return NULL; } - page = virt_to_page(nc->va); - if (!page_ref_sub_and_test(page, nc->pagecnt_bias)) goto refill; - if (unlikely(nc->pfmemalloc)) { - free_unref_page(page, compound_order(page)); + if (unlikely(page_pool_encoded_page_pfmemalloc(encoded_page))) { + free_unref_page(page, + page_pool_encoded_page_order(encoded_page)); goto refill; } @@ -125,12 +130,13 @@ void *__page_frag_alloc_align(struct page_frag_cache *nc, offset = 0; } - nc->pagecnt_bias--; - nc->offset = offset + fragsz; + pfrag->page = page; + pfrag->offset = offset; + pfrag->size = size - offset; - return nc->va + offset; + return page_pool_encoded_page_address(encoded_page) + offset; } -EXPORT_SYMBOL(__page_frag_alloc_align); +EXPORT_SYMBOL(__page_frag_cache_prepare); /* * Frees a page fragment allocated out of either a compound or order 0 page. From patchwork Fri Aug 23 15:00:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunsheng Lin X-Patchwork-Id: 13775389 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 915FEC5321D for ; Fri, 23 Aug 2024 15:06:57 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 2868B800A7; Fri, 23 Aug 2024 11:06:57 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 1E814800A4; Fri, 23 Aug 2024 11:06:57 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 012A9800A7; Fri, 23 Aug 2024 11:06:56 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id D03EA800A4 for ; Fri, 23 Aug 2024 11:06:56 -0400 (EDT) Received: from smtpin28.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id 7A95E1A1DAD for ; Fri, 23 Aug 2024 15:06:56 +0000 (UTC) X-FDA: 82483837632.28.E49710D Received: from szxga05-in.huawei.com (szxga05-in.huawei.com [45.249.212.191]) by imf17.hostedemail.com (Postfix) with ESMTP id 4079940021 for ; Fri, 23 Aug 2024 15:06:53 +0000 (UTC) Authentication-Results: imf17.hostedemail.com; dkim=none; spf=pass (imf17.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.191 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1724425597; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qIHoeO1xql+XVEKJR6q9hYgl8zcTGGL+wRC66wUUeww=; b=K+LFIouecrbg21Dgna2up360pOvOFSiXY5cPKczb8i/qJD1HQEqb9PMJE4ae1cTyFO+NaL 8MD4ux5Y3Uy+3oL3TsAJKdHZZaMznoQz9Uug35VTudiGUsaysipxlKevRLVd6VfgD8dK43 rs+FSr+q9npv+KBI8xVCxs9C2WVGbCE= ARC-Authentication-Results: i=1; imf17.hostedemail.com; dkim=none; spf=pass (imf17.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.191 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1724425597; a=rsa-sha256; cv=none; b=A2ebuTunGEgcEwxUfoH+oa1f1EQgcG7njo5vcxvomNoun6wFFNuoJMtMailHCSQr7U37G/ 9LbfXHmoxzCVt73NpmwA3qPyacprm7E2rlrXYebvyWWxQSFwLuURTalLcMKHp9vZ1Q4don 7SHWwKthQcqXfCAl523cELkCfSMrDAM= Received: from mail.maildlp.com (unknown [172.19.162.112]) by szxga05-in.huawei.com (SkyGuard) with ESMTP id 4Wr3Lq0Mr8z1j6QT; Fri, 23 Aug 2024 23:06:43 +0800 (CST) Received: from dggpemf200006.china.huawei.com (unknown [7.185.36.61]) by mail.maildlp.com (Postfix) with ESMTPS id F278E14013B; Fri, 23 Aug 2024 23:06:47 +0800 (CST) Received: from localhost.localdomain (10.90.30.45) by dggpemf200006.china.huawei.com (7.185.36.61) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Fri, 23 Aug 2024 23:06:47 +0800 From: Yunsheng Lin To: , , CC: , , Yunsheng Lin , Alexander Duyck , Andrew Morton , Subject: [PATCH net-next v14 06/11] mm: page_frag: use __alloc_pages() to replace alloc_pages_node() Date: Fri, 23 Aug 2024 23:00:34 +0800 Message-ID: <20240823150040.1567062-7-linyunsheng@huawei.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20240823150040.1567062-1-linyunsheng@huawei.com> References: <20240823150040.1567062-1-linyunsheng@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.90.30.45] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To dggpemf200006.china.huawei.com (7.185.36.61) X-Rspam-User: X-Stat-Signature: wbr7967he8wxq6p7hkomgitg8fj4ic3n X-Rspamd-Queue-Id: 4079940021 X-Rspamd-Server: rspam11 X-HE-Tag: 1724425613-11218 X-HE-Meta: U2FsdGVkX1+TDxLbfAluZeJYnSQnzmVN6TzTuyTTW9yWmqs7wiK3ZzNXKum7KaKmFtUQEjaQ6hGaljacZphxIn1ZY41jiOh/PjHKeqIlq4xvtrwnT2YOYkMuB8fU9wI5Qutw2xhr9D/HOvq1p4PaSPgjBbKmCBfH8tgkae/2gT65SnWtLPE77v8iMIA62h1O6drZslrHa2PPZSn4HrMUg4P81MOtUggoqDD7fuV/Ng9vPiw4vfZXBj6FBPrT69zEL55M4Unu18ap6+hc5Ek7P5slEMAAgAf49ubMQdKdGxmxFPkeoU0hatf5yGn6fjWHdI1jHUecoBybPRRy9Cz6aNp4BtPoRYaBSOm8316lbLAtBFblOTwq4LM6+xWwaf6DFS6ZTDfxAKnZtZn5TOLvW2hYL/fxL+zeAYcMixgjhjqStp9HJfX8Fa/K7Qai/gO3q2wjAmOzkDRrzlgqEJmehLmwOQIYHC69LVIo3gJzxb07sswcp1MyFLWrEZ2UtGUzJ7Yblf8IK5kKXgShnlsEHzDCa5m0Epw+mCMItPj+4WvxNrB7Yyz5iC42JQ8Rg8PL/MKgIAJbpE3wBjSMtRM5q15PrZ7BcQi0GauI3oLzSKLXkim4VftMZkY/qUfq0CHhJ6je//LsnzwGBPMMFPOHrhfPJ6OLk+jQ7Tlx/boWYtPlqaAiSaNRPR+BpYYrFLY5imNC5ZHLYhh6sYIf6nDvn41cXqrFTorA1P295L9iGM/jSW13ImZ1CFP/6bu3CCN+SckBgUnNvL44at3E9INXfHu0cTQxNOAO5+iIGcABtG3Iqq/xvOCaJUrFJnaH/r8Fecp9B5nEZ7C+RM2CHEQedJuJ0beVHaXgaJXXODw+DQEbPR96GYQsMnS2EpEJjIdkm4g8du0raSrzRbs4SSlz1g859GGeLg6KzvBS3KdUzayUDxh/9gG7j90GuRWr07ZRLnxkT8W/Vi8s2t4bDpb +3eBHSs3 m9BSbXsgKif8GlU8/BFaCMJPduZceS2Yd5HWvY2OEl8YEF/GCJ4D/d4Ij8qntUe1snGQGqSXbaJYtXc3NV6wk+4YED74/LVJvpfuM9T2km+MSj1jiP77+/KXkzXWfA4ApslD7Bvw2IoOyzgMrF0UPaR5GWEdZJ3Qad935mAbQCigtt1/+4YwOKw2tyV9M2NLoYpr0/kaGxt+IB7cbIzVYv9RqY3e+IGGH3Qg2XjryX3oF5kSnIIqaC+iHbcoV3MM4NoTntGIkezBt2Jrr1LYkNZULRkYR7E+YTygJ X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: It seems there is about 24Bytes binary size increase for __page_frag_cache_refill() after refactoring in arm64 system with 64K PAGE_SIZE. By doing the gdb disassembling, It seems we can have more than 100Bytes decrease for the binary size by using __alloc_pages() to replace alloc_pages_node(), as there seems to be some unnecessary checking for nid being NUMA_NO_NODE, especially when page_frag is part of the mm system. CC: Alexander Duyck Signed-off-by: Yunsheng Lin --- mm/page_frag_cache.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/page_frag_cache.c b/mm/page_frag_cache.c index 2865bff7199d..b3053a0f38aa 100644 --- a/mm/page_frag_cache.c +++ b/mm/page_frag_cache.c @@ -29,11 +29,11 @@ static struct page *__page_frag_cache_refill(struct page_frag_cache *nc, #if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) gfp_mask = (gfp_mask & ~__GFP_DIRECT_RECLAIM) | __GFP_COMP | __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC; - page = alloc_pages_node(NUMA_NO_NODE, gfp_mask, - PAGE_FRAG_CACHE_MAX_ORDER); + page = __alloc_pages(gfp_mask, PAGE_FRAG_CACHE_MAX_ORDER, + numa_mem_id(), NULL); #endif if (unlikely(!page)) { - page = alloc_pages_node(NUMA_NO_NODE, gfp, 0); + page = __alloc_pages(gfp, 0, numa_mem_id(), NULL); if (unlikely(!page)) { nc->encoded_page = 0; return NULL; From patchwork Fri Aug 23 15:00:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunsheng Lin X-Patchwork-Id: 13775390 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 42B48C52D7C for ; Fri, 23 Aug 2024 15:07:00 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 8C5B5800A8; Fri, 23 Aug 2024 11:06:58 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 876FB800A4; Fri, 23 Aug 2024 11:06:58 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 6A073800A8; Fri, 23 Aug 2024 11:06:58 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 4525B800A4 for ; Fri, 23 Aug 2024 11:06:58 -0400 (EDT) Received: from smtpin04.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay03.hostedemail.com (Postfix) with ESMTP id F18A9A1D91 for ; Fri, 23 Aug 2024 15:06:57 +0000 (UTC) X-FDA: 82483837674.04.7EC2B59 Received: from szxga06-in.huawei.com (szxga06-in.huawei.com [45.249.212.32]) by imf10.hostedemail.com (Postfix) with ESMTP id AAF97C000A for ; Fri, 23 Aug 2024 15:06:54 +0000 (UTC) Authentication-Results: imf10.hostedemail.com; dkim=none; spf=pass (imf10.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.32 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1724425573; a=rsa-sha256; cv=none; b=CEIPZ0+MmdKTb9UvOtoMV/NaUOFPq7Xkp6MIg1lny0n9uaelIWbhs/qqP+Ayg7coWrytA1 Z3kOOUF3o/QkMEsy+BPmRXAXBlBfQSRBkUyTO/wdQnQ9ED+TsPh0XRLQCUBluEPohTgOzA SJGoxlUlzETvcdVga8RkAzLwRwkAPHo= ARC-Authentication-Results: i=1; imf10.hostedemail.com; dkim=none; spf=pass (imf10.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.32 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1724425573; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3Q49kNfoRHNTbg6QBk9o0LtECwE9e4tPy6zxxFlopW4=; b=WvDV7C81DZ/FnI5ML4wdmmUCba/Ze1gn6E5b/ik34vH3hGpeBQmP7jqtgZ8sUrcxvFGVCz qAZTerxdc8hWzfRV27CMB2n5VTJVlrwK98iN25ZnHrb2cYKoFK9dg/z0P6B8/ZsyI9OgU6 D26PunuWtl4DSYosk60Xilg+3/sT9QI= Received: from mail.maildlp.com (unknown [172.19.163.17]) by szxga06-in.huawei.com (SkyGuard) with ESMTP id 4Wr3Jl6Z6lz1xvp8; Fri, 23 Aug 2024 23:04:55 +0800 (CST) Received: from dggpemf200006.china.huawei.com (unknown [7.185.36.61]) by mail.maildlp.com (Postfix) with ESMTPS id 6A33F1A0188; Fri, 23 Aug 2024 23:06:51 +0800 (CST) Received: from localhost.localdomain (10.90.30.45) by dggpemf200006.china.huawei.com (7.185.36.61) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Fri, 23 Aug 2024 23:06:51 +0800 From: Yunsheng Lin To: , , CC: , , Yunsheng Lin , Alexander Duyck , Andrew Morton , Subject: [PATCH net-next v14 08/11] mm: page_frag: introduce prepare/probe/commit API Date: Fri, 23 Aug 2024 23:00:36 +0800 Message-ID: <20240823150040.1567062-9-linyunsheng@huawei.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20240823150040.1567062-1-linyunsheng@huawei.com> References: <20240823150040.1567062-1-linyunsheng@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.90.30.45] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To dggpemf200006.china.huawei.com (7.185.36.61) X-Stat-Signature: nj5aixbhgwagygd384nss43xp74sdj7y X-Rspamd-Queue-Id: AAF97C000A X-Rspam-User: X-Rspamd-Server: rspam10 X-HE-Tag: 1724425614-165160 X-HE-Meta: U2FsdGVkX1+dLdD4M8qgNFnMuxiAdKTkXq5mSzZHOq1KhF82jbfZSWJSYWIAq0ZJ1+JN4s571BzPBbX3a2ROKsUYaKmxnPddbYUnJleIqCW6+me+1zs+jKt5We7JE5FDRE8OJvdiQ0l+bL63/aEpsl5ZDNQIwUF2DxDGXldxNXd0KaVXw4rvqZpmtqmJYZr0adcCsxrf2f7U4G/8XvSfg+i5ZNGET1wN+rGGmTsDRAUFuVyC2Fwrm1ks8Mh4yQfUHVxR+OGAscOF4URPCT/NdzP85sjOqT9epJwrzNcREZbMhmNTGgGSrfnJl6r5vydrGHvrCmOdmpM015Tj4YvQj52YDpjEb4d8uwMoapsIJO0oGdunFGvsAhPhXvpw1aU2Al/FYB1faAYmxgzQbIAdvB765lsP95Mx3A832g4+YN3xSM89bsIjiugiVdUw2h8Lyw6eqbAwBt9+KrPd1h+PHVhnUruK+YT8qNGTKZoxjaTr0IQb1P2lctduRdQM74Y3VA9udi0FNJQFe87JFnCU31MWcSUW67t2CVNniYRcQprdizUxBBrJLSrLE2ABS5wDmXok3Qb7B/sJc+9H3Mdc+YkHVE9jkfAsP4uSdulOTRdK8dZe2ag5fT02rr6F2aUYRttWD4iwUoiNOhcYecbcCwAxGX6mF8dHFvn/VEG+Ib8Fmsf5W84/a9o87iSz3nXu59ctlcaxbUvG19ZpEVBgfOr2KRGtJADlMr/quKXVPptg3Cp1+B+3kZtsmxjorZetXRtHZbk2ZB8n19h/KxZ/iJI7y9/FzxfCxL/J5NjsZj23Ntzj3g2pPnagU8k6RpLARrr5bCdfZFAHB4PgGDYBWMzgQQYIpEAF61JH1yh9+TdeCFVauNG6WWT5bWUgR82+ATzAVza8xCjuasia5hBrIFQA6vj9sH1of51aZ2AO7LE4FkRzbBLzy1ANeT52M/dJdFN4+lSAX5N+DJT57Rk cLMApJNI cHKRJ+LaxAC85Jjn83O2Bu+FmNmUNPevUvcyNLUbPT78ezVII6KtIkHzN61GEHsaVamZOlfR/K6XJeFtRdCEhEcUMEhV6m2uvZcl/gu2lbB8u/oYFi4TEAyj2hC+t83KdDmmBGQ/iaGhE0TE5F8/VpmJSbTdR/GLZfOmfxCerDVgUJw/COFxYgenSSkWG+EoLoW67T8caH1efNZp9/Cb3vsQ0mQx+lrIV4/tdiDLaok/0UQXY+dlKXr4t57wQDKwkwDW4tm/1CUoVyYK/ma3lk/8pLJXujHb2erZn X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: There are many use cases that need minimum memory in order for forward progress, but more performant if more memory is available or need to probe the cache info to use any memory available for frag caoleasing reason. Currently skb_page_frag_refill() API is used to solve the above use cases, but caller needs to know about the internal detail and access the data field of 'struct page_frag' to meet the requirement of the above use cases and its implementation is similar to the one in mm subsystem. To unify those two page_frag implementations, introduce a prepare API to ensure minimum memory is satisfied and return how much the actual memory is available to the caller and a probe API to report the current available memory to caller without doing cache refilling. The caller needs to either call the commit API to report how much memory it actually uses, or not do so if deciding to not use any memory. CC: Alexander Duyck Signed-off-by: Yunsheng Lin --- include/linux/page_frag_cache.h | 138 ++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/include/linux/page_frag_cache.h b/include/linux/page_frag_cache.h index 1ed0d1b7014b..5a064f74eac2 100644 --- a/include/linux/page_frag_cache.h +++ b/include/linux/page_frag_cache.h @@ -73,6 +73,11 @@ static inline unsigned int page_frag_cache_page_size(unsigned long encoded_page) return PAGE_SIZE << page_pool_encoded_page_order(encoded_page); } +static inline unsigned int page_frag_cache_page_offset(const struct page_frag_cache *nc) +{ + return nc->offset; +} + void page_frag_cache_drain(struct page_frag_cache *nc); void __page_frag_cache_drain(struct page *page, unsigned int count); void *__page_frag_cache_prepare(struct page_frag_cache *nc, unsigned int fragsz, @@ -126,6 +131,139 @@ static inline void *page_frag_alloc(struct page_frag_cache *nc, return __page_frag_alloc_align(nc, fragsz, gfp_mask, ~0u); } +static inline bool __page_frag_refill_align(struct page_frag_cache *nc, unsigned int fragsz, + struct page_frag *pfrag, gfp_t gfp_mask, + unsigned int align_mask) +{ + if (unlikely(!__page_frag_cache_prepare(nc, fragsz, pfrag, gfp_mask, align_mask))) + return false; + + __page_frag_cache_commit(nc, pfrag, true, fragsz); + return true; +} + +static inline bool page_frag_refill_align(struct page_frag_cache *nc, unsigned int fragsz, + struct page_frag *pfrag, gfp_t gfp_mask, + unsigned int align) +{ + WARN_ON_ONCE(!is_power_of_2(align)); + return __page_frag_refill_align(nc, fragsz, pfrag, gfp_mask, -align); +} + +static inline bool page_frag_refill(struct page_frag_cache *nc, unsigned int fragsz, + struct page_frag *pfrag, gfp_t gfp_mask) +{ + return __page_frag_refill_align(nc, fragsz, pfrag, gfp_mask, ~0u); +} + +static inline bool __page_frag_refill_prepare_align(struct page_frag_cache *nc, + unsigned int fragsz, + struct page_frag *pfrag, + gfp_t gfp_mask, + unsigned int align_mask) +{ + return !!__page_frag_cache_prepare(nc, fragsz, pfrag, gfp_mask, align_mask); +} + +static inline bool page_frag_refill_prepare_align(struct page_frag_cache *nc, + unsigned int fragsz, + struct page_frag *pfrag, + gfp_t gfp_mask, + unsigned int align) +{ + WARN_ON_ONCE(!is_power_of_2(align)); + return __page_frag_refill_prepare_align(nc, fragsz, pfrag, gfp_mask, -align); +} + +static inline bool page_frag_refill_prepare(struct page_frag_cache *nc, + unsigned int fragsz, + struct page_frag *pfrag, + gfp_t gfp_mask) +{ + return __page_frag_refill_prepare_align(nc, fragsz, pfrag, gfp_mask, ~0u); +} + +static inline void *__page_frag_alloc_refill_prepare_align(struct page_frag_cache *nc, + unsigned int fragsz, + struct page_frag *pfrag, + gfp_t gfp_mask, + unsigned int align_mask) +{ + return __page_frag_cache_prepare(nc, fragsz, pfrag, gfp_mask, align_mask); +} + +static inline void *page_frag_alloc_refill_prepare_align(struct page_frag_cache *nc, + unsigned int fragsz, + struct page_frag *pfrag, + gfp_t gfp_mask, + unsigned int align) +{ + WARN_ON_ONCE(!is_power_of_2(align)); + return __page_frag_alloc_refill_prepare_align(nc, fragsz, pfrag, gfp_mask, -align); +} + +static inline void *page_frag_alloc_refill_prepare(struct page_frag_cache *nc, + unsigned int fragsz, + struct page_frag *pfrag, + gfp_t gfp_mask) +{ + return __page_frag_alloc_refill_prepare_align(nc, fragsz, pfrag, gfp_mask, ~0u); +} + +static inline void *__page_frag_alloc_refill_probe_align(struct page_frag_cache *nc, + unsigned int fragsz, + struct page_frag *pfrag, + unsigned int align_mask) +{ + unsigned long encoded_page = nc->encoded_page; + unsigned int size, offset; + + size = page_frag_cache_page_size(encoded_page); + offset = __ALIGN_KERNEL_MASK(nc->offset, ~align_mask); + if (unlikely(offset + fragsz > size)) + return NULL; + + pfrag->page = page_pool_encoded_page_ptr(encoded_page); + pfrag->size = size - offset; + pfrag->offset = offset; + + return page_pool_encoded_page_address(encoded_page) + offset; +} + +static inline void *page_frag_alloc_refill_probe(struct page_frag_cache *nc, + unsigned int fragsz, + struct page_frag *pfrag) +{ + return __page_frag_alloc_refill_probe_align(nc, fragsz, pfrag, ~0u); +} + +static inline bool page_frag_refill_probe(struct page_frag_cache *nc, + unsigned int fragsz, + struct page_frag *pfrag) +{ + return !!page_frag_alloc_refill_probe(nc, fragsz, pfrag); +} + +static inline void page_frag_commit(struct page_frag_cache *nc, struct page_frag *pfrag, + unsigned int used_sz) +{ + __page_frag_cache_commit(nc, pfrag, true, used_sz); +} + +static inline void page_frag_commit_noref(struct page_frag_cache *nc, + struct page_frag *pfrag, unsigned int used_sz) +{ + __page_frag_cache_commit(nc, pfrag, false, used_sz); +} + +static inline void page_frag_alloc_abort(struct page_frag_cache *nc, unsigned int fragsz) +{ + VM_BUG_ON(fragsz > nc->offset); + + nc->pagecnt_bias++; + nc->offset -= fragsz; +} + void page_frag_free(void *addr); #endif From patchwork Fri Aug 23 15:00:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunsheng Lin X-Patchwork-Id: 13775391 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id CF45BC52D7C for ; Fri, 23 Aug 2024 15:07:07 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 606BE800A9; Fri, 23 Aug 2024 11:07:07 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 5B634800A4; Fri, 23 Aug 2024 11:07:07 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 45839800A9; Fri, 23 Aug 2024 11:07:07 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id 22753800A4 for ; Fri, 23 Aug 2024 11:07:07 -0400 (EDT) Received: from smtpin08.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay03.hostedemail.com (Postfix) with ESMTP id 979E7A1CCD for ; Fri, 23 Aug 2024 15:07:06 +0000 (UTC) X-FDA: 82483838052.08.8DC7AB6 Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) by imf21.hostedemail.com (Postfix) with ESMTP id 1AB751C0029 for ; Fri, 23 Aug 2024 15:07:03 +0000 (UTC) Authentication-Results: imf21.hostedemail.com; dkim=none; spf=pass (imf21.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.187 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1724425607; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VrSRwpGfW/I1D77rdQY6VOLMHPizc0zBtXpmmGu7ft0=; b=gjMwvNWL/5jaF17ek8i6EQ1rnPyIJ7nrnfYIE3kuELc0onJjzZaWViovvwvqPZSlyVTCu/ Y7gHhkZJwzMaPcdXkICkgPplarf5EKD6yfSk/H5a43o/GL3++A/pHcxTdi+/ReXadTIn/y BpHymWyzK+ZKcee3P4LCWqJRK8fz1QU= ARC-Authentication-Results: i=1; imf21.hostedemail.com; dkim=none; spf=pass (imf21.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.187 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com; dmarc=pass (policy=quarantine) header.from=huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1724425607; a=rsa-sha256; cv=none; b=wQE1XwyZqu5LCIvrf2PHmlFSQar88SBSFh7ahlqieJEbifs1lSatp+2NhwW7Bfvf9TJTSy MnL0KmRsVmzZHaRBqcxiyaj0OPhChJ0UCLDGriCU5ytHtGDqWup62W4CzR8adSSaKkQBpr tKOyKwFUDj02Tzv9ohB88s/1M9n4hyU= Received: from mail.maildlp.com (unknown [172.19.88.105]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4Wr3LL6P43zpVTd; Fri, 23 Aug 2024 23:06:18 +0800 (CST) Received: from dggpemf200006.china.huawei.com (unknown [7.185.36.61]) by mail.maildlp.com (Postfix) with ESMTPS id 03FC914011F; Fri, 23 Aug 2024 23:07:01 +0800 (CST) Received: from localhost.localdomain (10.90.30.45) by dggpemf200006.china.huawei.com (7.185.36.61) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Fri, 23 Aug 2024 23:07:00 +0800 From: Yunsheng Lin To: , , CC: , , Yunsheng Lin , Alexander Duyck , Jonathan Corbet , Andrew Morton , , Subject: [PATCH net-next v14 10/11] mm: page_frag: update documentation for page_frag Date: Fri, 23 Aug 2024 23:00:38 +0800 Message-ID: <20240823150040.1567062-11-linyunsheng@huawei.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20240823150040.1567062-1-linyunsheng@huawei.com> References: <20240823150040.1567062-1-linyunsheng@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.90.30.45] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To dggpemf200006.china.huawei.com (7.185.36.61) X-Rspam-User: X-Stat-Signature: yo1q7wqb51yuko3i3b8m154jpgqjn56p X-Rspamd-Queue-Id: 1AB751C0029 X-Rspamd-Server: rspam11 X-HE-Tag: 1724425623-805963 X-HE-Meta: U2FsdGVkX18qACamAifJK5WQph/kOcoNJ+8Ruj5IZ4ruxJsakpzV4f6jSEx1A/MQjSONSjpYnLT99Mzu6NwY1jPPnxU/eF9PMtnm0EyF/X8DLAl31Kw3aC/uVrM1Y08gd0355ZumJzlO736d4GIeK9AZsr5j8sR1AIOHYpb7KLga18NfEx6L/IzH3iicyDxab9bHdHXSae5bWupjY/T/R3XsBEmkL1aqmy3JxYNaKapImbYPmT/QwNI813ZURN5bORpa96YQTBc4kVlYZfRUbWQw/xOEdXRSYGGSqB8sABZvmAysyMB2+mnkkn77MME4h8Zuxg36aD21pkbG5LYyXMs0t1t8s9CJ/5WMC3oq0E9PXhOx4nFox+ucDmKPwWOwDzLq6AjgbSeVpjJ7Z1drugeIV2M3njIJE0jIXKHqNx7/6htJGAKzR7JWV+K9EXJ4P25U16ZLWsamO0bsavR/mnCQ5aUelL9O1YgC/eNZEC9Z08JeyXOZhh/WJItzjMjF2LCVwPGRgD8ktH8WWAqinCAF64CLasKW/bTx13zwCSLa6eFxBqzQwCx9CK5FH/Pk3nvFuALYobByAf1Eq8FfX+B9yTuA7egEZ9VnfG0xtrZafJBruCiieEim18ihQrOHz9i9HrlBltCH1fV+2dq5iVUO9qXMISWSgOtvTSyfYctV8nOqbm0m4veAhQlmzo7zBqJxb+ttCP7lrj+pNXdTR40xGAsNN0m1LEjId/43crzyeZzm0XVYKjFZ8R7kdm3FEASvNAicrNjX7qb0r4Dcfe0xxphNiR6d4IQfcS3/j4Nfa9ZXNN9EX3ftbC65xfoJ9HRTMy+bnz8nsbMST7z7sxpQcohuQq/8WgAgeOq+QvUCRd6TsYd+lpCTHs35ohToil5xAHr7MsuHObJ4KXyb+tchDsucKcb0heWUW0gUv86TlMo8gNBCQjb6D6m/0/xx3yz+2waYcCvh10nQ5Hl HhxxJ0fF pJ5jCIXFW5/KdLMJl8ZECpq2bnF8WQam5LWM5EbFNq4O5PakN8+xrAm+YImIsgKQmofGpCrzI1uy7lxFDIVnPVbMVP3wMhoBe/qnSZUGMXsA692vi47JD3CLdpmrwBbj9LjrGG8OMHJwnpZE6BfTJJUhDCBpRQxFNmROxk/IU2k0DSgEwdPXSF4V+7Uhb3G9IfwN06Azh60514lotJuylS9zU8xsJhQtRpQR2YO/3WCrWICDMpf2n8/oaMUSa2mF1tLVzPQy6lXSTHkDMHrTgauP4ykKFmyeXI3M7 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Update documentation about design, implementation and API usages for page_frag. CC: Alexander Duyck Signed-off-by: Yunsheng Lin --- Documentation/mm/page_frags.rst | 173 +++++++++++++++++++++- include/linux/page_frag_cache.h | 250 ++++++++++++++++++++++++++++++++ mm/page_frag_cache.c | 12 +- 3 files changed, 432 insertions(+), 3 deletions(-) diff --git a/Documentation/mm/page_frags.rst b/Documentation/mm/page_frags.rst index 503ca6cdb804..12c881c90589 100644 --- a/Documentation/mm/page_frags.rst +++ b/Documentation/mm/page_frags.rst @@ -1,3 +1,5 @@ +.. SPDX-License-Identifier: GPL-2.0 + ============== Page fragments ============== @@ -40,4 +42,173 @@ page via a single call. The advantage to doing this is that it allows for cleaning up the multiple references that were added to a page in order to avoid calling get_page per allocation. -Alexander Duyck, Nov 29, 2016. + +Architecture overview +===================== + +.. code-block:: none + + +----------------------+ + | page_frag API caller | + +----------------------+ + | + | + v + +------------------------------------------------------------------+ + | request page fragment | + +------------------------------------------------------------------+ + | | | + | | | + | Cache not enough | + | | | + | +-----------------+ | + | | reuse old cache |--Usable-->| + | +-----------------+ | + | | | + | Not usable | + | | | + | v | + Cache empty +-----------------+ | + | | drain old cache | | + | +-----------------+ | + | | | + v_________________________________v | + | | + | | + _________________v_______________ | + | | Cache is enough + | | | + PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE | | + | | | + | PAGE_SIZE >= PAGE_FRAG_CACHE_MAX_SIZE | + v | | + +----------------------------------+ | | + | refill cache with order > 0 page | | | + +----------------------------------+ | | + | | | | + | | | | + | Refill failed | | + | | | | + | v v | + | +------------------------------------+ | + | | refill cache with order 0 page | | + | +----------------------------------=-+ | + | | | + Refill succeed | | + | Refill succeed | + | | | + v v v + +------------------------------------------------------------------+ + | allocate fragment from cache | + +------------------------------------------------------------------+ + +API interface +============= +As the design and implementation of page_frag API implies, the allocation side +does not allow concurrent calling. Instead it is assumed that the caller must +ensure there is not concurrent alloc calling to the same page_frag_cache +instance by using its own lock or rely on some lockless guarantee like NAPI +softirq. + +Depending on different aligning requirement, the page_frag API caller may call +page_frag_alloc*_align*() to ensure the returned virtual address or offset of +the page is aligned according to the 'align/alignment' parameter. Note the size +of the allocated fragment is not aligned, the caller needs to provide an aligned +fragsz if there is an alignment requirement for the size of the fragment. + +Depending on different use cases, callers expecting to deal with va, page or +both va and page for them may call page_frag_alloc, page_frag_refill, or +page_frag_alloc_refill API accordingly. + +There is also a use case that needs minimum memory in order for forward progress, +but more performant if more memory is available. Using page_frag_alloc_prepare() +and page_frag_alloc_commit() related API, the caller requests the minimum memory +it needs and the prepare API will return the maximum size of the fragment +returned. The caller needs to either call the commit API to report how much +memory it actually uses, or not do so if deciding to not use any memory. + +.. kernel-doc:: include/linux/page_frag_cache.h + :identifiers: page_frag_cache_init page_frag_cache_is_pfmemalloc + page_frag_cache_page_offset __page_frag_alloc_align + page_frag_alloc_align page_frag_alloc + __page_frag_refill_align page_frag_refill_align + page_frag_refill __page_frag_refill_prepare_align + page_frag_refill_prepare_align page_frag_refill_prepare + __page_frag_alloc_refill_prepare_align + page_frag_alloc_refill_prepare_align + page_frag_alloc_refill_prepare + __page_frag_alloc_refill_probe_align + page_frag_alloc_refill_probe page_frag_refill_probe + page_frag_commit page_frag_commit_noref + page_frag_alloc_abort + +.. kernel-doc:: mm/page_frag_cache.c + :identifiers: page_frag_cache_drain page_frag_free + +Coding examples +=============== + +Init & Drain API +---------------- + +.. code-block:: c + + page_frag_cache_init(pfrag); + ... + page_frag_cache_drain(pfrag); + + +Alloc & Free API +---------------- + +.. code-block:: c + + void *va; + + va = page_frag_alloc_align(pfrag, size, gfp, align); + if (!va) + goto do_error; + + err = do_something(va, size); + if (err) { + page_frag_free(va); + goto do_error; + } + +Prepare & Commit API +-------------------- + +.. code-block:: c + + struct page_frag page_frag, *pfrag; + bool merge = true; + void *va; + + pfrag = &page_frag; + va = page_frag_alloc_refill_prepare(nc, 32U, pfrag, GFP_KERNEL); + if (!va) + goto wait_for_space; + + copy = min_t(unsigned int, copy, pfrag->size); + if (!skb_can_coalesce(skb, i, pfrag->page, pfrag->offset)) { + if (i >= max_skb_frags) + goto new_segment; + + merge = false; + } + + copy = mem_schedule(copy); + if (!copy) + goto wait_for_space; + + err = copy_from_iter_full_nocache(va, copy, iter); + if (err) + goto do_error; + + if (merge) { + skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); + page_frag_commit_noref(nc, pfrag, copy); + } else { + skb_fill_page_desc(skb, i, pfrag->page, pfrag->offset, copy); + page_frag_commit(nc, pfrag, copy); + } diff --git a/include/linux/page_frag_cache.h b/include/linux/page_frag_cache.h index 5a064f74eac2..b68b6874aa2d 100644 --- a/include/linux/page_frag_cache.h +++ b/include/linux/page_frag_cache.h @@ -58,11 +58,28 @@ static inline struct page *page_pool_encoded_page_ptr(unsigned long encoded_page return virt_to_page((void *)encoded_page); } +/** + * page_frag_cache_init() - Init page_frag cache. + * @nc: page_frag cache from which to init + * + * Inline helper to init the page_frag cache. + */ static inline void page_frag_cache_init(struct page_frag_cache *nc) { nc->encoded_page = 0; } +/** + * page_frag_cache_is_pfmemalloc() - Check for pfmemalloc. + * @nc: page_frag cache from which to check + * + * Used to check if the current page in page_frag cache is pfmemalloc'ed. + * It has the same calling context expectation as the alloc API. + * + * Return: + * true if the current page in page_frag cache is pfmemalloc'ed, otherwise + * return false. + */ static inline bool page_frag_cache_is_pfmemalloc(struct page_frag_cache *nc) { return page_pool_encoded_page_pfmemalloc(nc->encoded_page); @@ -73,6 +90,16 @@ static inline unsigned int page_frag_cache_page_size(unsigned long encoded_page) return PAGE_SIZE << page_pool_encoded_page_order(encoded_page); } +/** + * page_frag_cache_page_offset() - Return the current page fragment's offset. + * @nc: page_frag cache from which to check + * + * The API is only used in net/sched/em_meta.c for historical reason, do not use + * it for new caller unless there is a strong reason. + * + * Return: + * the offset of the current page fragment in the page_frag cache. + */ static inline unsigned int page_frag_cache_page_offset(const struct page_frag_cache *nc) { return nc->offset; @@ -102,6 +129,19 @@ static inline void __page_frag_cache_commit(struct page_frag_cache *nc, nc->offset = pfrag->offset + used_sz; } +/** + * __page_frag_alloc_align() - Alloc a page fragment with aligning + * requirement. + * @nc: page_frag cache from which to allocate + * @fragsz: the requested fragment size + * @gfp_mask: the allocation gfp to use when cache need to be refilled + * @align_mask: the requested aligning requirement for the 'va' + * + * Get a page fragment from page_frag cache with aligning requirement. + * + * Return: + * Return va of the page fragment, otherwise return NULL. + */ static inline void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask, unsigned int align_mask) { @@ -117,6 +157,19 @@ static inline void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned return va; } +/** + * page_frag_alloc_align() - Alloc a page fragment with aligning requirement. + * @nc: page_frag cache from which to allocate + * @fragsz: the requested fragment size + * @gfp_mask: the allocation gfp to use when cache needs to be refilled + * @align: the requested aligning requirement for virtual address of fragment + * + * WARN_ON_ONCE() checking for @align before allocing a page fragment from + * page_frag cache with aligning requirement. + * + * Return: + * virtual address of the page fragment, otherwise return NULL. + */ static inline void *page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask, unsigned int align) @@ -125,12 +178,36 @@ static inline void *page_frag_alloc_align(struct page_frag_cache *nc, return __page_frag_alloc_align(nc, fragsz, gfp_mask, -align); } +/** + * page_frag_alloc() - Alloc a page fragment. + * @nc: page_frag cache from which to allocate + * @fragsz: the requested fragment size + * @gfp_mask: the allocation gfp to use when cache need to be refilled + * + * Get a page fragment from page_frag cache. + * + * Return: + * virtual address of the page fragment, otherwise return NULL. + */ static inline void *page_frag_alloc(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask) { return __page_frag_alloc_align(nc, fragsz, gfp_mask, ~0u); } +/** + * __page_frag_refill_align() - Refill a page_frag with aligning requirement. + * @nc: page_frag cache from which to refill + * @fragsz: the requested fragment size + * @pfrag: the page_frag to be refilled. + * @gfp_mask: the allocation gfp to use when cache need to be refilled + * @align_mask: the requested aligning requirement for the 'va' + * + * Refill a page_frag from page_frag cache with aligning requirement. + * + * Return: + * Return true if refill succeeds, otherwise return false. + */ static inline bool __page_frag_refill_align(struct page_frag_cache *nc, unsigned int fragsz, struct page_frag *pfrag, gfp_t gfp_mask, unsigned int align_mask) @@ -142,6 +219,20 @@ static inline bool __page_frag_refill_align(struct page_frag_cache *nc, unsigned return true; } +/** + * page_frag_refill_align() - Refill a page_frag with aligning requirement. + * @nc: page_frag cache from which to refill + * @fragsz: the requested fragment size + * @pfrag: the page_frag to be refilled. + * @gfp_mask: the allocation gfp to use when cache needs to be refilled + * @align: the requested aligning requirement for virtual address of fragment + * + * WARN_ON_ONCE() checking for @align before allocing a page fragment from + * page_frag cache with aligning requirement. + * + * Return: + * Return true if refill succeeds, otherwise return false. + */ static inline bool page_frag_refill_align(struct page_frag_cache *nc, unsigned int fragsz, struct page_frag *pfrag, gfp_t gfp_mask, unsigned int align) @@ -150,12 +241,38 @@ static inline bool page_frag_refill_align(struct page_frag_cache *nc, unsigned i return __page_frag_refill_align(nc, fragsz, pfrag, gfp_mask, -align); } +/** + * page_frag_refill() - Refill a page_frag. + * @nc: page_frag cache from which to refill + * @fragsz: the requested fragment size + * @pfrag: the page_frag to be refilled. + * @gfp_mask: the allocation gfp to use when cache need to be refilled + * + * Get a page fragment from page_frag cache. + * + * Return: + * Return true if refill succeeds, otherwise return false. + */ static inline bool page_frag_refill(struct page_frag_cache *nc, unsigned int fragsz, struct page_frag *pfrag, gfp_t gfp_mask) { return __page_frag_refill_align(nc, fragsz, pfrag, gfp_mask, ~0u); } +/** + * __page_frag_refill_prepare_align() - Prepare refilling a page_frag with aligning + * requirement. + * @nc: page_frag cache from which to refill + * @fragsz: the requested fragment size + * @pfrag: the page_frag to be refilled. + * @gfp_mask: the allocation gfp to use when cache need to be refilled + * @align_mask: the requested aligning requirement for the 'va' + * + * Prepare refill a page_frag from page_frag cache with aligning requirement. + * + * Return: + * Return true if prepare refilling succeeds, otherwise return false. + */ static inline bool __page_frag_refill_prepare_align(struct page_frag_cache *nc, unsigned int fragsz, struct page_frag *pfrag, @@ -165,6 +282,21 @@ static inline bool __page_frag_refill_prepare_align(struct page_frag_cache *nc, return !!__page_frag_cache_prepare(nc, fragsz, pfrag, gfp_mask, align_mask); } +/** + * page_frag_refill_prepare_align() - Prepare refilling a page_frag with aligning + * requirement. + * @nc: page_frag cache from which to refill + * @fragsz: the requested fragment size + * @pfrag: the page_frag to be refilled. + * @gfp_mask: the allocation gfp to use when cache needs to be refilled + * @align: the requested aligning requirement for virtual address of fragment + * + * WARN_ON_ONCE() checking for @align before prepare refilling a page_frag from + * page_frag cache with aligning requirement. + * + * Return: + * Return true if prepare refilling succeeds, otherwise return false. + */ static inline bool page_frag_refill_prepare_align(struct page_frag_cache *nc, unsigned int fragsz, struct page_frag *pfrag, @@ -175,6 +307,18 @@ static inline bool page_frag_refill_prepare_align(struct page_frag_cache *nc, return __page_frag_refill_prepare_align(nc, fragsz, pfrag, gfp_mask, -align); } +/** + * page_frag_refill_prepare() - Prepare refilling a page_frag. + * @nc: page_frag cache from which to refill + * @fragsz: the requested fragment size + * @pfrag: the page_frag to be refilled. + * @gfp_mask: the allocation gfp to use when cache need to be refilled + * + * Prepare refilling a page_frag from page_frag cache. + * + * Return: + * Return true if refill succeeds, otherwise return false. + */ static inline bool page_frag_refill_prepare(struct page_frag_cache *nc, unsigned int fragsz, struct page_frag *pfrag, @@ -183,6 +327,20 @@ static inline bool page_frag_refill_prepare(struct page_frag_cache *nc, return __page_frag_refill_prepare_align(nc, fragsz, pfrag, gfp_mask, ~0u); } +/** + * __page_frag_alloc_refill_prepare_align() - Prepare allocing a fragment and + * refilling a page_frag with aligning requirement. + * @nc: page_frag cache from which to allocate and refill + * @fragsz: the requested fragment size + * @pfrag: the page_frag to be prepared. + * @gfp_mask: the allocation gfp to use when cache need to be refilled + * @align_mask: the requested aligning requirement for the fragment. + * + * Prepare allocing a fragment and refilling a page_frag from page_frag cache. + * + * Return: + * virtual address of the page fragment, otherwise return NULL. + */ static inline void *__page_frag_alloc_refill_prepare_align(struct page_frag_cache *nc, unsigned int fragsz, struct page_frag *pfrag, @@ -192,6 +350,21 @@ static inline void *__page_frag_alloc_refill_prepare_align(struct page_frag_cach return __page_frag_cache_prepare(nc, fragsz, pfrag, gfp_mask, align_mask); } +/** + * page_frag_alloc_refill_prepare_align() - Prepare allocing a fragment and + * refilling a page_frag with aligning requirement. + * @nc: page_frag cache from which to allocate and refill + * @fragsz: the requested fragment size + * @pfrag: the page_frag to be prepared. + * @gfp_mask: the allocation gfp to use when cache need to be refilled + * @align: the requested aligning requirement for the fragment. + * + * WARN_ON_ONCE() checking for @align before prepare allocing a fragment and + * refilling a page_frag from page_frag cache. + * + * Return: + * virtual address of the page fragment, otherwise return NULL. + */ static inline void *page_frag_alloc_refill_prepare_align(struct page_frag_cache *nc, unsigned int fragsz, struct page_frag *pfrag, @@ -202,6 +375,19 @@ static inline void *page_frag_alloc_refill_prepare_align(struct page_frag_cache return __page_frag_alloc_refill_prepare_align(nc, fragsz, pfrag, gfp_mask, -align); } +/** + * page_frag_alloc_refill_prepare() - Prepare allocing a fragment and refilling + * a page_frag. + * @nc: page_frag cache from which to allocate and refill + * @fragsz: the requested fragment size + * @pfrag: the page_frag to be prepared. + * @gfp_mask: the allocation gfp to use when cache need to be refilled + * + * Prepare allocing a fragment and refilling a page_frag from page_frag cache. + * + * Return: + * virtual address of the page fragment, otherwise return NULL. + */ static inline void *page_frag_alloc_refill_prepare(struct page_frag_cache *nc, unsigned int fragsz, struct page_frag *pfrag, @@ -210,6 +396,19 @@ static inline void *page_frag_alloc_refill_prepare(struct page_frag_cache *nc, return __page_frag_alloc_refill_prepare_align(nc, fragsz, pfrag, gfp_mask, ~0u); } +/** + * __page_frag_alloc_refill_probe_align() - Probe allocing a fragment and refilling + * a page_frag with aligning requirement. + * @nc: page_frag cache from which to allocate and refill + * @fragsz: the requested fragment size + * @pfrag: the page_frag to be probed. + * @align_mask: the requested aligning requirement for the fragment. + * + * Probe allocing a fragment and refilling a page_frag from page_frag cache. + * + * Return: + * virtual address of the page fragment, otherwise return NULL. + */ static inline void *__page_frag_alloc_refill_probe_align(struct page_frag_cache *nc, unsigned int fragsz, struct page_frag *pfrag, @@ -230,6 +429,18 @@ static inline void *__page_frag_alloc_refill_probe_align(struct page_frag_cache return page_pool_encoded_page_address(encoded_page) + offset; } +/** + * page_frag_alloc_refill_probe() - Probe allocing a fragment and refilling + * a page_frag. + * @nc: page_frag cache from which to allocate and refill + * @fragsz: the requested fragment size + * @pfrag: the page_frag to be probed + * + * Probe allocing a fragment and refilling a page_frag from page_frag cache. + * + * Return: + * virtual address of the page fragment, otherwise return NULL. + */ static inline void *page_frag_alloc_refill_probe(struct page_frag_cache *nc, unsigned int fragsz, struct page_frag *pfrag) @@ -237,6 +448,17 @@ static inline void *page_frag_alloc_refill_probe(struct page_frag_cache *nc, return __page_frag_alloc_refill_probe_align(nc, fragsz, pfrag, ~0u); } +/** + * page_frag_refill_probe() - Probe refilling a page_frag. + * @nc: page_frag cache from which to refill + * @fragsz: the requested fragment size + * @pfrag: the page_frag to be probed + * + * Probe refilling a page_frag from page_frag cache. + * + * Return: + * Return true if refill succeeds, otherwise return false. + */ static inline bool page_frag_refill_probe(struct page_frag_cache *nc, unsigned int fragsz, struct page_frag *pfrag) @@ -244,18 +466,46 @@ static inline bool page_frag_refill_probe(struct page_frag_cache *nc, return !!page_frag_alloc_refill_probe(nc, fragsz, pfrag); } +/** + * page_frag_commit - Commit allocing a page fragment. + * @nc: page_frag cache from which to commit + * @pfrag: the page_frag to be committed + * @used_sz: size of the page fragment has been used + * + * Commit the actual used size for the allocation that was either prepared or + * probed. + */ static inline void page_frag_commit(struct page_frag_cache *nc, struct page_frag *pfrag, unsigned int used_sz) { __page_frag_cache_commit(nc, pfrag, true, used_sz); } +/** + * page_frag_commit_noref - Commit allocing a page fragment without taking + * page refcount. + * @nc: page_frag cache from which to commit + * @pfrag: the page_frag to be committed + * @used_sz: size of the page fragment has been used + * + * Commit the alloc preparing or probing by passing the actual used size, but + * not taking refcount. Mostly used for fragmemt coalescing case when the + * current fragment can share the same refcount with previous fragment. + */ static inline void page_frag_commit_noref(struct page_frag_cache *nc, struct page_frag *pfrag, unsigned int used_sz) { __page_frag_cache_commit(nc, pfrag, false, used_sz); } +/** + * page_frag_alloc_abort - Abort the page fragment allocation. + * @nc: page_frag cache to which the page fragment is aborted back + * @fragsz: size of the page fragment to be aborted + * + * It is expected to be called from the same context as the alloc API. + * Mostly used for error handling cases where the fragment is no longer needed. + */ static inline void page_frag_alloc_abort(struct page_frag_cache *nc, unsigned int fragsz) { VM_BUG_ON(fragsz > nc->offset); diff --git a/mm/page_frag_cache.c b/mm/page_frag_cache.c index b3053a0f38aa..2c8de60bbae7 100644 --- a/mm/page_frag_cache.c +++ b/mm/page_frag_cache.c @@ -48,6 +48,10 @@ static struct page *__page_frag_cache_refill(struct page_frag_cache *nc, return page; } +/** + * page_frag_cache_drain - Drain the current page from page_frag cache. + * @nc: page_frag cache from which to drain + */ void page_frag_cache_drain(struct page_frag_cache *nc) { if (!nc->encoded_page) @@ -138,8 +142,12 @@ void *__page_frag_cache_prepare(struct page_frag_cache *nc, unsigned int fragsz, } EXPORT_SYMBOL(__page_frag_cache_prepare); -/* - * Frees a page fragment allocated out of either a compound or order 0 page. +/** + * page_frag_free - Free a page fragment. + * @addr: va of page fragment to be freed + * + * Free a page fragment allocated out of either a compound or order 0 page by + * virtual address. */ void page_frag_free(void *addr) {