]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
netfs: Fix DIO write retry for filesystems without a ->prepare_write()
authorDavid Howells <dhowells@redhat.com>
Thu, 25 Jun 2026 14:06:33 +0000 (15:06 +0100)
committerChristian Brauner <brauner@kernel.org>
Wed, 1 Jul 2026 13:26:30 +0000 (15:26 +0200)
Fix netfs_unbuffered_write() so that it doesn't re-issue a write twice when
the filesystem doesn't have a ->prepare_write().  The resetting of the
iterator and the call to netfs_reissue_write() should just be removed as
almost everything it does is done again when the loop it's in goes back to
the top.

It does, however, still need the IN_PROGRESS flag setting, so that (and the
stat inc) are moved out of the if-statement.

Further, the MADE_PROGRESS flags should be cleared and wreq->transferred
should be updated, so fix those too.

Reported-by: syzbot+3c74b1f0c372e98efc32@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=3c74b1f0c372e98efc32
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260625140640.3116900-16-dhowells@redhat.com
cc: Paulo Alcantara <pc@manguebit.org>
cc: hongao <hongao@uniontech.com>
cc: ChenXiaoSong <chenxiaosong@chenxiaosong.com>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
fs/netfs/direct_write.c

index 25f8ceb15fad64650c119c4097cca3ef9648dea5..c16fbad286a17796d12962d2bb9fdf4fddfe5f88 100644 (file)
@@ -166,13 +166,16 @@ static int netfs_unbuffered_write(struct netfs_io_request *wreq)
                 */
                subreq->error = -EAGAIN;
                trace_netfs_sreq(subreq, netfs_sreq_trace_retry);
-               if (subreq->transferred > 0)
+               if (subreq->transferred > 0) {
                        iov_iter_advance(&wreq->buffer.iter, subreq->transferred);
+                       wreq->transferred += subreq->transferred;
+               }
 
                if (stream->source == NETFS_UPLOAD_TO_SERVER &&
                    wreq->netfs_ops->retry_request)
                        wreq->netfs_ops->retry_request(wreq, stream);
 
+               __clear_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags);
                __clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags);
                __clear_bit(NETFS_SREQ_BOUNDARY, &subreq->flags);
                __clear_bit(NETFS_SREQ_FAILED, &subreq->flags);
@@ -186,17 +189,10 @@ static int netfs_unbuffered_write(struct netfs_io_request *wreq)
 
                netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit);
 
-               if (stream->prepare_write) {
+               if (stream->prepare_write)
                        stream->prepare_write(subreq);
-                       __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags);
-                       netfs_stat(&netfs_n_wh_retry_write_subreq);
-               } else {
-                       struct iov_iter source;
-
-                       netfs_reset_iter(subreq);
-                       source = subreq->io_iter;
-                       netfs_reissue_write(stream, subreq, &source);
-               }
+               __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags);
+               netfs_stat(&netfs_n_wh_retry_write_subreq);
        }
 
        netfs_unbuffered_write_done(wreq);