[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAJfpegtmBUSYVkx7_dB1p4XQsd2b156B_vCr=BNx-0yySHOhOg@mail.gmail.com>
Date: Tue, 27 Jan 2026 10:44:13 +0100
From: Miklos Szeredi <miklos@...redi.hu>
To: Zhang Tianci <zhangtianci.1997@...edance.com>
Cc: linux-fsdevel <linux-fsdevel@...r.kernel.org>,
linux-kernel <linux-kernel@...r.kernel.org>, 谢永吉 <xieyongji@...edance.com>
Subject: Re: [QUESTION] fuse: why invalidate all page cache in truncate()
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.
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.
Thanks,
Miklos
Powered by blists - more mailing lists