Re: [fuse-devel] Debugging a stale kernel cache during file growth

Matthew Wilcox
2026-04-16T23:19:14Z

On Thu, Apr 16, 2026 at 07:41:37PM +0700, Nikolay Amiantov wrote:
> +++ b/fs/fuse/inode.c
> @@ -334,10 +334,42 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
> * extend local i_size without keeping userspace server in sync. So,
> * attr->size coming from server can be stale. We cannot trust it.
> */
> - if (!(cache_mask & STATX_SIZE))
> - i_size_write(inode, attr->size);
> + if (!(cache_mask & STATX_SIZE)) {
> + if (S_ISREG(inode->i_mode) && attr->size > oldsize) {
> + struct folio *folio;
> + pgoff_t index = oldsize >> PAGE_SHIFT;
> +
> + spin_unlock(&fi->lock);
> + folio = __filemap_get_folio(inode->i_mapping, index,
> + FGP_LOCK | FGP_CREAT,
> + mapping_gfp_mask(inode->i_mapping));
> + if (!IS_ERR(folio)) {
> + spin_lock(&fi->lock);
> + if (!test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {
> + folio_clear_uptodate(folio);
> + i_size_write(inode, attr->size);
> + }
> + spin_unlock(&fi->lock);
> +
> + folio_unlock(folio);
> + folio_put(folio);
> + goto size_updated;

Yes, at this point, you've left the folio in an error state. I'm sure you
didn't mean to do that, but the VFS interprets unlocked && !uptodate as
"an error happened" (there is a minor exception to this involving failed
readahead, but let's set that aside).

What you could do, rather than unlock the folio here is to initiate a
read of the folio and allow the read to unlock the folio. But I don't
think this is a good idea, I like the idea of invalidating the folio
much better.