[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAP4dvsc0BXH+gBL6F9CjCWSw2bD3k8S0CGN2Ym-fZniZH61bag@mail.gmail.com>
Date: Wed, 28 Jan 2026 14:14:39 +0800
From: Zhang Tianci <zhangtianci.1997@...edance.com>
To: Miklos Szeredi <miklos@...redi.hu>
Cc: linux-fsdevel <linux-fsdevel@...r.kernel.org>,
linux-kernel <linux-kernel@...r.kernel.org>, 谢永吉 <xieyongji@...edance.com>
Subject: Re: [External] Re: [QUESTION] fuse: why invalidate all page cache in truncate()
Hi Miklos,
On Tue, Jan 27, 2026 at 5:44 PM Miklos Szeredi <miklos@...redi.hu> wrote:
>
> On Sun, 4 Jan 2026 at 07:51, Zhang Tianci
> <zhangtianci.1997@...edance.com> wrote:
> >
> > Hi all,
> >
> > We have recently encountered a case where aria2c adopts the following
> > IO pattern when downloading files(We enabled writeback_cache option):
> >
> > It allocates file space via fallocate. If fallocate is not supported,
> > it will circularly write 256KB of zero-filled data to the file until it reaches
> > an enough size, and then truncate the file to the desired size. Subsequently,
> > it fills non-zero data into the file through random writes.
> >
> > This causes aria2c to run extremely slowly, which does not meet our
> > expectations,
> > because we have enabled writeback_cache, random writes should not be this slow.
> > After investigation, I found that a readpage operation is performed in every
> > write_begin callback. This is quite odd, as the file was just fully filled with
> > zeros via write operations; the file's page cache should all be uptodate,
> > so there is no need for a readpage. Upon further analysis, I discovered that the
> > root cause is that truncate has invalidated all the page cache.
> >
> > I would like to know why the invalidation is performed. After checking the code
> > commit history, I found that this has been the implementation since FUSE added
> > support for the writeback cache mode.
>
> This in fact goes back to the very first version committed into Linus' tree:
>
> $ git show d8a5ba45457e4 | grep -C 3 invalidate_inode_pages
> +void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
> +{
> + if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
> + invalidate_inode_pages(inode->i_mapping);
>
> This pattern was copied into setattr and, since it was harmless, left
> there for two centuries.
Thanks for sharing your memories.
>
> And because it was there for so long there's a minute chance that some
> fuse filesystem is relying on this behavior, so I'm a bit reluctant to
> change it.
>
> And fixing this does not in fact fix the underlying issue. Manually
> preallocating disk space by writing zero blocks has the size effect of
> priming the page cache as well, which makes the random writes faster.
> Doing the same with fallocate() does not have this side effect and
> would leave the fuse filesystem with the bad performance.
Yep, I agree. I'm just wondering if we can or should optimize for this
specific case.
Thanks,
Tianci
Powered by blists - more mailing lists