Re: [PATCH v1] fuse: don't clear folio uptodate on writethrough errors
"Darrick J. Wong" <[email protected]> Thu, 25 Jun 2026 11:55:30 -0700
| Newsgroups | dev.linux.lists.fuse-devel,org.kernel.vger.linux-fsdevel |
|---|---|
| Message-ID | <20260625185530.GS6070@frogsfrogsfrogs> |
On Wed, Jun 24, 2026 at 01:52:01PM -0700, Joanne Koong wrote: > In the writethrough path (fuse_send_write_pages()), if the write to the > server failed or was a short write, the uptodate flag on the folios are > cleared. > > As explained by Matthew in [1], this is dangerous because the folio may > be mapped into userspace. The mm code has the invariant that a > non-uptodate folio must never be visible to userspace (to avoid > potentially leaking confidental information to userspace) and has checks > in place for this that if violated can bring down the whole machine. > > Practically speaking, the effect of this change for the fuse > writethrough error path is that if an application does a write and then > the server fails to persist the data or only services a short write, the > page cache folio keeps the data the application wrote instead of being > reverted to the server's contents on the next read. The failure is still > reported to the application synchronously through the short count / > error return of the write() syscall. Folios that were only partially > written are unaffected since they were never marked uptodate in the > first place (fuse_fill_write_page() only marks a folio as uptodate if > the whole folio was written to). > > [1] https://lore.kernel.org/linux-fsdevel/[email protected]/ > > Suggested-by: Matthew Wilcox <[email protected]> > Signed-off-by: Joanne Koong <[email protected]> Heh. I suppose it's good that we no longer throw away dirty folios because it's a bit rude if read() suddenly reverts. Let's hope there's not some weird third-level side effect that blows this up. Reviewed-by: "Darrick J. Wong" <[email protected]> --D > --- > fs/fuse/file.c | 18 +----------------- > 1 file changed, 1 insertion(+), 17 deletions(-) > > diff --git a/fs/fuse/file.c b/fs/fuse/file.c > index cb8da4c06d17..c4ae4009a423 100644 > --- a/fs/fuse/file.c > +++ b/fs/fuse/file.c > @@ -1227,8 +1227,7 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia, > struct file *file = iocb->ki_filp; > struct fuse_file *ff = file->private_data; > struct fuse_mount *fm = ff->fm; > - unsigned int offset, i; > - bool short_write; > + unsigned int i; > int err; > > for (i = 0; i < ap->num_folios; i++) > @@ -1243,24 +1242,9 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia, > if (!err && ia->write.out.size > count) > err = -EIO; > > - short_write = ia->write.out.size < count; > - offset = ap->descs[0].offset; > - count = ia->write.out.size; > for (i = 0; i < ap->num_folios; i++) { > struct folio *folio = ap->folios[i]; > > - if (err) { > - folio_clear_uptodate(folio); > - } else { > - if (count >= folio_size(folio) - offset) > - count -= folio_size(folio) - offset; > - else { > - if (short_write) > - folio_clear_uptodate(folio); > - count = 0; > - } > - offset = 0; > - } > if (ia->write.folio_locked && (i == ap->num_folios - 1)) > folio_unlock(folio); > folio_put(folio); > -- > 2.52.0 > >