Skip to content

Commit 9b038d0

Browse files
dhowellsbrauner
authored andcommitted
netfs: Fix io_uring based write-through
This can be triggered by mounting a cifs filesystem with a cache=strict mount option and then, using the fsx program from xfstests, doing: ltp/fsx -A -d -N 1000 -S 11463 -P /tmp /cifs-mount/foo \ --replay-ops=gen112-fsxops Where gen112-fsxops holds: fallocate 0x6be7 0x8fc5 0x377d3 copy_range 0x9c71 0x77e8 0x2edaf 0x377d3 write 0x2776d 0x8f65 0x377d3 The problem is that netfs_io_request::len is being used for two purposes and ends up getting set to the amount of data we transferred, not the amount of data the caller asked to be transferred (for various reasons, such as mmap'd writes, we might end up rounding out the data written to the server to include the entire folio at each end). Fix this by keeping the amount we were asked to write in ->len and using ->submitted to track what we issued ops for. Then, when we come to calling ->ki_complete(), ->len is the right size. This also required netfs_cleanup_dio_write() to change since we're no longer advancing wreq->len. Use wreq->transferred instead as we might have done a short read. With this, the generic/112 xfstest passes if cifs is forced to put all non-DIO opens into write-through mode. Fixes: 288ace2 ("netfs: New writeback implementation") Signed-off-by: David Howells <[email protected]> Link: https://lore.kernel.org/r/[email protected] cc: Jeff Layton <[email protected]> cc: Steve French <[email protected]> cc: Enzo Matsumiya <[email protected]> cc: [email protected] cc: [email protected] cc: [email protected] cc: [email protected] cc: [email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 8f6a15f commit 9b038d0

File tree

3 files changed

+6
-5
lines changed

3 files changed

+6
-5
lines changed

fs/netfs/direct_write.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
static void netfs_cleanup_dio_write(struct netfs_io_request *wreq)
1313
{
1414
struct inode *inode = wreq->inode;
15-
unsigned long long end = wreq->start + wreq->len;
15+
unsigned long long end = wreq->start + wreq->transferred;
1616

1717
if (!wreq->error &&
1818
i_size_read(inode) < end) {

fs/netfs/write_collect.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ static void netfs_collect_write_results(struct netfs_io_request *wreq)
510510
* stream has a gap that can be jumped.
511511
*/
512512
if (notes & SOME_EMPTY) {
513-
unsigned long long jump_to = wreq->start + wreq->len;
513+
unsigned long long jump_to = wreq->start + READ_ONCE(wreq->submitted);
514514

515515
for (s = 0; s < NR_IO_STREAMS; s++) {
516516
stream = &wreq->io_streams[s];
@@ -690,10 +690,11 @@ void netfs_write_collection_worker(struct work_struct *work)
690690
wake_up_bit(&wreq->flags, NETFS_RREQ_IN_PROGRESS);
691691

692692
if (wreq->iocb) {
693-
wreq->iocb->ki_pos += wreq->transferred;
693+
size_t written = min(wreq->transferred, wreq->len);
694+
wreq->iocb->ki_pos += written;
694695
if (wreq->iocb->ki_complete)
695696
wreq->iocb->ki_complete(
696-
wreq->iocb, wreq->error ? wreq->error : wreq->transferred);
697+
wreq->iocb, wreq->error ? wreq->error : written);
697698
wreq->iocb = VFS_PTR_POISON;
698699
}
699700

fs/netfs/write_issue.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ static void netfs_issue_write(struct netfs_io_request *wreq,
254254
stream->construct = NULL;
255255

256256
if (subreq->start + subreq->len > wreq->start + wreq->submitted)
257-
wreq->len = wreq->submitted = subreq->start + subreq->len - wreq->start;
257+
WRITE_ONCE(wreq->submitted, subreq->start + subreq->len - wreq->start);
258258
netfs_do_issue_write(stream, subreq);
259259
}
260260

0 commit comments

Comments
 (0)