Skip to content
This repository was archived by the owner on Oct 31, 2024. It is now read-only.

Commit 2c1eabb

Browse files
dhowellsgregkh
authored andcommitted
netfs: Fix missing wakeup after issuing writes
[ Upstream commit 1ca4169 ] After dividing up a proposed write into subrequests, netfslib sets NETFS_RREQ_ALL_QUEUED to indicate to the collector that it can move on to the final cleanup once it has emptied the subrequest queues. Now, whilst the collector will normally end up running at least once after this bit is set just because it takes a while to process all the write subrequests before the collector runs out of subrequests, there exists the possibility that the issuing thread will be forced to sleep and the collector thread will clean up all the subrequests before ALL_QUEUED gets set. In such a case, the collector thread will not get triggered again and will never clear NETFS_RREQ_IN_PROGRESS thus leaving a request uncompleted and causing a potential futute hang. Fix this by scheduling the write collector if all the subrequest queues are empty (and thus no writes pending issuance). Note that we'd do this ideally before queuing the subrequest, but in the case of buffered writeback, at least, we can't find out that we've run out of folios until after we've called writeback_iter() and it has returned NULL - at which point we might not actually have any subrequests still under construction. Fixes: 288ace2 ("netfs: New writeback implementation") Signed-off-by: David Howells <dhowells@redhat.com> Link: https://lore.kernel.org/r/3317784.1727880350@warthog.procyon.org.uk cc: Jeff Layton <jlayton@kernel.org> cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 0455ffc commit 2c1eabb

File tree

1 file changed

+27
-15
lines changed

1 file changed

+27
-15
lines changed

fs/netfs/write_issue.c

+27-15
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,30 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
494494
return 0;
495495
}
496496

497+
/*
498+
* End the issuing of writes, letting the collector know we're done.
499+
*/
500+
static void netfs_end_issue_write(struct netfs_io_request *wreq)
501+
{
502+
bool needs_poke = true;
503+
504+
smp_wmb(); /* Write subreq lists before ALL_QUEUED. */
505+
set_bit(NETFS_RREQ_ALL_QUEUED, &wreq->flags);
506+
507+
for (int s = 0; s < NR_IO_STREAMS; s++) {
508+
struct netfs_io_stream *stream = &wreq->io_streams[s];
509+
510+
if (!stream->active)
511+
continue;
512+
if (!list_empty(&stream->subrequests))
513+
needs_poke = false;
514+
netfs_issue_write(wreq, stream);
515+
}
516+
517+
if (needs_poke)
518+
netfs_wake_write_collector(wreq, false);
519+
}
520+
497521
/*
498522
* Write some of the pending data back to the server
499523
*/
@@ -541,10 +565,7 @@ int netfs_writepages(struct address_space *mapping,
541565
break;
542566
} while ((folio = writeback_iter(mapping, wbc, folio, &error)));
543567

544-
for (int s = 0; s < NR_IO_STREAMS; s++)
545-
netfs_issue_write(wreq, &wreq->io_streams[s]);
546-
smp_wmb(); /* Write lists before ALL_QUEUED. */
547-
set_bit(NETFS_RREQ_ALL_QUEUED, &wreq->flags);
568+
netfs_end_issue_write(wreq);
548569

549570
mutex_unlock(&ictx->wb_lock);
550571

@@ -632,10 +653,7 @@ int netfs_end_writethrough(struct netfs_io_request *wreq, struct writeback_contr
632653
if (writethrough_cache)
633654
netfs_write_folio(wreq, wbc, writethrough_cache);
634655

635-
netfs_issue_write(wreq, &wreq->io_streams[0]);
636-
netfs_issue_write(wreq, &wreq->io_streams[1]);
637-
smp_wmb(); /* Write lists before ALL_QUEUED. */
638-
set_bit(NETFS_RREQ_ALL_QUEUED, &wreq->flags);
656+
netfs_end_issue_write(wreq);
639657

640658
mutex_unlock(&ictx->wb_lock);
641659

@@ -680,13 +698,7 @@ int netfs_unbuffered_write(struct netfs_io_request *wreq, bool may_wait, size_t
680698
break;
681699
}
682700

683-
netfs_issue_write(wreq, upload);
684-
685-
smp_wmb(); /* Write lists before ALL_QUEUED. */
686-
set_bit(NETFS_RREQ_ALL_QUEUED, &wreq->flags);
687-
if (list_empty(&upload->subrequests))
688-
netfs_wake_write_collector(wreq, false);
689-
701+
netfs_end_issue_write(wreq);
690702
_leave(" = %d", error);
691703
return error;
692704
}

0 commit comments

Comments
 (0)