From mboxrd@z Thu Jan 1 00:00:00 1970 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 14B1DC25B7A for ; Wed, 15 May 2024 05:57:32 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 7577D6B03CC; Wed, 15 May 2024 01:57:32 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 6E7E66B03CE; Wed, 15 May 2024 01:57:32 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 4B81E6B03CD; Wed, 15 May 2024 01:57:32 -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 2761B6B03CB for ; Wed, 15 May 2024 01:57:32 -0400 (EDT) Received: from smtpin17.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id E0F2A403F2 for ; Wed, 15 May 2024 05:57:31 +0000 (UTC) X-FDA: 82119573102.17.4301FB4 Received: from mailout1.w1.samsung.com (mailout1.w1.samsung.com [210.118.77.11]) by imf09.hostedemail.com (Postfix) with ESMTP id E38C5140006 for ; Wed, 15 May 2024 05:57:28 +0000 (UTC) Authentication-Results: imf09.hostedemail.com; dkim=pass header.d=samsung.com header.s=mail20170921 header.b=sqVMr3yB; spf=pass (imf09.hostedemail.com: domain of da.gomez@samsung.com designates 210.118.77.11 as permitted sender) smtp.mailfrom=da.gomez@samsung.com; dmarc=pass (policy=none) header.from=samsung.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1715752649; 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:dkim-signature; bh=6AbpwZVsLVgVT3CkKdkc06GB5sYOIf3QpK6XfswU18c=; b=n2ttg7Ou7c+4Lyb9dppHnT4Ju267QaxDEVbfw9Se3CAvFFflLnDV+OJpibcCHkvKFcsRzK 0U8bYmUvyy07tQCUUQrmiDQxk2FkZKrqafltRKoMQpdUXc/jTQz8bxCG4OuylffcsRtAzN adqvQwh5U69OAEdj9b/M66Ip475POaM= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1715752649; a=rsa-sha256; cv=none; b=iGl3401R0/L8nOvpZJxORuwOx8JpACavc7xh7O0TJswdZ80GGueA1nacGYw+DK5cc35Ykb KH2F6baAbdkDjGZULcq4cdK9uui2IDAH5qZ3sOFKENTx0Jgp4Ru9tXgfQdm2y1irdKDfD3 xxHpXpFWuVV4c8Q6X3Uj310KrfWpmzs= ARC-Authentication-Results: i=1; imf09.hostedemail.com; dkim=pass header.d=samsung.com header.s=mail20170921 header.b=sqVMr3yB; spf=pass (imf09.hostedemail.com: domain of da.gomez@samsung.com designates 210.118.77.11 as permitted sender) smtp.mailfrom=da.gomez@samsung.com; dmarc=pass (policy=none) header.from=samsung.com Received: from eucas1p1.samsung.com (unknown [182.198.249.206]) by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id 20240515055727euoutp019652cb37ea0f3e89fce16584437ea93b~Pk-Ez9Kfs1504315043euoutp01X for ; Wed, 15 May 2024 05:57:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20240515055727euoutp019652cb37ea0f3e89fce16584437ea93b~Pk-Ez9Kfs1504315043euoutp01X DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1715752647; bh=6AbpwZVsLVgVT3CkKdkc06GB5sYOIf3QpK6XfswU18c=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=sqVMr3yBGELFFcJQXx0N/7y7+cX9+En6CeWCTEo1+I3rKtkXEW9MQtk9NRR80EnHe DR9jCayKCg+OHmQNrfe7y5HawvCC2YF4IrFRHU3vz3S+vekavEixFiCcrvEz0abgp8 g1KQMmmn3s7V4rXYxTgsGJ1/gMkcN3GcVX2Ml/UA= Received: from eusmges2new.samsung.com (unknown [203.254.199.244]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20240515055726eucas1p2328d05eecfcf5f4f66f26a0b452caf86~Pk-EhwvNb1215012150eucas1p2R; Wed, 15 May 2024 05:57:26 +0000 (GMT) Received: from eucas1p1.samsung.com ( [182.198.249.206]) by eusmges2new.samsung.com (EUCPMTA) with SMTP id A0.D8.09875.6CE44466; Wed, 15 May 2024 06:57:26 +0100 (BST) Received: from eusmtrp1.samsung.com (unknown [182.198.249.138]) by eucas1p2.samsung.com (KnoxPortal) with ESMTPA id 20240515055726eucas1p2a795fc743373571bfc3349f9e1ef3f9e~Pk-EEVLoG1154511545eucas1p2I; Wed, 15 May 2024 05:57:26 +0000 (GMT) Received: from eusmgms2.samsung.com (unknown [182.198.249.180]) by eusmtrp1.samsung.com (KnoxPortal) with ESMTP id 20240515055726eusmtrp1bf43dd20643a60993f5e52ab44b8af56~Pk-EDnfqX0390703907eusmtrp1u; Wed, 15 May 2024 05:57:26 +0000 (GMT) X-AuditID: cbfec7f4-131ff70000002693-d8-66444ec66dea Received: from eusmtip1.samsung.com ( [203.254.199.221]) by eusmgms2.samsung.com (EUCPMTA) with SMTP id 75.F1.09010.6CE44466; Wed, 15 May 2024 06:57:26 +0100 (BST) Received: from CAMSVWEXC01.scsc.local (unknown [106.1.227.71]) by eusmtip1.samsung.com (KnoxPortal) with ESMTPA id 20240515055726eusmtip1afeac5310d50bc39c07e1816d5c07585~Pk-D02d7J0235902359eusmtip1R; Wed, 15 May 2024 05:57:26 +0000 (GMT) Received: from CAMSVWEXC02.scsc.local (2002:6a01:e348::6a01:e348) by CAMSVWEXC01.scsc.local (2002:6a01:e347::6a01:e347) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 15 May 2024 06:57:25 +0100 Received: from CAMSVWEXC02.scsc.local ([::1]) by CAMSVWEXC02.scsc.local ([fe80::3c08:6c51:fa0a:6384%13]) with mapi id 15.00.1497.012; Wed, 15 May 2024 06:57:25 +0100 From: Daniel Gomez To: "hughd@google.com" , "akpm@linux-foundation.org" , "willy@infradead.org" , "jack@suse.cz" , "mcgrof@kernel.org" CC: "linux-mm@kvack.org" , "linux-xfs@vger.kernel.org" , "djwong@kernel.org" , "Pankaj Raghav" , "dagmcr@gmail.com" , "yosryahmed@google.com" , "baolin.wang@linux.alibaba.com" , "ritesh.list@gmail.com" , "lsf-pc@lists.linux-foundation.org" , "david@redhat.com" , "chandan.babu@oracle.com" , "linux-kernel@vger.kernel.org" , "brauner@kernel.org" , Daniel Gomez Subject: [PATCH 02/12] shmem: add per-block uptodate tracking for large folios Thread-Topic: [PATCH 02/12] shmem: add per-block uptodate tracking for large folios Thread-Index: AQHapozCeJW3qmZrtEOp+8upfVo2+A== Date: Wed, 15 May 2024 05:57:24 +0000 Message-ID: <20240515055719.32577-3-da.gomez@samsung.com> In-Reply-To: <20240515055719.32577-1-da.gomez@samsung.com> Accept-Language: en-US, en-GB Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-ms-exchange-messagesentrepresentingtype: 1 x-ms-exchange-transport-fromentityheader: Hosted x-originating-ip: [106.210.248.161] Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrIKsWRmVeSWpSXmKPExsWy7djPc7rH/FzSDI4161rMWb+GzeL/3mOM Fq8Pf2K0uHRUzuJs3282i6/rfzFbXH7CZ/H0Ux+LxezpzUwWl3fNYbO4t+Y/q8WuPzvYLfa9 3stscWPCU0aLg6c62C1+/wDKbt8V6SDosXPWXXaPBZtKPTav0PLYtKqTzWPTp0nsHidm/Gbx 2PnQ0mPyjeWMHh+f3mLxeL/vKpvHmQVH2D0+b5IL4InisklJzcksSy3St0vgymhpm8hY0OBS 0fe9g6mB8aB5FyMnh4SAicT5ef/Zuxi5OIQEVjBKrDz5gA3C+cIocbq/jwnC+cwosXvTfTaY ltudhxkhEssZJU5cO8ACV7Xo+B1mCOcMo8TyNUtYIZyVjBILdj1kB+lnE9CU2HdyE9hKEYHb jBJPT50Bc5gFTrJK/Nm8E2gYB4ewQIBEzz5DEFNEIFTi6p8gkF4RAT2JFet3MYOEWQRUJa41 BoKEeQUsJdb2b2UBsTkFrCTuzv8KdiqjgKzEo5W/wNYyC4hL3HoynwniBUGJRbP3MEPYYhL/ dj2Eek1H4uz1J4wQtoHE1qX7WCBsZYn179qYIOboSdyYOoUNwtaWWLbwNTPEDYISJ2c+AYeE hMBBLon/z7azQjS7SEzYtw9qqLDEq+Nb2CFsGYnTk3tYJjBqz0Jy3ywkO2Yh2TELyY4FjCyr GMVTS4tz01OLjfJSy/WKE3OLS/PS9ZLzczcxAlPl6X/Hv+xgXP7qo94hRiYOxkOMEhzMSiK8 ImnOaUK8KYmVValF+fFFpTmpxYcYpTlYlMR5VVPkU4UE0hNLUrNTUwtSi2CyTBycUg1MzG4H X9Q05rXOamb4cMgmuv3Rno8y8ce/XbHyOmbNcLTEzn1n5eI4oydFDxofeEzjj3+tmHCjzexc HdshvWWNX2ZnsIlfkK10PvV8m5+JzOz+edscPigc9dq6svy7yY3dT3iYbsgm5hjwbdZ9m/dS 8G/E7VMMZbHb5j1X3VVxqfpWrHbvqfn6Dpl/WwsrflSIz5nRmZrE/NmSKfPsLI+fc1UUDyZL /JyyyP6myQ/3GgU+5S0qFU8DtExLd10tfr7v1oEFgUanj2rec2E0W23s433UeebNQqkb+cmf UlY/u5P96tTCGVxSUoKR2SHhcraaO7Z+rnzLcs/55YYvdYrHmOOkMg6YM3kc/LlNzeatEktx RqKhFnNRcSIAOTw8zQQEAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrLKsWRmVeSWpSXmKPExsVy+t/xu7rH/FzSDP5cELSYs34Nm8X/vccY LV4f/sRocemonMXZvt9sFl/X/2K2uPyEz+Lppz4Wi9nTm5ksLu+aw2Zxb81/Votdf3awW+x7 vZfZ4saEp4wWB091sFv8/gGU3b4r0kHQY+esu+weCzaVemxeoeWxaVUnm8emT5PYPU7M+M3i sfOhpcfkG8sZPT4+vcXi8X7fVTaPMwuOsHt83iQXwBOlZ1OUX1qSqpCRX1xiqxRtaGGkZ2hp oWdkYqlnaGwea2VkqqRvZ5OSmpNZllqkb5egl9HSNpGxoMGlou97B1MD40HzLkZODgkBE4nb nYcZQWwhgaWMEpNui0PEZSQ2frnKCmELS/y51sXWxcgFVPORUeLNur8sEM4ZRonZW7YxQzgr GSUePWpmBmlhE9CU2HdyEztIQkTgNqPE01NnwBxmgZOsEgdOf2YHqRIW8JOYunsZ2BIRgVCJ PXubmSBsPYkV63cBTeLgYBFQlbjWGAgS5hWwlFjbv5UF4lZLiUuvtoPdzSlgJXF3/lc2EJtR QFbi0cpfYOOZBcQlbj2ZzwTxg4DEkj3nmSFsUYmXj/9B/aYjcfb6E0YI20Bi69J9LBC2ssT6 d21MEHP0JG5MncIGYWtLLFv4mhniHkGJkzOfsExglJ6FZN0sJC2zkLTMQtKygJFlFaNIamlx bnpusZFecWJucWleul5yfu4mRmC623bs55YdjCtffdQ7xMjEwXiIUYKDWUmEVyTNOU2INyWx siq1KD++qDQntfgQoykwiCYyS4km5wMTbl5JvKGZgamhiZmlgamlmbGSOK9nQUeikEB6Yklq dmpqQWoRTB8TB6dUA1PwQyvn3HrXnjO/RQR3blKfHnY5+IaEic41pxMJqy9v/rGTa+/iiG9c /MuiSjeuCXuRyKHbeLFmx6y3kW5fFz6/qnYuae9npvAVGj6y1rsdNlZ/vT3BxKvmmE7r+XDZ C1NtNJV0Fr3a2lU4RegB03o5qzcTBJvnm8YstzP/Ulb/8HyB24tc0wLFfTOstLo/38xX+Oug fEb+j7WHHu+ttfJxd3xqL1+yX+xjLfpey/Lgwdrb3B+3uEt+kTwl/+1639X4t0pK0cqvP6Yu OsC5vnP6acYl/RbvH0StzF++iE/USPPmbabGQoXky8v3bTARTGiJz2yxX/DKS2aBrXTw2qpo bsXgufNu9u7611vvNU2JpTgj0VCLuag4EQBY2qAJAAQAAA== X-CMS-MailID: 20240515055726eucas1p2a795fc743373571bfc3349f9e1ef3f9e X-Msg-Generator: CA X-RootMTR: 20240515055726eucas1p2a795fc743373571bfc3349f9e1ef3f9e X-EPHeader: CA CMS-TYPE: 201P X-CMS-RootMailID: 20240515055726eucas1p2a795fc743373571bfc3349f9e1ef3f9e References: <20240515055719.32577-1-da.gomez@samsung.com> X-Rspam-User: X-Stat-Signature: 4xn47pg7tb1ptxrgmidoucrb3k9u93n4 X-Rspamd-Server: rspam07 X-Rspamd-Queue-Id: E38C5140006 X-HE-Tag: 1715752648-867763 X-HE-Meta: U2FsdGVkX18FbcPn4DaqgMjTt1SvQBWRLYfnTnCBn0g6x+V6o+9JlQuo06Iy7PhpHg+4W46sU7uFLI0PhRrPdcK30lIwhR6iOpX5AEsjWmQs0kJI6l+3jjsO9cmGheaZspV/fTqtIGImHS1lNcbH5GPd/KHAjSeOwoZwMvi7Wuit8xwEUahYI3wctiCRmT57O1kT6/OmZId5HJ4miZ+x152th2P8Lwt3AgZBqRPNeRBwpENt2HAyh1VI0Go35kd0vPQ0p/pG8X4UDAkvCjozu3KJCIFmCzL/OG9z58HFEl7jNNOWvjPQ06safXLU7ioi4j89XcdGQl9nIRVbpy+tnP9hVf0J/d3a4u6B2W2pO0/mCvF82kCDHAh044ApgN1F19SSn2xqanUwRGUQf5iPGXMt5eo6VTBZqYbWCq0RirQjiliQA+rrKh45xe2PkP4zIup9iFJznd6mloavwu05Y8gB2c7q+msjBuH7f5h6Kddbtsw9JeD1W6l30pLw0JSyhqeFD3A4mQWzcRFBN0GiZAoI0yk6osdFE5hqrvXj9o6cyzznMa0nyzXbyNM1BpefN1KSZcxrUTpeH/KhzgxgumjWnbQmDQ/Ye4LIhnUvEzx6MVpkHvD/0i8e9/j7Fc5/t6Wv3Z+UHaPT1OJqNkxCL+2vAPFGC1SOdv9OaW3qmawqo98yFKZ6M/cNB166c6mZwfCeC7tEjUEMnzWm5/B4uDxdjUW1LZcJw9TFCtf1SRBz4Q9G/YIS/wbOjTKC7nukagjPQ6UC99kkflCkiSG6b449QPaK9vWvJUdrRguhCsMuQsXrrdHxF1Dg1asTF2R9WBkpygzBrKXE7dqk0hFTkKzaB9SgAoGpdFdnIjybN1nbadVVPPQBxI79Ua82/1mqq/uly9S5QYgE4fuv6HDi6KpxjcP9b2K8dP76Z/ga3sWtMHr7ciX2WJN/lwtccdvg1hh5wVC8kyLhzw57nBf c4pdN1kg qmIF5gf1uSdWEfeXSPY/+kOstgqmApuxg7pTwkx94/UpexNxPWI4wR86lK9YzjIGwcdW76UfWs3PsGJPimzGEfzWMjrpx4d+ZW0QIgyLQmBOSHijJ8NhFSj8rStyG0i7FkLCFZv3YNxATxvTa/AL3JkB5DbaqfJ9Res9rqsNNw+rJRRToYMk9aYWXv8KDwbIx2Ddsyr3AymsK2jhe8Eb5UlqeN5x91tFDnejK3GtNTFlnBOY= 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: Based on iomap per-block dirty and uptodate state track, add support for shmem_folio_state struct to track the uptodate state per-block for large folios. Signed-off-by: Daniel Gomez --- mm/shmem.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 189 insertions(+), 6 deletions(-) diff --git a/mm/shmem.c b/mm/shmem.c index 94ab99b6b574..4818f9fbd328 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -131,6 +131,124 @@ struct shmem_options { #define SHMEM_SEEN_QUOTA 32 }; =20 +/* + * Structure allocated for each folio to track per-block uptodate state. + * + * Like buffered-io iomap_folio_state struct but only for uptodate. + */ +struct shmem_folio_state { + spinlock_t state_lock; + unsigned long state[]; +}; + +static inline bool sfs_is_fully_uptodate(struct folio *folio) +{ + struct inode *inode =3D folio->mapping->host; + struct shmem_folio_state *sfs =3D folio->private; + + return bitmap_full(sfs->state, i_blocks_per_folio(inode, folio)); +} + +static inline bool sfs_is_block_uptodate(struct shmem_folio_state *sfs, + unsigned int block) +{ + return test_bit(block, sfs->state); +} + +/** + * sfs_get_last_block_uptodate - find the index of the last uptodate block + * within a specified range + * @folio: The folio + * @first: The starting block of the range to search + * @last: The ending block of the range to search + * + * Returns the index of the last uptodate block within the specified range= . If + * a non uptodate block is found at the start, it returns UINT_MAX. + */ +static unsigned int sfs_get_last_block_uptodate(struct folio *folio, + unsigned int first, + unsigned int last) +{ + struct inode *inode =3D folio->mapping->host; + struct shmem_folio_state *sfs =3D folio->private; + unsigned int nr_blocks =3D i_blocks_per_folio(inode, folio); + unsigned int aux =3D find_next_zero_bit(sfs->state, nr_blocks, first); + + /* + * Exceed the range of possible last block and return UINT_MAX if a non + * uptodate block is found at the beginning of the scan. + */ + if (aux =3D=3D first) + return UINT_MAX; + + return min_t(unsigned int, aux - 1, last); +} + +static void sfs_set_range_uptodate(struct folio *folio, + struct shmem_folio_state *sfs, size_t off, + size_t len) +{ + struct inode *inode =3D folio->mapping->host; + unsigned int first_blk =3D off >> inode->i_blkbits; + unsigned int last_blk =3D (off + len - 1) >> inode->i_blkbits; + unsigned int nr_blks =3D last_blk - first_blk + 1; + unsigned long flags; + + spin_lock_irqsave(&sfs->state_lock, flags); + bitmap_set(sfs->state, first_blk, nr_blks); + if (sfs_is_fully_uptodate(folio)) + folio_mark_uptodate(folio); + spin_unlock_irqrestore(&sfs->state_lock, flags); +} + +static struct shmem_folio_state *sfs_alloc(struct inode *inode, + struct folio *folio) +{ + struct shmem_folio_state *sfs =3D folio->private; + unsigned int nr_blocks =3D i_blocks_per_folio(inode, folio); + gfp_t gfp =3D GFP_KERNEL; + + if (sfs || nr_blocks <=3D 1) + return sfs; + + /* + * sfs->state tracks uptodate flag when the block size is smaller + * than the folio size. + */ + sfs =3D kzalloc(struct_size(sfs, state, BITS_TO_LONGS(nr_blocks)), gfp); + if (!sfs) + return sfs; + + spin_lock_init(&sfs->state_lock); + if (folio_test_uptodate(folio)) + bitmap_set(sfs->state, 0, nr_blocks); + folio_attach_private(folio, sfs); + + return sfs; +} + +static void sfs_free(struct folio *folio, bool force) +{ + if (!folio_test_private(folio)) + return; + + if (!force) + WARN_ON_ONCE(sfs_is_fully_uptodate(folio) !=3D + folio_test_uptodate(folio)); + + kfree(folio_detach_private(folio)); +} + +static void shmem_set_range_uptodate(struct folio *folio, size_t off, + size_t len) +{ + struct shmem_folio_state *sfs =3D folio->private; + + if (sfs) + sfs_set_range_uptodate(folio, sfs, off, len); + else + folio_mark_uptodate(folio); +} #ifdef CONFIG_TMPFS static unsigned long shmem_default_max_blocks(void) { @@ -1487,7 +1605,7 @@ static int shmem_writepage(struct page *page, struct = writeback_control *wbc) } folio_zero_range(folio, 0, folio_size(folio)); flush_dcache_folio(folio); - folio_mark_uptodate(folio); + shmem_set_range_uptodate(folio, 0, folio_size(folio)); } =20 swap =3D folio_alloc_swap(folio); @@ -1769,13 +1887,16 @@ static int shmem_replace_folio(struct folio **folio= p, gfp_t gfp, if (!new) return -ENOMEM; =20 + if (folio_get_private(old)) + folio_attach_private(new, folio_detach_private(old)); + folio_get(new); folio_copy(new, old); flush_dcache_folio(new); =20 __folio_set_locked(new); __folio_set_swapbacked(new); - folio_mark_uptodate(new); + shmem_set_range_uptodate(new, 0, folio_size(new)); new->swap =3D entry; folio_set_swapcache(new); =20 @@ -2063,6 +2184,12 @@ static int shmem_get_folio_gfp(struct inode *inode, = pgoff_t index, =20 alloced: alloced =3D true; + + if (!sfs_alloc(inode, folio) && folio_test_large(folio)) { + error =3D -ENOMEM; + goto unlock; + } + if (folio_test_pmd_mappable(folio) && DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE) < folio_next_index(folio) - 1) { @@ -2104,7 +2231,7 @@ static int shmem_get_folio_gfp(struct inode *inode, p= goff_t index, for (i =3D 0; i < n; i++) clear_highpage(folio_page(folio, i)); flush_dcache_folio(folio); - folio_mark_uptodate(folio); + shmem_set_range_uptodate(folio, 0, folio_size(folio)); } =20 /* Perhaps the file has been truncated since we checked */ @@ -2773,8 +2900,8 @@ shmem_write_end(struct file *file, struct address_spa= ce *mapping, folio_zero_segments(folio, 0, from, from + copied, folio_size(folio)); } - folio_mark_uptodate(folio); } + shmem_set_range_uptodate(folio, 0, folio_size(folio)); folio_mark_dirty(folio); folio_unlock(folio); folio_put(folio); @@ -2782,6 +2909,59 @@ shmem_write_end(struct file *file, struct address_sp= ace *mapping, return copied; } =20 +static void shmem_invalidate_folio(struct folio *folio, size_t offset, + size_t len) +{ + /* + * If we're invalidating the entire folio, clear the dirty state + * from it and release it to avoid unnecessary buildup of the LRU. + */ + if (offset =3D=3D 0 && len =3D=3D folio_size(folio)) { + WARN_ON_ONCE(folio_test_writeback(folio)); + folio_cancel_dirty(folio); + sfs_free(folio, true); + } +} + +static bool shmem_release_folio(struct folio *folio, gfp_t gfp_flags) +{ + if (folio_test_dirty(folio) && !sfs_is_fully_uptodate(folio)) + return false; + + sfs_free(folio, false); + return true; +} + +/* + * shmem_is_partially_uptodate checks whether blocks within a folio are + * uptodate or not. + * + * Returns true if all blocks which correspond to the specified part + * of the folio are uptodate. + */ +static bool shmem_is_partially_uptodate(struct folio *folio, size_t from, + size_t count) +{ + struct shmem_folio_state *sfs =3D folio->private; + struct inode *inode =3D folio->mapping->host; + unsigned int first, last; + + if (!sfs) + return false; + + /* Caller's range may extend past the end of this folio */ + count =3D min(folio_size(folio) - from, count); + + /* First and last blocks in range within folio */ + first =3D from >> inode->i_blkbits; + last =3D (from + count - 1) >> inode->i_blkbits; + + if (sfs_get_last_block_uptodate(folio, first, last) !=3D last) + return false; + + return true; +} + static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *t= o) { struct file *file =3D iocb->ki_filp; @@ -3533,7 +3713,7 @@ static int shmem_symlink(struct mnt_idmap *idmap, str= uct inode *dir, goto out_remove_offset; inode->i_op =3D &shmem_symlink_inode_operations; memcpy(folio_address(folio), symname, len); - folio_mark_uptodate(folio); + shmem_set_range_uptodate(folio, 0, folio_size(folio)); folio_mark_dirty(folio); folio_unlock(folio); folio_put(folio); @@ -4523,7 +4703,10 @@ static const struct address_space_operations shmem_a= ops =3D { #ifdef CONFIG_MIGRATION .migrate_folio =3D migrate_folio, #endif - .error_remove_folio =3D shmem_error_remove_folio, + .error_remove_folio =3D shmem_error_remove_folio, + .invalidate_folio =3D shmem_invalidate_folio, + .release_folio =3D shmem_release_folio, + .is_partially_uptodate =3D shmem_is_partially_uptodate, }; =20 static const struct file_operations shmem_file_operations =3D { --=20 2.43.0