From patchwork Mon Apr 15 13:19:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yunsheng Lin X-Patchwork-Id: 13630034 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 00F45C4345F for ; Mon, 15 Apr 2024 13:22:23 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id C18986B00A3; Mon, 15 Apr 2024 09:22:21 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id BC80D6B00A4; Mon, 15 Apr 2024 09:22:21 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A1A1D6B00A5; Mon, 15 Apr 2024 09:22:21 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id 7E7DF6B00A3 for ; Mon, 15 Apr 2024 09:22:21 -0400 (EDT) Received: from smtpin01.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id 1D2F5C054C for ; Mon, 15 Apr 2024 13:22:21 +0000 (UTC) X-FDA: 82011830082.01.4F12325 Received: from szxga07-in.huawei.com (szxga07-in.huawei.com [45.249.212.35]) by imf06.hostedemail.com (Postfix) with ESMTP id BE08A180011 for ; Mon, 15 Apr 2024 13:22:18 +0000 (UTC) Authentication-Results: imf06.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf06.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.35 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=1713187339; 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=9s6PoiFEfUU1t6RgwVkprdTMCiqw+5QdXvBJfqgSCtk=; b=tdtHw7bG9Ysd5Nd14DraKT6HW+7Op+rr8OcgUX2NPVNl56akWYA4w5lNLOyc+8Rh0a8QdG 0XJRIwt9kwY/tKhf8ZLmEzYmu5S3zuO+F9QiL6fY1skMLWKkkAE8X2h4rc64DS4n2nEJRz 7wd4iF9zsgqhOQlNp1imADoImhlctGE= ARC-Authentication-Results: i=1; imf06.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf06.hostedemail.com: domain of linyunsheng@huawei.com designates 45.249.212.35 as permitted sender) smtp.mailfrom=linyunsheng@huawei.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1713187339; a=rsa-sha256; cv=none; b=uJK9MvDuBDi4kBBqUx36P/+P7qBvJ9JxjDIBbWhbBmuYxmmHvA1ghl4vRBO3xor3famxOq u+YpWTeQihEt8Iy5NX/aS30ADM3NrbIDdbWSZi+Y8gd8qfrum35STt0oYDeHFMmuAHiHls kwi5LpF6jAY4TxFZffoSi05qXTLTBXU= Received: from mail.maildlp.com (unknown [172.19.88.163]) by szxga07-in.huawei.com (SkyGuard) with ESMTP id 4VJ76v2HPmz1fxcp; Mon, 15 Apr 2024 21:19:19 +0800 (CST) Received: from dggpemm500005.china.huawei.com (unknown [7.185.36.74]) by mail.maildlp.com (Postfix) with ESMTPS id 15A9818002D; Mon, 15 Apr 2024 21:22:16 +0800 (CST) Received: from localhost.localdomain (10.69.192.56) by dggpemm500005.china.huawei.com (7.185.36.74) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 15 Apr 2024 21:22:15 +0800 From: Yunsheng Lin To: , , CC: , , Yunsheng Lin , Alexander Duyck , Andrew Morton , Subject: [PATCH net-next v2 10/15] mm: page_frag: reuse existing bit field of 'va' for pagecnt_bias Date: Mon, 15 Apr 2024 21:19:35 +0800 Message-ID: <20240415131941.51153-11-linyunsheng@huawei.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20240415131941.51153-1-linyunsheng@huawei.com> References: <20240415131941.51153-1-linyunsheng@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.69.192.56] X-ClientProxiedBy: dggems706-chm.china.huawei.com (10.3.19.183) To dggpemm500005.china.huawei.com (7.185.36.74) X-Rspamd-Queue-Id: BE08A180011 X-Rspam-User: X-Rspamd-Server: rspam05 X-Stat-Signature: p5ub1pwfnim15ykgwywr73or5yjj6j4k X-HE-Tag: 1713187338-71440 X-HE-Meta: U2FsdGVkX195+/kFfwmR0kyWU+J46eWIk/q7g/grQjdTwcDC1UZaddXLUUWkHy0nby3uocuDRWMORemuEesywueagSNegibRdaF3TIOHb7BdxuXCEBb0JB7wQSRi1SaUd+JKve25LCfktlBPjiFm+Waz6a9OAYzGReM/uYJlqYTJK1g0becaRJbyecyUFyUs0YlNXx7wF9uxjMSmcXcnG48OR2a5xAWHvpq7RJLLmZQHxZrR3nwt56pvA36Wu/eXXZtMZ51U40zvibawLa9vdu4BAZyQF1ZMI+/XqPyPVUqeNgHxZ885/EvGA6Y5gWQ/tLE94mg8c9leXtPOzJt6knoq7rUaCZluJjXQEv7F9jr4CLA7JH50ghaKkvbp6h0SWGaxe9k12TC2W42kzHd/zGj/1qcu7J297liR12dP2b72EFFm8g1r6stgy9juqTjnRtAq8qXZ05bf0nNsvluHz0xT5kBi8lHcNwY8VQhdiSgH7kK3gRAN4AhW0I/MSgGOLUuio20yi0QTUHhVjXVXoV4byNvX5oosyPKT0UJUYGRgxTyV3OWySaBmGSDihk37LdnvKK9bAmSjvHUpyanX7LLGs5rZAWcTq3iV6/nkKP8LuTTfdJ0qIdv/xumF6PTdf5NQBU+FBLGQQeRZZMT6hYDFC2aOrmiU3xACnyk3Jdu1+To6etpp6HS4jrNc+tp0D0ZCE8SWWVvfz3GC7NJlBMEHp8RczTmZhdPrPm6LdJoumCAahzCnpdK7+sEdSEaE+ckSD+A07lndJQB1X/An9Z4muuTYT65XF99NZgVQCIFvNbjZC0OprPveYQTlIER/H57zXfwRSrYTQHDg03nRGFMb+oX0cq4V64a0NqjXVZn054sETKzJEvnzoUAwo6tdeIvEps8RjBPssCvehuspOATorBPSRXfRjqwc4QRyGXXnb6rxWqzIphIbijFZlIQaKIAZZ3PU7WlXoINzbX2 0N3IRtU7 lyjSViPllIfoZtF36NiIAUcu6liXGgyBEyR+K8CokDBjaZwCZzFkgRtO5At2W1U5H6belpX5HLZ7Ivt6k/jGGXnchAb5tGEOnRw4988x+hkpHlkH5SpwbHE1rOWpdCOT6g3VFYULpgvV4WXfHXGhBIBKa/i2985OiobmBZ0owXrwqxdvocXjHMHecS50Kpf+gkj2mWebhqvL6A7/85AzXukjVZ2mh40wxJuS9m+uFLGuB6i2sy4U30NGvJznn7A1qlQRs06/lE8646dM= 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: As alignment of 'va' is always aligned with the order of the page allocated, we can reuse the LSB bits for the pagecount bias, and remove the orginal space needed by 'pagecnt_bias'. Also limit the 'fragsz' to be at least the size of 'usigned int' to match the limited pagecnt_bias. Signed-off-by: Yunsheng Lin --- include/linux/page_frag_cache.h | 20 +++++++---- mm/page_frag_cache.c | 63 +++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/include/linux/page_frag_cache.h b/include/linux/page_frag_cache.h index 40a7d6da9ef0..a97a1ac017d6 100644 --- a/include/linux/page_frag_cache.h +++ b/include/linux/page_frag_cache.h @@ -9,7 +9,18 @@ #define PAGE_FRAG_CACHE_MAX_ORDER get_order(PAGE_FRAG_CACHE_MAX_SIZE) struct page_frag_cache { - void *va; + union { + void *va; + /* we maintain a pagecount bias, so that we dont dirty cache + * line containing page->_refcount every time we allocate a + * fragment. As 'va' is always aligned with the order of the + * page allocated, we can reuse the LSB bits for the pagecount + * bias, and its bit width happens to be indicated by the + * 'size_mask' below. + */ + unsigned long pagecnt_bias; + + }; #if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) __u16 offset; __u16 size_mask:15; @@ -18,10 +29,6 @@ struct page_frag_cache { __u32 offset:31; __u32 pfmemalloc:1; #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; }; static inline void page_frag_cache_init(struct page_frag_cache *nc) @@ -56,7 +63,8 @@ static inline void *page_frag_alloc_va_align(struct page_frag_cache *nc, gfp_t gfp_mask, unsigned int align) { - WARN_ON_ONCE(!is_power_of_2(align) || align >= PAGE_SIZE); + WARN_ON_ONCE(!is_power_of_2(align) || align >= PAGE_SIZE || + fragsz < sizeof(unsigned int)); return __page_frag_alloc_va_align(nc, fragsz, gfp_mask, align); } diff --git a/mm/page_frag_cache.c b/mm/page_frag_cache.c index 8d93029116e1..5f7f96c88163 100644 --- a/mm/page_frag_cache.c +++ b/mm/page_frag_cache.c @@ -18,8 +18,8 @@ #include #include "internal.h" -static struct page *__page_frag_cache_refill(struct page_frag_cache *nc, - gfp_t gfp_mask) +static bool __page_frag_cache_refill(struct page_frag_cache *nc, + gfp_t gfp_mask) { struct page *page = NULL; gfp_t gfp = gfp_mask; @@ -38,9 +38,26 @@ static struct page *__page_frag_cache_refill(struct page_frag_cache *nc, if (unlikely(!page)) page = alloc_pages_node(NUMA_NO_NODE, gfp, 0); - nc->va = page ? page_address(page) : NULL; + if (unlikely(!page)) { + nc->va = NULL; + return false; + } + + nc->va = page_address(page); - return page; +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) + VM_BUG_ON(nc->pagecnt_bias & nc->size_mask); + page_ref_add(page, nc->size_mask - 1); + nc->pagecnt_bias |= nc->size_mask; +#else + VM_BUG_ON(nc->pagecnt_bias & (PAGE_SIZE - 1)); + page_ref_add(page, PAGE_SIZE - 2); + nc->pagecnt_bias |= (PAGE_SIZE - 1); +#endif + + nc->pfmemalloc = page_is_pfmemalloc(page); + nc->offset = 0; + return true; } void page_frag_cache_drain(struct page_frag_cache *nc) @@ -65,38 +82,31 @@ EXPORT_SYMBOL(__page_frag_cache_drain); void *page_frag_alloc_va(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask) { - unsigned int size, offset; + unsigned long size_mask; + unsigned int offset; struct page *page; + void *va; if (unlikely(!nc->va)) { refill: - page = __page_frag_cache_refill(nc, gfp_mask); - if (!page) + if (!__page_frag_cache_refill(nc, gfp_mask)) return NULL; - - /* 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; } #if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) /* if size can vary use size else just use PAGE_SIZE */ - size = nc->size_mask + 1; + size_mask = nc->size_mask; #else - size = PAGE_SIZE; + size_mask = PAGE_SIZE - 1; #endif + va = (void *)((unsigned long)nc->va & ~size_mask); offset = nc->offset; - if (unlikely(offset + fragsz > size)) { - page = virt_to_page(nc->va); - if (!page_ref_sub_and_test(page, nc->pagecnt_bias)) + if (unlikely(offset + fragsz > (size_mask + 1))) { + page = virt_to_page(va); + + if (!page_ref_sub_and_test(page, nc->pagecnt_bias & size_mask)) goto refill; if (unlikely(nc->pfmemalloc)) { @@ -105,12 +115,11 @@ void *page_frag_alloc_va(struct page_frag_cache *nc, unsigned int fragsz, } /* OK, page count is 0, we can safely set it */ - set_page_count(page, PAGE_FRAG_CACHE_MAX_SIZE + 1); + set_page_count(page, size_mask); + nc->pagecnt_bias |= size_mask; - /* reset page count bias and offset to start of new frag */ - nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1; offset = 0; - if (unlikely(fragsz > size)) { + if (unlikely(fragsz > (size_mask + 1))) { /* * The caller is trying to allocate a fragment * with fragsz > PAGE_SIZE but the cache isn't big @@ -127,7 +136,7 @@ void *page_frag_alloc_va(struct page_frag_cache *nc, unsigned int fragsz, nc->pagecnt_bias--; nc->offset = offset + fragsz; - return nc->va + offset; + return va + offset; } EXPORT_SYMBOL(page_frag_alloc_va);