From nobody Sat Jul 25 21:20:41 2026 Received: from mail-pl1-f180.google.com (mail-pl1-f180.google.com [209.85.214.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 57C2B3F4DD0 for ; Mon, 13 Jul 2026 11:57:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783943837; cv=none; b=FBJneV3ABHsyHKj3tmWwe5ESh05Ou34+ttmgI9bCBeiifhMr6cDTGQ89fFPWQ9sEaK3vkIWu7hHw990j2WpPdKZ/vG0/kI29IeO9OOhNMjuDw5I5Mt24OCWucoERXjJ9AD7JbI7XfdcK/W1hL/m7C+7mO4ifAvv6vQ1PIxP+c54= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783943837; c=relaxed/simple; bh=J74Gbz9uVDwyKXHy+deWVbqG7EY4vd+RF3prZqFNUcg=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=uVFK2ahZBSSIXNdRsq2tGu2nQ5ictPtYq8lO9M6hhGi+P09yvCEMe30Eq0cwgrHg0x0eKaBEaqeML1eiuHKPfsyCXbesX7nFzCNRu9gwelM3r00gXRz1K8iEj1IPU0LMkYTQGBtlyD44swtT43hDBXjwSEzlZxbF3tgaeYGcVI0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=thingy.jp; spf=pass smtp.mailfrom=0x0f.com; dkim=pass (1024-bit key) header.d=thingy.jp header.i=@thingy.jp header.b=llCfOm/k; arc=none smtp.client-ip=209.85.214.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=thingy.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=0x0f.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=thingy.jp header.i=@thingy.jp header.b="llCfOm/k" Received: by mail-pl1-f180.google.com with SMTP id d9443c01a7336-2ced3386430so5471805ad.1 for ; Mon, 13 Jul 2026 04:57:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=thingy.jp; s=google; t=1783943835; x=1784548635; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=Seb0uCVoBGNXdsIQSXFh8tqETWz4/TxV3J6OMvF+xsI=; b=llCfOm/k9zHrdrEm5iEO0/S5WGiz8DQhn2otsroIKyaSR7RKwscYF/z/OmsCJZ+sIc PppgRf1QmzGpI8/+TjbrOknESZ4CuIMp4dxF5ztJmiwcJzYtxaUVThu3Vz0yqG80MC9J 4S0lBaQYdldFjdVGVnsUMSud3IIStrt4MfQw4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783943835; x=1784548635; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Seb0uCVoBGNXdsIQSXFh8tqETWz4/TxV3J6OMvF+xsI=; b=c6EQOsxzuCuTT7sxEPVvH7Z6zNrTyWR/esv7a0FyU2xpmgJX4FutfshYkOpMyphMKT W3hA70sn66g3Bo3TSPhRMpbPVICvBXyyg6P4e2cmin7/HaiOvKXddtjIrigdSeAaHNRO +Ak24NtqfkdXTOfIysoUCeeAXDCzfs7TpDS6K5ZzKMymQy3uWzgndmTxOY7l8ucD8kQ8 5/fEMdIikhHi81uiDzOQIK4TcwfolOLs2FSUSpZhBQC/tAQ2+D8ZnOuyhHGYJcSHVxHL oDIkRPIcA1BPSeNsKTAf9M+LuHotTDkasUuhsoZkpi55kIpm+DaKmIiP91nN3E9fLZ2r b2jg== X-Gm-Message-State: AOJu0Yz1HqFHfWmRmmd9NqX7rRAmCCX7V8X0nfvlnaWX5ZofKVnuGT7b uIWOYWgjI6lirmnRJECJq1J/zTvdhpiV3eDMXZ47T3NG/vaWtYVDxY8qhnnjQvhZnaN4qfEXdxe D90fF X-Gm-Gg: AfdE7cnIHNPfJJQJDd/N8hKGR4l85pykzfS4/gUILTZz84Mme4DbDKEyWVUvXn9Ymqp J4IZIY1HEZT2tEurdgX0OQYQJGglMSWxctE1P//EkcV6uHpkqFZdbR9Xl+mFxTjz8ASQguFP/6c pW6kLLobs766KfD32TbYnYJEo3zqrHxd7QD3qOvBZqqd3L3AXVx/4UCgo0PKlaTPZKMIXDvTKJj 0qDNKLlYFE7YtASnsEHMB91KQ8hJQibHNx4dj83u7DffBvih4/Xu2zaqBeKa10kmgoUgWhRDMA+ VI91Meha8D1KGY+fzZBntcH7+1QVYqztcJ+TwNqOg1i4T6URVcLlEy+gChXyworAnrnYZQ0LYGV lzA9HSqBan2AEZIsWXoHOgmc88t5VCYiW36IJVez7SXMccdY4PJAwJCUTPsmFsAmLXtdBAAa9LS +KVDWyzRUumFlnGtnJT3qmeb+Pww== X-Received: by 2002:a17:902:c405:b0:2c9:c46b:1286 with SMTP id d9443c01a7336-2ce9ef17a85mr96026795ad.34.1783943835529; Mon, 13 Jul 2026 04:57:15 -0700 (PDT) Received: from kinako.work.home.arpa ([2400:4162:2428:2ffe:a973:53e4:1a28:8545]) by smtp.googlemail.com with ESMTPSA id d9443c01a7336-2ccc9c21429sm99111925ad.37.2026.07.13.04.57.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jul 2026 04:57:15 -0700 (PDT) From: Daniel Palmer To: ljs@kernel.org, akpm@linux-foundation.org, dhowells@redhat.com Cc: linux-kernel@vger.kernel.org, thehajime@gmail.com, Daniel Palmer , Sashiko Subject: [PATCH] ramfs: nommu: fix error rollback and reader races in ramfs_nommu_expand_for_mapping() Date: Mon, 13 Jul 2026 20:57:00 +0900 Message-ID: <20260713115700.1349111-1-daniel@thingy.jp> X-Mailer: git-send-email 2.53.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ramfs_nommu_expand_for_mapping() sets the new i_size before it has allocated or inserted any of the contiguous backing pages. If alloc_pages() or add_to_page_cache_lru() fails, the inode is left with an inflated i_size and possibly a partial run of pages. As ramfs_nommu_setattr() treats a truncate to the current i_size as a no-op, the expansion cannot be retried and shared mmap() of the file fails with -ENOSYS. Setting i_size early also races with lockless readers: buffered reads and splice do not take i_rwsem, so once the new size is visible a concurrent read can instantiate a zero-filled folio, making the expansion's add_to_page_cache_lru() fail with -EEXIST. Fix this by taking mapping->invalidate_lock around the insertion, evicting any stray folios first, and only publishing i_size once every page is in place. On failure, after freeing the pages that were allocated but not inserted truncate the mapping back to empty so already inserted pages are also disposed of. Fixes: 642fb4d1f1dd ("[PATCH] NOMMU: Provide shared-writable mmap support o= n ramfs") Reported-by: Sashiko Closes: https://sashiko.dev/#/message/20260523130445.1101818-1-daniel%40thi= ngy.jp Assisted-by: Claude:claude-5-fable # expanded my fix to address the reader = race etc. Signed-off-by: Daniel Palmer --- sashiko found these issues on a previous patch to fix creating memfd's. I quickly fixed up the i_size part and then fed it to fable for review before sending and it said the reader thing needed to be fixed too and expanded the commit message to reflect that. I am not sure about the locking part at all so hopefully someone can chime in on that. Maybe sashiko will say the things it reported and fable fixed aren't a problem after all.. :). I tested the happy path on my mc68000 virt machine and manually stepped through the code to make sure its actually being executed and tested on real hardware. fs/ramfs/file-nommu.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index fb471bf88ab7..6819f4790065 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -80,8 +80,6 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, s= ize_t newsize) if (ret) return ret; =20 - i_size_write(inode, newsize); - /* allocate enough contiguous pages to be able to satisfy the * request */ pages =3D alloc_pages(gfp, order); @@ -99,9 +97,15 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, = size_t newsize) __free_page(pages + loop); =20 /* clear the memory we allocated */ - newsize =3D PAGE_SIZE * npages; data =3D page_address(pages); - memset(data, 0, newsize); + memset(data, 0, PAGE_SIZE * npages); + + /* block the read and splice paths from instantiating pagecache + * folios whilst we build the contiguous mapping, and evict any + * folio they may already have instantiated (the read path only + * checks i_size after folio lookup/creation) */ + filemap_invalidate_lock(inode->i_mapping); + truncate_inode_pages(inode->i_mapping, 0); =20 /* attach all the pages to the inode's address space */ for (loop =3D 0; loop < npages; loop++) { @@ -120,11 +124,20 @@ int ramfs_nommu_expand_for_mapping(struct inode *inod= e, size_t newsize) put_page(page); } =20 + /* only publish the new size once all of the backing pages are in + * place, so that readers never observe a size without the pages to + * back it and a failure leaves the inode unchanged at size 0 */ + i_size_write(inode, newsize); + filemap_invalidate_unlock(inode->i_mapping); return 0; =20 add_error: + /* free the pages we hadn't inserted yet... */ while (loop < npages) __free_page(pages + loop++); + /* ...and evict the ones we had; they belong to the page cache now */ + truncate_inode_pages(inode->i_mapping, 0); + filemap_invalidate_unlock(inode->i_mapping); return ret; } =20 --=20 2.53.0