]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netfs, afs: Fix write skipping in dir/link writepages
authorDavid Howells <dhowells@redhat.com>
Tue, 12 May 2026 12:34:00 +0000 (13:34 +0100)
committerChristian Brauner <brauner@kernel.org>
Tue, 12 May 2026 12:42:32 +0000 (14:42 +0200)
Fix netfs_write_single() and afs_single_writepages() to better handle a
write that would be skipped due to lock contention and WB_SYNC_NONE by
returning 1 from netfs_write_single() if it skipped and making
afs_single_writepages() skip also.  If a skip occurs, the inode must be
re-marked as the VFS may have cleared the mark.

This is really only theoretical for directories in netfs_write_single() as
the only path to that is through afs_single_writepages() that takes the
->validate_lock around it, thereby serialising it.

Fixes: 6dd80936618c ("afs: Use netfslib for directories")
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260512123404.719402-24-dhowells@redhat.com
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/afs/dir.c
fs/netfs/write_issue.c

index aaaa55878ffd28691777668261f577d7a9472d6d..d1542a1a50bfad7d6b246737190784fdaccddc08 100644 (file)
@@ -2206,7 +2206,14 @@ int afs_single_writepages(struct address_space *mapping,
        /* Need to lock to prevent the folio queue and folios from being thrown
         * away.
         */
-       down_read(&dvnode->validate_lock);
+       if (!down_read_trylock(&dvnode->validate_lock)) {
+               if (wbc->sync_mode == WB_SYNC_NONE) {
+                       /* The VFS will have undirtied the inode. */
+                       netfs_single_mark_inode_dirty(&dvnode->netfs.inode);
+                       return 0;
+               }
+               down_read(&dvnode->validate_lock);
+       }
 
        if (is_dir ?
            test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) :
@@ -2214,6 +2221,8 @@ int afs_single_writepages(struct address_space *mapping,
                iov_iter_folio_queue(&iter, ITER_SOURCE, dvnode->directory, 0, 0,
                                     i_size_read(&dvnode->netfs.inode));
                ret = netfs_writeback_single(mapping, wbc, &iter);
+               if (ret == 1)
+                       ret = 0; /* Skipped write due to lock conflict. */
        }
 
        up_read(&dvnode->validate_lock);
index 03961622996be1d9a9bcad69f989337c2516b304..c03c7cc45e4716344cc7347aaa0d474a036b9faf 100644 (file)
@@ -830,6 +830,9 @@ static int netfs_write_folio_single(struct netfs_io_request *wreq,
  *
  * Write a monolithic, non-pagecache object back to the server and/or
  * the cache.
+ *
+ * Return: 0 if successful; 1 if skipped due to lock conflict and WB_SYNC_NONE;
+ * or a negative error code.
  */
 int netfs_writeback_single(struct address_space *mapping,
                           struct writeback_control *wbc,
@@ -846,8 +849,10 @@ int netfs_writeback_single(struct address_space *mapping,
 
        if (!mutex_trylock(&ictx->wb_lock)) {
                if (wbc->sync_mode == WB_SYNC_NONE) {
+                       /* The VFS will have undirtied the inode. */
+                       netfs_single_mark_inode_dirty(&ictx->inode);
                        netfs_stat(&netfs_n_wb_lock_skip);
-                       return 0;
+                       return 1;
                }
                netfs_stat(&netfs_n_wb_lock_wait);
                mutex_lock(&ictx->wb_lock);