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 37812C77B7C for ; Wed, 25 Jun 2025 18:46:00 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id CBE146B00AD; Wed, 25 Jun 2025 14:45:59 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id C6F4B6B00AF; Wed, 25 Jun 2025 14:45:59 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id B5CEA6B00B0; Wed, 25 Jun 2025 14:45:59 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id A2A836B00AD for ; Wed, 25 Jun 2025 14:45:59 -0400 (EDT) Received: from smtpin04.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id 09D931A06F6 for ; Wed, 25 Jun 2025 18:45:59 +0000 (UTC) X-FDA: 83594802438.04.174B897 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by imf05.hostedemail.com (Postfix) with ESMTP id 2A114100012 for ; Wed, 25 Jun 2025 18:45:56 +0000 (UTC) Authentication-Results: imf05.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=GB7kfnpB; dmarc=pass (policy=quarantine) header.from=redhat.com; spf=pass (imf05.hostedemail.com: domain of bfoster@redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=bfoster@redhat.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1750877157; a=rsa-sha256; cv=none; b=c1g+4S+i99Ed6Crw0t31D+GkJrqqGtKsGWmSMS9Wfw9X0UoD3K/SABVAC9aqtppV/QkPSD 9EbpzmoYXORsLBXpkVzl9jD3/k0EtSyJtniyF3o8MfGhxjHZPnJJ2+vc7Gvd0jv2h73JJC koUUYgv/CS30tQXNXSClEnlzSucEpHg= ARC-Authentication-Results: i=1; imf05.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=GB7kfnpB; dmarc=pass (policy=quarantine) header.from=redhat.com; spf=pass (imf05.hostedemail.com: domain of bfoster@redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=bfoster@redhat.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1750877157; 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: references:dkim-signature; bh=KvNuFAr/cekQC2tItlFtBXGb9eHojIU+HaWvni46BGU=; b=YTXSSU9RdeObd95oPYz7slJhVxkgQEx4rcU8fQygUgRt5sc/SSeiAtsNoPOOM6tSXXfVJj 4ohW5/J6IEsfcS/PayAPDMwn3y0ZnzStkn4BU4bz9bv9z6Dd0vLpc6WiSw0gLjCpNnEqPA 36GIr/YvkbtjDSTH+5ZE3WRW3pYUTIM= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750877156; h=from:from: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; bh=KvNuFAr/cekQC2tItlFtBXGb9eHojIU+HaWvni46BGU=; b=GB7kfnpBt3OQh0akB/gH6XGRuBrw70dzOvPPHIV/8CWS5QYzhFg+/HUDhzWMNG6OVVOj99 JTpGDjPQXfBrrbFNjwBMvLqJHFK2GIEgIRhWobsq0KvU7jrDQ6Av2Gt3YTA+TxKiOtkxSX 5Hcweoq+UKvZ7HnjT00OX9cWUf9Ha6s= Received: from mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-510-aCvpWRV7NKud88y6f4nwrQ-1; Wed, 25 Jun 2025 14:45:53 -0400 X-MC-Unique: aCvpWRV7NKud88y6f4nwrQ-1 X-Mimecast-MFC-AGG-ID: aCvpWRV7NKud88y6f4nwrQ_1750877152 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0273F19560AA; Wed, 25 Jun 2025 18:45:52 +0000 (UTC) Received: from bfoster.redhat.com (unknown [10.22.64.142]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2702F30001A1; Wed, 25 Jun 2025 18:45:50 +0000 (UTC) From: Brian Foster To: linux-mm@kvack.org Cc: Hugh Dickins , Baolin Wang Subject: [PATCH] tmpfs: zero post-eof folio range on file extension Date: Wed, 25 Jun 2025 14:49:30 -0400 Message-ID: <20250625184930.269727-1-bfoster@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: OIqeoezy0LtZQyuSdpUfMFh1y7hUrl3_hDMl1ywFjiA_1750877152 X-Mimecast-Originator: redhat.com Content-Type: text/plain Content-Transfer-Encoding: 8bit X-Rspam-User: X-Rspamd-Queue-Id: 2A114100012 X-Rspamd-Server: rspam10 X-Stat-Signature: gxfpzonk6opx3wd7tr5oxurwpykyturf X-HE-Tag: 1750877156-301085 X-HE-Meta: U2FsdGVkX19cjVbZbAgd4U7JuABsMUvFWBKVzyDziIFTDBcACaWsQuOR/WBiR4Ps01wXMns3SuBuILUFIRcpCW41NvAYhuaF4HwbMJEWWxLdy92bhenRwnApgknCJD+8Wt437F1FbZDGL3AcXJPl8lhxXxFZstUUr58+GOansJkBi3MGJkwO15x6jI+uaL9LtYhLtwlGM05Jh8ZCwBxEh+IkrCFscPQNCpSkyQtjvElfSHlPKOxNIbfJK4SDPHkP/Bky8uEiE9/zR+9noVWvlv6g51rwBCXl6XyHTeS/kJoGcJHNJYEqLvtK6YXCt/118TbNBI0We8iAp6ko/yZWtX7gf3V3ozWm3powWkvjMcNrMqL6xS2vgunoQPRuX27nqBshlPFbDQBu6OGOfiEBw8PqKF8zOCUYCv/X1LkE2it/U2MRFQhrzLEcqmiJqaZrp8qvec76IMv+8kBqVMwP+r1YZxe7F2gkscbzSiX0rYLUYGKdgzl764Zwzls2GFGr75+eJ+oqRqotLLbZ4O0dLTYKQWRyF0nMqzquz+MDFay6cfQ8qr3PfTDz2HvClcxUGZ4HXxS7RWqTjYvFKswCnVG2q4TnHaPqTcNiu3fhvV9Gvlk7nvUt902Gq096OEevg6Ogpfa+sZ57PBJ4yPYV9GNCIJi8bPLq9Qe66NkEvWdF6MaqeDWhGP/aMyy09VyQnSJf36oCoTnt4V4f6oDcNfzgKhQn4py3UXin0kXB0dsYCFj2lOeZacQbaPGAc14NxBsRh+vfHqwGXdUrRniaprUStgRzzzXnvPFcHU4ba4g0DcmAx9PN7trWYJGGSx+4bqI97IB8sH2hUX2mJ09B+j+crWjSGlRVmQHPjJpcVQwnU7+bRhbUR/ZV20AcH+oeOs+rPmeM+SvQzCucPayRM4U9e9mKZ/toT0nokmz+agBKN1C6C767fgAL2vj4jD7VW8TKEBap3r2P1ioeVlg J5HLQkQg n261lSR/2/0vrAOF6+x+Nn/iqZqEq9kNQwRs4RmGnxOlBfSSnFIcGmC89XrfORgNB7ALlBo7Veg2e+gy4d8PnQ4xpogV1L7mTkQHIisgmz8g62ofROoScpbOTfP2UZVoctR0TnxSqIUxOod4UFotIJrNYykixYNyrO7BdAiWLVCTd4DAzySbgEr5UKn9MuW4x5/2v7zdJnwjMBdl17YQ91U7nMB0MGPNCuLRyl9rS4tl2YV+6wMiNsmIokVGIa0cj3KM5XsCHOeLgFqATNXDN1ZaIYf07nXO9yXyj4sx/G3+qdooAPHw8HrIHvjB6csXwKa44vkYTCbhwpxgvlafJgPMszCtvp6f2o6yd3ZzAId6vOLbCt2D5NacQ/w== 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: Most traditional filesystems zero the post-eof portion of the eof folio at writeback time, or when the file size is extended by truncate or extending writes. This ensures that the previously post-eof range of the folio is zeroed before it is exposed to the file. tmpfs doesn't implement the writeback path the way a traditional filesystem does, so zeroing behavior won't be exactly the same. However, it can still perform explicit zeroing from the various operations that extend a file and expose a post-eof portion of the eof folio. The current lack of zeroing is observed via failure of fstests test generic/363 on tmpfs. This test injects post-eof mapped writes in certain situations to detect gaps in zeroing behavior. Add a new eof zeroing helper for file extending operations. Look up the current eof folio, and if one exists, zero the range about to be exposed. This allows generic/363 to pass on tmpfs. Signed-off-by: Brian Foster --- Hi all, This survives the aforemented reproducer, an fstests regression run, and ~100m fsx operations without issues. Let me know if there are any other recommended tests for tmpfs and I'm happy to run them. Otherwise, a couple notes as I'm not terribly familiar with tmpfs... First, I used _get_partial_folio() because we really only want to zero an eof folio if one has been previously allocated. My understanding is that lookup path will avoid unnecessary folio allocation in such cases, but let me know if that's wrong. Also, it seems that the falloc path leaves newly preallocated folios !uptodate until they are used. This had me wondering if perhaps shmem_zero_eof() could just skip out if the eof folio happens to be !uptodate. Hm? Thoughts, reviews, flames appreciated. Brian mm/shmem.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/mm/shmem.c b/mm/shmem.c index 3a5a65b1f41a..4bb96c24fb9e 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1077,6 +1077,29 @@ static struct folio *shmem_get_partial_folio(struct inode *inode, pgoff_t index) return folio; } +/* + * Zero any post-EOF range of the EOF folio about to be exposed by size + * extension. + */ +static void shmem_zero_eof(struct inode *inode, loff_t pos) +{ + struct folio *folio; + loff_t i_size = i_size_read(inode); + size_t from, len; + + folio = shmem_get_partial_folio(inode, i_size >> PAGE_SHIFT); + if (!folio) + return; + + /* zero to the end of the folio or start of extending operation */ + from = offset_in_folio(folio, i_size); + len = min_t(loff_t, folio_size(folio) - from, pos - i_size); + folio_zero_range(folio, from, len); + + folio_unlock(folio); + folio_put(folio); +} + /* * Remove range of pages and swap entries from page cache, and free them. * If !unfalloc, truncate or punch hole; if unfalloc, undo failed fallocate. @@ -1302,6 +1325,8 @@ static int shmem_setattr(struct mnt_idmap *idmap, return -EPERM; if (newsize != oldsize) { + if (newsize > oldsize) + shmem_zero_eof(inode, newsize); error = shmem_reacct_size(SHMEM_I(inode)->flags, oldsize, newsize); if (error) @@ -3464,6 +3489,8 @@ static ssize_t shmem_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ret = file_update_time(file); if (ret) goto unlock; + if (iocb->ki_pos > i_size_read(inode)) + shmem_zero_eof(inode, iocb->ki_pos); ret = generic_perform_write(iocb, from); unlock: inode_unlock(inode); @@ -3791,8 +3818,15 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, cond_resched(); } - if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size) + /* + * The post-eof portion of the eof folio isn't guaranteed to be zeroed + * by fallocate, so zero through the end of the fallocated range + * instead of the start. + */ + if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size) { + shmem_zero_eof(inode, offset + len); i_size_write(inode, offset + len); + } undone: spin_lock(&inode->i_lock); inode->i_private = NULL; -- 2.49.0