From: Matthew Wilcox <willy@infradead.org>
To: Dave Chinner <david@fromorbit.com>
Cc: Matt Whitlock <kernel@mattwhitlock.name>,
linux-fsdevel@vger.kernel.org, Christoph Hellwig <hch@lst.de>,
David Howells <dhowells@redhat.com>, Jens Axboe <axboe@kernel.dk>,
Al Viro <viro@zeniv.linux.org.uk>
Subject: Re: [Reproducer] Corruption, possible race between splice and FALLOC_FL_PUNCH_HOLE
Date: Tue, 27 Jun 2023 11:31:56 +0100 [thread overview]
Message-ID: <ZJq6nJBoX1m6Po9+@casper.infradead.org> (raw)
In-Reply-To: <ZJp4Df8MnU8F3XAt@dread.disaster.area>
On Tue, Jun 27, 2023 at 03:47:57PM +1000, Dave Chinner wrote:
> On Mon, Jun 26, 2023 at 09:12:52PM -0400, Matt Whitlock wrote:
> > Hello, all. I am experiencing a data corruption issue on Linux 6.1.24 when
> > calling fallocate with FALLOC_FL_PUNCH_HOLE to punch out pages that have
> > just been spliced into a pipe. It appears that the fallocate call can zero
> > out the pages that are sitting in the pipe buffer, before those pages are
> > read from the pipe.
> >
> > Simplified code excerpt (eliding error checking):
> >
> > int fd = /* open file descriptor referring to some disk file */;
> > for (off_t consumed = 0;;) {
> > ssize_t n = splice(fd, NULL, STDOUT_FILENO, NULL, SIZE_MAX, 0);
> > if (n <= 0) break;
> > consumed += n;
> > fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, consumed);
> > }
>
> Huh. Never seen that pattern before - what are you trying to
> implement with this?
>
> > Expected behavior:
> > Punching holes in a file after splicing pages out of that file into a pipe
> > should not corrupt the spliced-out pages in the pipe buffer.
>
> splice is a nasty, tricky beast that should never have been
> inflicted on the world...
Indeed. I understand the problem, I just don't know if it's a bug.
> > Observed behavior:
> > Some of the pages that have been spliced into the pipe get zeroed out by the
> > subsequent fallocate call before they can be consumed from the read side of
> > the pipe.
>
> Which implies the splice is not copying the page cache pages but
> simply taking a reference to them.
Yup.
> Hmmm. the corruption, more often than not, starts on a high-order
> aligned file offset. Tracing indicates data is being populated in
> the page cache by readahead, which would be using high-order folios
> in XFS.
>
> All the splice operations are return byte counts that are 4kB
> aligned, so punch is doing filesystem block aligned punches. The
> extent freeing traces indicate the filesystem is removing exactly
> the right ranges from the file, and so the page cache invalidation
> calls it is doing are also going to be for the correct ranges.
>
> This smells of a partial high-order folio invalidation problem,
> or at least a problem with splice working on pages rather than
> folios the two not being properly coherent as a result of partial
> folio invalidation.
>
> To confirm, I removed all the mapping_set_large_folios() calls in
> XFS, and the data corruption goes away. Hence, at minimum, large
> folios look like a trigger for the problem.
If you do a PUNCH HOLE, documented behaviour is:
Specifying the FALLOC_FL_PUNCH_HOLE flag (available since Linux 2.6.38)
in mode deallocates space (i.e., creates a hole) in the byte range
starting at offset and continuing for len bytes. Within the specified
range, partial filesystem blocks are zeroed, and whole filesystem
blocks are removed from the file. After a successful call, subsequent
reads from this range will return zeros.
So we have, let's say, an order-4 folio and the user tries to PUNCH_HOLE
page 3 of it. We try to split it, but that fails because the pipe holds
a reference. The filesystem has removed the underlying data from the
storage medium. What is the page cache to do? It must memset() so that
subsequent reads return zeroes. And now the page in the pipe has the
hole punched into it.
I think you can reproduce this problem without large folios by using a
512-byte block size filesystem and punching holes that are sub page
size. The page cache must behave similarly.
Perhaps the problem is that splice() appears to copy, but really just
takes the reference. Perhaps splice needs to actually copy if it
sees a multi-page folio and isn't going to take all of it. I'm not
an expert in splice-ology, so let's cc some people who know more about
splice than I do.
next prev parent reply other threads:[~2023-06-27 10:32 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-27 1:12 [Reproducer] Corruption, possible race between splice and FALLOC_FL_PUNCH_HOLE Matt Whitlock
2023-06-27 5:47 ` Dave Chinner
2023-06-27 6:20 ` Dave Chinner
2023-06-27 10:31 ` Matthew Wilcox [this message]
2023-06-27 18:38 ` Matt Whitlock
2023-06-27 21:49 ` Dave Chinner
2023-06-27 18:14 ` Matt Whitlock
2023-06-27 21:51 ` Dave Chinner
2023-06-28 6:30 ` David Howells
2023-06-28 8:15 ` Dave Chinner
2023-06-28 9:33 ` David Howells
2023-06-28 12:51 ` Matthew Wilcox
2023-06-28 14:19 ` David Howells
2023-06-28 22:41 ` Dave Chinner
2023-06-28 17:35 ` Matt Whitlock
2023-06-28 18:27 ` David Howells
2023-06-28 22:17 ` Dave Chinner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZJq6nJBoX1m6Po9+@casper.infradead.org \
--to=willy@infradead.org \
--cc=axboe@kernel.dk \
--cc=david@fromorbit.com \
--cc=dhowells@redhat.com \
--cc=hch@lst.de \
--cc=kernel@mattwhitlock.name \
--cc=linux-fsdevel@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).