]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
netfs: Fix read-gaps to remove netfs_folio from filled folio
authorDavid Howells <dhowells@redhat.com>
Tue, 12 May 2026 12:33:52 +0000 (13:33 +0100)
committerChristian Brauner <brauner@kernel.org>
Tue, 12 May 2026 12:42:31 +0000 (14:42 +0200)
Fix netfs_read_gaps() to remove the netfs_folio record from the folio
record before marking the folio uptodate if it successfully fills the gaps
around the dirty data in a streaming write folio (dirty, but not uptodate).

Found with:

    fsx -q -N 1000000 -p 10000 -o 128000 -l 600000 \
        /xfstest.test/junk --replay-ops=junk.fsxops

using the following as junk.fsxops:

    truncate 0x0 0x138b1 0x8b15d *
    write 0x507ee 0x10df7 0x927c0
    write 0x19993 0x10e04 0x927c0 *
    mapwrite 0x66214 0x1a253 0x927c0
    copy_range 0xb704 0x89b9 0x24429 0x79380
    write 0x2402b 0x144a2 0x90660 *
    mapwrite 0x204d5 0x140a0 0x927c0 *
    copy_range 0x1f72c 0x137d0 0x7a906 0x927c0 *
    read 0 0x9157c 0x9157c

on cifs with the default cache option.

It shows folio 0x24 misbehaving if the FMODE_READ check is commented out in
netfs_perform_write():

                if (//(file->f_mode & FMODE_READ) ||
                    netfs_is_cache_enabled(ctx)) {

and no fscache.  This was initially found with the generic/522 xfstest.

Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260512123404.719402-16-dhowells@redhat.com
Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading")
cc: Paulo Alcantara <pc@manguebit.org>
cc: Matthew Wilcox <willy@infradead.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/netfs/buffered_read.c

index ebd84a6cc3f09c2bf193b4122c592b4fea978733..51f844bfbdff6c02f1c7b37355752c32014cd2c8 100644 (file)
@@ -395,6 +395,7 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
 {
        struct netfs_io_request *rreq;
        struct address_space *mapping = folio->mapping;
+       struct netfs_group *group = netfs_folio_group(folio);
        struct netfs_folio *finfo = netfs_folio_info(folio);
        struct netfs_inode *ctx = netfs_inode(mapping->host);
        struct folio *sink = NULL;
@@ -461,6 +462,12 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
 
        ret = netfs_wait_for_read(rreq);
        if (ret >= 0) {
+               if (group)
+                       folio_change_private(folio, group);
+               else
+                       folio_detach_private(folio);
+               kfree(finfo);
+               trace_netfs_folio(folio, netfs_folio_trace_filled_gaps);
                flush_dcache_folio(folio);
                folio_mark_uptodate(folio);
        }
@@ -496,10 +503,8 @@ int netfs_read_folio(struct file *file, struct folio *folio)
        struct netfs_inode *ctx = netfs_inode(mapping->host);
        int ret;
 
-       if (folio_test_dirty(folio)) {
-               trace_netfs_folio(folio, netfs_folio_trace_read_gaps);
+       if (folio_test_dirty(folio))
                return netfs_read_gaps(file, folio);
-       }
 
        _enter("%lx", folio->index);