* Re: [PATCH v5 03/25] fsverity: generate and store zero-block hash
From: Darrick J. Wong @ 2026-03-25 16:07 UTC (permalink / raw)
To: Andrey Albershteyn
Cc: Christoph Hellwig, Andrey Albershteyn, linux-xfs, fsverity,
linux-fsdevel, ebiggers, linux-ext4, linux-f2fs-devel,
linux-btrfs
In-Reply-To: <vatqzcvepp7z6iotzayuyh7fajwdqs76pn4o3sdn3f5thiwsjc@dt46ylrbjnkp>
On Wed, Mar 25, 2026 at 01:03:40PM +0100, Andrey Albershteyn wrote:
> On 2026-03-25 08:57:00, Christoph Hellwig wrote:
> > Shouldn't we still try to get this out of the fsverity_info first?
>
> I don't really understand why, this hash depends on salt (inode
> specific) and merkle tree block size (also inode specific).
Agreed, the merkle tree geometry and salt inputs are per-file.
I sorta wonder if the file ought to get an autogenerated salt if
userspace doesn't provide one, but not enough to go digging any deeper
into "does that make sense?"
--D
^ permalink raw reply
* Re: [PATCH v5 07/25] iomap: introduce IOMAP_F_FSVERITY and teach writeback to handle fsverity
From: Darrick J. Wong @ 2026-03-25 16:26 UTC (permalink / raw)
To: Andrey Albershteyn
Cc: Christoph Hellwig, Andrey Albershteyn, linux-xfs, fsverity,
linux-fsdevel, ebiggers, linux-ext4, linux-f2fs-devel,
linux-btrfs
In-Reply-To: <std5dib2mf5nfd2gf3jbrhujvqr2tytczplopwfy4zrxrrmrgj@py7g4alrifbi>
On Wed, Mar 25, 2026 at 01:38:07PM +0100, Andrey Albershteyn wrote:
> On 2026-03-25 09:00:21, Christoph Hellwig wrote:
> > > @@ -353,9 +353,16 @@ static inline bool iomap_block_needs_zeroing(const struct iomap_iter *iter,
> > > {
> > > const struct iomap *srcmap = iomap_iter_srcmap(iter);
> > >
> > > - return srcmap->type != IOMAP_MAPPED ||
> > > - (srcmap->flags & IOMAP_F_NEW) ||
> > > - pos >= i_size_read(iter->inode);
> > > + if (srcmap->type != IOMAP_MAPPED)
> > > + return true;
> > > +
> > > + if (srcmap->flags & IOMAP_F_NEW)
> > > + return true;
> > > +
> > > + if (srcmap->flags & IOMAP_F_FSVERITY)
> > > + return false;
> > > +
> > > + return pos >= i_size_read(iter->inode);
> >
> > This might be a good time to document the various reasons for needing
> > zeroing.
>
> something like this?
>
> --- a/fs/iomap/buffered-io.c
> +++ b/fs/iomap/buffered-io.c
> @@ -344,9 +344,27 @@ static inline bool iomap_block_needs_zeroing(const struct iomap_iter *iter,
> {
> const struct iomap *srcmap = iomap_iter_srcmap(iter);
>
> - return srcmap->type != IOMAP_MAPPED ||
> - (srcmap->flags & IOMAP_F_NEW) ||
> - pos >= i_size_read(iter->inode);
> + /*
> + * If this block is not mapped, we don't have any backing blocks to read
> + * yet
/* If this block has not been written, there's nothing to read */
> + */
> + if (srcmap->type != IOMAP_MAPPED)
> + return true;
> +
> + /*
> + * This block just got allocated and does not contain any meaningful data
> + */
/* Newly allocated blocks have not been written */
Otherwise looks good to me.
--D
> + if (srcmap->flags & IOMAP_F_NEW)
> + return true;
> +
> + /*
> + * fsverity metadata is stored past i_size, we need to read it instead of
> + * zeroing
> + */
> + if (srcmap->flags & IOMAP_F_FSVERITY)
> + return false;
> +
> + return pos >= i_size_read(iter->inode);
> }
>
> >
> > > +/*
> > > + * IO happens beyond inode EOF, fsverity metadata is stored there
> > > + */
> > > +#define IOMAP_F_FSVERITY (1U << 10)
> >
> > This comment feels a bit too sparse. Here is my interpretation of what
> > this flag does:
> >
> > /*
> > * Indicates reads and writes of fsverity metadata.
> > *
> > * Fsverity metadata is stored after the regular file data and thus beyond
> > * i_size.
> > */
>
> Thanks! I will update it
>
> --
> - Andrey
>
>
^ permalink raw reply
* Re: [PATCH v5 10/25] iomap: teach iomap to handle fsverity holes and verify data holes
From: Darrick J. Wong @ 2026-03-25 16:29 UTC (permalink / raw)
To: Andrey Albershteyn
Cc: linux-xfs, fsverity, linux-fsdevel, ebiggers, hch, linux-ext4,
linux-f2fs-devel, linux-btrfs
In-Reply-To: <20260319170231.1455553-11-aalbersh@kernel.org>
On Thu, Mar 19, 2026 at 06:01:57PM +0100, Andrey Albershteyn wrote:
> fsverity metadata has two kinds of holes - ones in merkle tree and one
> after fsverity descriptor.
>
> Merkle tree holes are blocks full of hashes of zeroed data blocks. These
> are not stored on the disk but synthesized on the fly. This saves a bit
> of space for sparse files. Due to this iomap also need to lookup
> fsverity_info for folios with fsverity metadata. ->vi has a hash of the
> zeroed data block which will be used to fill the merkle tree block. This
> patch extends lookup of fsverity_info from just for file data but also
> for all fsverity metadata.
>
> The hole past descriptor is interpreted as end of metadata region. As we
> don't have EOF here we use this hole as an indication that rest of the
> folio is empty. This patch marks rest of the folio beyond fsverity
> descriptor as uptodate.
>
> For file data, fsverity needs to verify consistency of the whole file
> against the root hash, hashes of holes are included in the merkle tree.
> Verify them too.
>
> Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
> ---
> fs/iomap/buffered-io.c | 40 ++++++++++++++++++++++++++++++++--------
> 1 file changed, 32 insertions(+), 8 deletions(-)
>
> diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
> index a11e54975df8..fce748dfb2cf 100644
> --- a/fs/iomap/buffered-io.c
> +++ b/fs/iomap/buffered-io.c
> @@ -551,9 +551,27 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
> if (plen == 0)
> return 0;
>
> - /* zero post-eof blocks as the page may be mapped */
> - if (iomap_block_needs_zeroing(iter, pos)) {
> + /*
> + * Handling of fsverity "holes". We hit this for two case:
> + * 1. No need to go further, the hole after fsverity
> + * descriptor is the end of the fsverity metadata.
> + *
> + * 2. This folio contains merkle tree blocks which need to be
> + * synthesized. If we already have fsverity info (ctx->vi)
> + * synthesize these blocks.
> + */
> + if ((iomap->flags & IOMAP_F_FSVERITY) &&
> + iomap->type == IOMAP_HOLE) {
> + if (ctx->vi)
> + fsverity_folio_zero_hash(folio, poff, plen,
> + ctx->vi);
Let me nitpick one more time... should this ^^ function be named
fsverify_fill_zerohash, since it fills the folio with a repeating
pattern of the hash of a zeroed block?
(I'm nitpicking because zero is a noun and a verb)
Otherwise the logic looks fine to me, and like hch says this probably
ought to be rolled into patch 8.
--D
> + iomap_set_range_uptodate(folio, poff, plen);
> + } else if (iomap_block_needs_zeroing(iter, pos)) {
> + /* zero post-eof blocks as the page may be mapped */
> folio_zero_range(folio, poff, plen);
> + if (ctx->vi &&
> + !fsverity_verify_blocks(ctx->vi, folio, plen, poff))
> + return -EIO;
> iomap_set_range_uptodate(folio, poff, plen);
> } else {
> if (!*bytes_submitted)
> @@ -600,9 +618,12 @@ void iomap_read_folio(const struct iomap_ops *ops,
>
> trace_iomap_readpage(iter.inode, 1);
>
> - if (iter.pos < i_size_read(iter.inode))
> - ctx->vi = fsverity_get_info(iter.inode);
> - if (ctx->vi)
> + /*
> + * Fetch fsverity_info for both data and fsverity metadata, as iomap
> + * needs zeroed hash for merkle tree block synthesis
> + */
> + ctx->vi = fsverity_get_info(iter.inode);
> + if (ctx->vi && iter.pos < i_size_read(iter.inode))
> fsverity_readahead(ctx->vi, folio->index,
> folio_nr_pages(folio));
>
> @@ -673,9 +694,12 @@ void iomap_readahead(const struct iomap_ops *ops,
>
> trace_iomap_readahead(rac->mapping->host, readahead_count(rac));
>
> - if (iter.pos < i_size_read(iter.inode))
> - ctx->vi = fsverity_get_info(iter.inode);
> - if (ctx->vi)
> + /*
> + * Fetch fsverity_info for both data and fsverity metadata, as iomap
> + * needs zeroed hash for merkle tree block synthesis
> + */
> + ctx->vi = fsverity_get_info(iter.inode);
> + if (ctx->vi && iter.pos < i_size_read(iter.inode))
> fsverity_readahead(ctx->vi, readahead_index(rac),
> readahead_count(rac));
>
> --
> 2.51.2
>
>
^ permalink raw reply
* Re: [PATCH 3/5] fuse: implement file attributes mask for statx
From: Joanne Koong @ 2026-03-25 18:35 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: miklos, bpf, bernd, neal, linux-fsdevel, linux-ext4
In-Reply-To: <177188733175.3935219.14499232455997407711.stgit@frogsfrogsfrogs>
On Mon, Feb 23, 2026 at 3:07 PM Darrick J. Wong <djwong@kernel.org> wrote:
>
> From: Darrick J. Wong <djwong@kernel.org>
>
> Actually copy the attributes/attributes_mask from userspace. Ignore
> file attributes bits that the VFS sets (or doesn't set) on its own.
>
> Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
> ---
> fs/fuse/fuse_i.h | 37 +++++++++++++++++++++++++++++++++++++
> fs/fuse/dir.c | 4 ++++
> fs/fuse/inode.c | 4 ++++
> 3 files changed, 45 insertions(+)
>
>
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index 1d4beca5c7018d..79793db3e9a743 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -147,6 +147,10 @@ struct fuse_inode {
> /** Version of last attribute change */
> u64 attr_version;
>
> + /** statx file attributes */
> + u64 statx_attributes;
> + u64 statx_attributes_mask;
> +
> union {
> /* read/write io cache (regular file only) */
> struct {
> @@ -1236,6 +1240,39 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
> u64 attr_valid, u32 cache_mask,
> u64 evict_ctr);
>
> +/*
> + * These statx attribute flags are set by the VFS so mask them out of replies
> + * from the fuse server for local filesystems. Nonlocal filesystems are
> + * responsible for enforcing and advertising these flags themselves.
> + */
> +#define FUSE_STATX_LOCAL_VFS_ATTRIBUTES (STATX_ATTR_IMMUTABLE | \
> + STATX_ATTR_APPEND)
> +
> +/*
> + * These statx attribute flags are set by the VFS so mask them out of replies
> + * from the fuse server.
> + */
> +#define FUSE_STATX_VFS_ATTRIBUTES (STATX_ATTR_AUTOMOUNT | STATX_ATTR_DAX | \
> + STATX_ATTR_MOUNT_ROOT)
> +
> +static inline u64 fuse_statx_attributes_mask(const struct inode *inode,
> + const struct fuse_statx *sx)
> +{
> + if (fuse_inode_is_exclusive(inode))
> + return sx->attributes_mask & ~(FUSE_STATX_VFS_ATTRIBUTES |
> + FUSE_STATX_LOCAL_VFS_ATTRIBUTES);
> + return sx->attributes_mask & ~FUSE_STATX_VFS_ATTRIBUTES;
> +}
> +
> +static inline u64 fuse_statx_attributes(const struct inode *inode,
> + const struct fuse_statx *sx)
> +{
> + if (fuse_inode_is_exclusive(inode))
> + return sx->attributes & ~(FUSE_STATX_VFS_ATTRIBUTES |
> + FUSE_STATX_LOCAL_VFS_ATTRIBUTES);
> + return sx->attributes & ~FUSE_STATX_VFS_ATTRIBUTES;
> +}
> +
> u32 fuse_get_cache_mask(struct inode *inode);
>
> /**
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index 7ac6b232ef1232..10fa47e969292f 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -1464,6 +1464,8 @@ static int fuse_do_statx(struct mnt_idmap *idmap, struct inode *inode,
> stat->result_mask = sx->mask & (STATX_BASIC_STATS | STATX_BTIME);
> stat->btime.tv_sec = sx->btime.tv_sec;
> stat->btime.tv_nsec = min_t(u32, sx->btime.tv_nsec, NSEC_PER_SEC - 1);
> + stat->attributes |= fuse_statx_attributes(inode, sx);
> + stat->attributes_mask |= fuse_statx_attributes_mask(inode, sx);
> fuse_fillattr(idmap, inode, &attr, stat);
> stat->result_mask |= STATX_TYPE;
> }
> @@ -1568,6 +1570,8 @@ static int fuse_update_get_attr(struct mnt_idmap *idmap, struct inode *inode,
> stat->btime = fi->i_btime;
> stat->result_mask |= STATX_BTIME;
> }
> + stat->attributes = fi->statx_attributes;
> + stat->attributes_mask = fi->statx_attributes_mask;
Do these need to be |= so we don't overwrite any vfs attributes stored
in stat already?
Thanks,
Joanne
> }
>
> return err;
> diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> index 58c3351b467221..ff8b94cb02e63c 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -286,6 +286,10 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
> fi->i_btime.tv_sec = sx->btime.tv_sec;
> fi->i_btime.tv_nsec = sx->btime.tv_nsec;
> }
> +
> + fi->statx_attributes = fuse_statx_attributes(inode, sx);
> + fi->statx_attributes_mask = fuse_statx_attributes_mask(inode,
> + sx);
> }
>
> if (attr->blksize)
>
^ permalink raw reply
* Re: [PATCH 31/41] fs: Provide functions for handling mapping_metadata_bhs directly
From: Jan Kara @ 2026-03-25 19:00 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Jan Kara, linux-fsdevel, linux-block, Christian Brauner, Al Viro,
linux-ext4, Ted Tso, Tigran A. Aivazian, David Sterba,
OGAWA Hirofumi, Muchun Song, Oscar Salvador, David Hildenbrand,
linux-mm, linux-aio, Benjamin LaHaise
In-Reply-To: <acImXDl7MTsmVK_U@infradead.org>
On Mon 23-03-26 22:51:24, Christoph Hellwig wrote:
> On Fri, Mar 20, 2026 at 02:41:26PM +0100, Jan Kara wrote:
> > As part of transition toward moving mapping_metadata_bhs to fs-private
> > part of the inode, provide functions for operations on this list
> > directly instead of going through the inode / mapping.
> >
> > Signed-off-by: Jan Kara <jack@suse.cz>
...
> > @@ -553,9 +547,8 @@ EXPORT_SYMBOL_GPL(mmb_has_buffers);
> > * buffer stays on our list until IO completes (at which point it can be
> > * reaped).
> > */
> > -int sync_mapping_buffers(struct address_space *mapping)
> > +int mmb_sync_buffers(struct mapping_metadata_bhs *mmb)
>
> mmb and buffers in the same name feels a bit redundant.
>
> mmc_sync_all? mapping_sync_buffers?
I've called this just mmb_sync() and I've also shortened
mmb_invalidate_buffers() to mmb_invalidate().
>
> > +int generic_mmb_fsync_noflush(struct file *file,
> > + struct mapping_metadata_bhs *mmb,
> > + loff_t start, loff_t end, bool datasync)
>
> mmb_fsync? mapping_buffers_fsync?
This I've called mmb_fsync().
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply
* Re: [PATCH 12/41] fs: Drop sync_mapping_buffers() from __generic_file_fsync()
From: Jan Kara @ 2026-03-25 19:01 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Jan Kara, linux-fsdevel, linux-block, Christian Brauner, Al Viro,
linux-ext4, Ted Tso, Tigran A. Aivazian, David Sterba,
OGAWA Hirofumi, Muchun Song, Oscar Salvador, David Hildenbrand,
linux-mm, linux-aio, Benjamin LaHaise
In-Reply-To: <acKzrqjnKFNK0xmh@infradead.org>
On Tue 24-03-26 08:54:22, Christoph Hellwig wrote:
> On Tue, Mar 24, 2026 at 02:36:53PM +0100, Jan Kara wrote:
> > Leaving the two implementations separate certainly works for me as well
> > (that's why I've put that patch to the end because I've expected some
> > discussions around it :)). Just the amount of common trivial calls you need
> > to do (fdatawrite(), sync_inode_metadata(),
> > file_check_and_advance_wb_err(), blkdev_issue_flush()) looked high enough
> > to me to be worth merging the implementations. But I don't feel strongly
> > either way.
>
> I don't really feel either way, and I really should not micro-manage
> the series either. So go for what you think works best. The important
> part is to have the fsync changes early and to avoid hardcoding
> buffer_head knowledge into libfs.c.
After trying with the callback and not liking it too much in the end I've
just decided to stay with two separate implementations.
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply
* Re: [PATCH 4/5] fuse: update file mode when updating acls
From: Joanne Koong @ 2026-03-25 19:39 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: miklos, bpf, bernd, neal, linux-fsdevel, linux-ext4
In-Reply-To: <177188733196.3935219.3172887920210313838.stgit@frogsfrogsfrogs>
On Mon, Feb 23, 2026 at 3:07 PM Darrick J. Wong <djwong@kernel.org> wrote:
>
> From: Darrick J. Wong <djwong@kernel.org>
>
> If someone sets ACLs on a file that can be expressed fully as Unix DAC
> mode bits, most local filesystems will then update the mode bits and
> drop the ACL xattr to reduce inefficiency in the file access paths.
> Let's do that too. Note that means that we can setacl and end up with
> no ACL xattrs, so we also need to tolerate ENODATA returns from
> fuse_removexattr.
>
> Note that here we define a "local" fuse filesystem as one that uses
> fuseblk mode; we'll shortly add fuse servers that use iomap for the file
> IO path to that list.
>
> Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> ---
> fs/fuse/fuse_i.h | 2 +-
> fs/fuse/acl.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 43 insertions(+), 2 deletions(-)
>
> diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c
> index cbde6ac1add35a..f2b959efd67490 100644
> --- a/fs/fuse/acl.c
> +++ b/fs/fuse/acl.c
> @@ -11,6 +11,18 @@
> #include <linux/posix_acl.h>
> #include <linux/posix_acl_xattr.h>
>
> +/*
> + * If this fuse server behaves like a local filesystem, we can implement the
> + * kernel's optimizations for ACLs for local filesystems instead of passing
> + * the ACL requests straight through to another server.
> + */
> +static inline bool fuse_inode_has_local_acls(const struct inode *inode)
> +{
> + const struct fuse_conn *fc = get_fuse_conn(inode);
> +
> + return fc->posix_acl && fuse_inode_is_exclusive(inode);
> +}
> +
> static struct posix_acl *__fuse_get_acl(struct fuse_conn *fc,
> struct inode *inode, int type, bool rcu)
> {
> @@ -98,6 +110,7 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> struct inode *inode = d_inode(dentry);
> struct fuse_conn *fc = get_fuse_conn(inode);
> const char *name;
> + umode_t mode = inode->i_mode;
> int ret;
>
> if (fuse_is_bad(inode))
> @@ -113,6 +126,18 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> else
> return -EINVAL;
>
> + /*
> + * If the ACL can be represented entirely with changes to the mode
> + * bits, then most filesystems will update the mode bits and delete
> + * the ACL xattr.
> + */
> + if (acl && type == ACL_TYPE_ACCESS &&
> + fuse_inode_has_local_acls(inode)) {
> + ret = posix_acl_update_mode(idmap, inode, &mode, &acl);
> + if (ret)
> + return ret;
> + }
> +
> if (acl) {
> unsigned int extra_flags = 0;
> /*
I think this sentence in this comment block "Fuse userspace is
responsible for updating access permissions in the inode, if needed"
needs some updating now, since this is only now true for non-local
fuse servers
> @@ -139,7 +164,7 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> * through POSIX ACLs. Such daemons don't expect setgid bits to
> * be stripped.
> */
> - if (fc->posix_acl &&
> + if (fc->posix_acl && mode == inode->i_mode &&
Maybe a bit verbose but imo it'd be clearer if we had a separate
boolean tracking the case where the kernel updated the mode bits,
instead of using "mode == inode->i_mode" here and below for the
fuse_do_setattr() logic block. That makes it more clear here to reason
about (eg it'd at least make it more obvious here that we don't need
to strip sgid since the kernel already did that when it updated the
mode bits earlier)
> !in_group_or_capable(idmap, inode,
> i_gid_into_vfsgid(idmap, inode)))
> extra_flags |= FUSE_SETXATTR_ACL_KILL_SGID;
> @@ -148,6 +173,22 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> kfree(value);
> } else {
> ret = fuse_removexattr(inode, name);
> + /* If the acl didn't exist to start with that's fine. */
> + if (ret == -ENODATA)
> + ret = 0;
> + }
> +
> + /* If we scheduled a mode update above, push that to userspace now. */
> + if (!ret) {
> + struct iattr attr = { };
> +
> + if (mode != inode->i_mode) {
> + attr.ia_valid |= ATTR_MODE;
> + attr.ia_mode = mode;
> + }
> +
> + if (attr.ia_valid)
> + ret = fuse_do_setattr(idmap, dentry, &attr, NULL);
> }
I think this logic reads clearer if it's restructured to
if (!ret && mode != inode->i_mode) {
struct iattr attr = {
.ia_valid = ATTR_MODE,
.ia_mode = mode,
};
ret = fuse_do_setattr(idmap, dentry, &attr, NULL);
}
>
> if (fc->posix_acl) {
>
For local / exclusive servers, the kernel already has / sets the
refreshed attributes, so we could probably skip the invalidation logic
here for that case since the cache is already uptodate?
Thanks,
Joanne
^ permalink raw reply
* Re: [PATCH] ext4: Fix deadlock on inode reallocation
From: Mateusz Guzik @ 2026-03-25 21:07 UTC (permalink / raw)
To: Jan Kara; +Cc: Ted Tso, linux-ext4, yi1.lai, stable
In-Reply-To: <20260320090428.24899-2-jack@suse.cz>
can this get any traction?
master as-is contains a change which uncovered the ext4 problem.
either the deadlock needs to be fixed in time for the release or the
other change needs to get temporarily reverted.
interested parties can find proposed revert here:
https://lore.kernel.org/linux-fsdevel/20260316103306.1258289-1-mjguzik@gmail.com/
On Fri, Mar 20, 2026 at 10:04 AM Jan Kara <jack@suse.cz> wrote:
>
> Currently there is a race in ext4 when reallocating freed inode
> resulting in a deadlock:
>
> Task1 Task2
> ext4_evict_inode()
> handle = ext4_journal_start();
> ...
> if (IS_SYNC(inode))
> handle->h_sync = 1;
> ext4_free_inode()
> ext4_new_inode()
> handle = ext4_journal_start()
> finds the bit in inode bitmap
> already clear
> insert_inode_locked()
> waits for inode to be
> removed from the hash.
> ext4_journal_stop(handle)
> jbd2_journal_stop(handle)
> jbd2_log_wait_commit(journal, tid);
> - deadlocks waiting for transaction handle Task2 holds
>
> Fix the problem by removing inode from the hash already in
> ext4_clear_inode() by which time all IO for the inode is done so reuse
> is already fine but we are still before possibly blocking on transaction
> commit.
>
> Reported-by: "Lai, Yi" <yi1.lai@linux.intel.com>
> Link: https://lore.kernel.org/all/abNvb2PcrKj1FBeC@ly-workstation
> Fixes: 88ec797c4680 ("fs: make insert_inode_locked() wait for inode destruction")
> CC: stable@vger.kernel.org
> Signed-off-by: Jan Kara <jack@suse.cz>
> ---
> fs/ext4/super.c | 21 +++++++++++++++++++++
> 1 file changed, 21 insertions(+)
>
> Ted, this is a regression recently introduced by VFS changes in
> insert_inode_locked() but I think it's best fixed in ext4. If you agree, it
> would be nice to merge this so that it makes it to 7.0 release. Thanks!
>
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 43f680c750ae..b8122d24c083 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -1527,6 +1527,27 @@ void ext4_clear_inode(struct inode *inode)
> invalidate_inode_buffers(inode);
> clear_inode(inode);
> ext4_discard_preallocations(inode);
> + /*
> + * We must remove the inode from the hash before ext4_free_inode()
> + * clears the bit in inode bitmap as otherwise another process reusing
> + * the inode will block in insert_inode_hash() waiting for inode
> + * eviction to complete while holding transaction handle open, but
> + * ext4_evict_inode() still running for that inode could block waiting
> + * for transaction commit if the inode is marked as IS_SYNC => deadlock.
> + *
> + * Removing the inode from the hash here is safe. There are two cases
> + * to consider:
> + * 1) The inode still has references to it (i_nlink > 0). In that case
> + * we are keeping the inode and once we remove the inode from the hash,
> + * iget() can create the new inode structure for the same inode number
> + * and we are fine with that as all IO on behalf of the inode is
> + * finished.
> + * 2) We are deleting the inode (i_nlink == 0). In that case inode
> + * number cannot be reused until ext4_free_inode() clears the bit in
> + * the inode bitmap, at which point all IO is done and reuse is fine
> + * again.
> + */
> + remove_inode_hash(inode);
> ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
> dquot_drop(inode);
> if (EXT4_I(inode)->jinode) {
> --
> 2.51.0
>
^ permalink raw reply
* Re: [PATCH 3/5] fuse: implement file attributes mask for statx
From: Darrick J. Wong @ 2026-03-25 22:12 UTC (permalink / raw)
To: Joanne Koong; +Cc: miklos, bpf, bernd, neal, linux-fsdevel, linux-ext4
In-Reply-To: <CAJnrk1ZZV=nf2ZvsFz2gCEdFanK2c=_4X8hH5PyZ4ys-b5T8kQ@mail.gmail.com>
On Wed, Mar 25, 2026 at 11:35:47AM -0700, Joanne Koong wrote:
> On Mon, Feb 23, 2026 at 3:07 PM Darrick J. Wong <djwong@kernel.org> wrote:
> >
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > Actually copy the attributes/attributes_mask from userspace. Ignore
> > file attributes bits that the VFS sets (or doesn't set) on its own.
> >
> > Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> > Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
> > ---
> > fs/fuse/fuse_i.h | 37 +++++++++++++++++++++++++++++++++++++
> > fs/fuse/dir.c | 4 ++++
> > fs/fuse/inode.c | 4 ++++
> > 3 files changed, 45 insertions(+)
> >
> >
> > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> > index 1d4beca5c7018d..79793db3e9a743 100644
> > --- a/fs/fuse/fuse_i.h
> > +++ b/fs/fuse/fuse_i.h
> > @@ -147,6 +147,10 @@ struct fuse_inode {
> > /** Version of last attribute change */
> > u64 attr_version;
> >
> > + /** statx file attributes */
> > + u64 statx_attributes;
> > + u64 statx_attributes_mask;
> > +
> > union {
> > /* read/write io cache (regular file only) */
> > struct {
> > @@ -1236,6 +1240,39 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
> > u64 attr_valid, u32 cache_mask,
> > u64 evict_ctr);
> >
> > +/*
> > + * These statx attribute flags are set by the VFS so mask them out of replies
> > + * from the fuse server for local filesystems. Nonlocal filesystems are
> > + * responsible for enforcing and advertising these flags themselves.
> > + */
> > +#define FUSE_STATX_LOCAL_VFS_ATTRIBUTES (STATX_ATTR_IMMUTABLE | \
> > + STATX_ATTR_APPEND)
> > +
> > +/*
> > + * These statx attribute flags are set by the VFS so mask them out of replies
> > + * from the fuse server.
> > + */
> > +#define FUSE_STATX_VFS_ATTRIBUTES (STATX_ATTR_AUTOMOUNT | STATX_ATTR_DAX | \
> > + STATX_ATTR_MOUNT_ROOT)
> > +
> > +static inline u64 fuse_statx_attributes_mask(const struct inode *inode,
> > + const struct fuse_statx *sx)
> > +{
> > + if (fuse_inode_is_exclusive(inode))
> > + return sx->attributes_mask & ~(FUSE_STATX_VFS_ATTRIBUTES |
> > + FUSE_STATX_LOCAL_VFS_ATTRIBUTES);
> > + return sx->attributes_mask & ~FUSE_STATX_VFS_ATTRIBUTES;
> > +}
> > +
> > +static inline u64 fuse_statx_attributes(const struct inode *inode,
> > + const struct fuse_statx *sx)
> > +{
> > + if (fuse_inode_is_exclusive(inode))
> > + return sx->attributes & ~(FUSE_STATX_VFS_ATTRIBUTES |
> > + FUSE_STATX_LOCAL_VFS_ATTRIBUTES);
> > + return sx->attributes & ~FUSE_STATX_VFS_ATTRIBUTES;
> > +}
> > +
> > u32 fuse_get_cache_mask(struct inode *inode);
> >
> > /**
> > diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> > index 7ac6b232ef1232..10fa47e969292f 100644
> > --- a/fs/fuse/dir.c
> > +++ b/fs/fuse/dir.c
> > @@ -1464,6 +1464,8 @@ static int fuse_do_statx(struct mnt_idmap *idmap, struct inode *inode,
> > stat->result_mask = sx->mask & (STATX_BASIC_STATS | STATX_BTIME);
> > stat->btime.tv_sec = sx->btime.tv_sec;
> > stat->btime.tv_nsec = min_t(u32, sx->btime.tv_nsec, NSEC_PER_SEC - 1);
> > + stat->attributes |= fuse_statx_attributes(inode, sx);
> > + stat->attributes_mask |= fuse_statx_attributes_mask(inode, sx);
> > fuse_fillattr(idmap, inode, &attr, stat);
> > stat->result_mask |= STATX_TYPE;
> > }
> > @@ -1568,6 +1570,8 @@ static int fuse_update_get_attr(struct mnt_idmap *idmap, struct inode *inode,
> > stat->btime = fi->i_btime;
> > stat->result_mask |= STATX_BTIME;
> > }
> > + stat->attributes = fi->statx_attributes;
> > + stat->attributes_mask = fi->statx_attributes_mask;
>
> Do these need to be |= so we don't overwrite any vfs attributes stored
> in stat already?
Ackpth yes. Good catch!
--D
> Thanks,
> Joanne
>
> > }
> >
> > return err;
> > diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> > index 58c3351b467221..ff8b94cb02e63c 100644
> > --- a/fs/fuse/inode.c
> > +++ b/fs/fuse/inode.c
> > @@ -286,6 +286,10 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
> > fi->i_btime.tv_sec = sx->btime.tv_sec;
> > fi->i_btime.tv_nsec = sx->btime.tv_nsec;
> > }
> > +
> > + fi->statx_attributes = fuse_statx_attributes(inode, sx);
> > + fi->statx_attributes_mask = fuse_statx_attributes_mask(inode,
> > + sx);
> > }
> >
> > if (attr->blksize)
> >
>
^ permalink raw reply
* Re: [PATCH 4/5] fuse: update file mode when updating acls
From: Darrick J. Wong @ 2026-03-25 22:23 UTC (permalink / raw)
To: Joanne Koong; +Cc: miklos, bpf, bernd, neal, linux-fsdevel, linux-ext4
In-Reply-To: <CAJnrk1YL3KnON-WtNjNi+2GZ+6rYvnVUnYwCk5efv0o41XkxcA@mail.gmail.com>
On Wed, Mar 25, 2026 at 12:39:57PM -0700, Joanne Koong wrote:
> On Mon, Feb 23, 2026 at 3:07 PM Darrick J. Wong <djwong@kernel.org> wrote:
> >
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > If someone sets ACLs on a file that can be expressed fully as Unix DAC
> > mode bits, most local filesystems will then update the mode bits and
> > drop the ACL xattr to reduce inefficiency in the file access paths.
> > Let's do that too. Note that means that we can setacl and end up with
> > no ACL xattrs, so we also need to tolerate ENODATA returns from
> > fuse_removexattr.
> >
> > Note that here we define a "local" fuse filesystem as one that uses
> > fuseblk mode; we'll shortly add fuse servers that use iomap for the file
> > IO path to that list.
> >
> > Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> > ---
> > fs/fuse/fuse_i.h | 2 +-
> > fs/fuse/acl.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
> > 2 files changed, 43 insertions(+), 2 deletions(-)
> >
> > diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c
> > index cbde6ac1add35a..f2b959efd67490 100644
> > --- a/fs/fuse/acl.c
> > +++ b/fs/fuse/acl.c
> > @@ -11,6 +11,18 @@
> > #include <linux/posix_acl.h>
> > #include <linux/posix_acl_xattr.h>
> >
> > +/*
> > + * If this fuse server behaves like a local filesystem, we can implement the
> > + * kernel's optimizations for ACLs for local filesystems instead of passing
> > + * the ACL requests straight through to another server.
> > + */
> > +static inline bool fuse_inode_has_local_acls(const struct inode *inode)
> > +{
> > + const struct fuse_conn *fc = get_fuse_conn(inode);
> > +
> > + return fc->posix_acl && fuse_inode_is_exclusive(inode);
> > +}
> > +
> > static struct posix_acl *__fuse_get_acl(struct fuse_conn *fc,
> > struct inode *inode, int type, bool rcu)
> > {
> > @@ -98,6 +110,7 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> > struct inode *inode = d_inode(dentry);
> > struct fuse_conn *fc = get_fuse_conn(inode);
> > const char *name;
> > + umode_t mode = inode->i_mode;
> > int ret;
> >
> > if (fuse_is_bad(inode))
> > @@ -113,6 +126,18 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> > else
> > return -EINVAL;
> >
> > + /*
> > + * If the ACL can be represented entirely with changes to the mode
> > + * bits, then most filesystems will update the mode bits and delete
> > + * the ACL xattr.
> > + */
> > + if (acl && type == ACL_TYPE_ACCESS &&
> > + fuse_inode_has_local_acls(inode)) {
> > + ret = posix_acl_update_mode(idmap, inode, &mode, &acl);
> > + if (ret)
> > + return ret;
> > + }
> > +
> > if (acl) {
> > unsigned int extra_flags = 0;
> > /*
>
> I think this sentence in this comment block "Fuse userspace is
> responsible for updating access permissions in the inode, if needed"
> needs some updating now, since this is only now true for non-local
> fuse servers
Done.
/*
* For non-local filesystems, fuse userspace is responsible for
* updating access permissions in the inode, if needed.
* fuse_setxattr invalidates the inode attributes, which will
* force them to be refreshed the next time they are used, and
* it also updates i_ctime.
*/
>
> > @@ -139,7 +164,7 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> > * through POSIX ACLs. Such daemons don't expect setgid bits to
> > * be stripped.
> > */
> > - if (fc->posix_acl &&
> > + if (fc->posix_acl && mode == inode->i_mode &&
>
> Maybe a bit verbose but imo it'd be clearer if we had a separate
> boolean tracking the case where the kernel updated the mode bits,
> instead of using "mode == inode->i_mode" here and below for the
> fuse_do_setattr() logic block. That makes it more clear here to reason
> about (eg it'd at least make it more obvious here that we don't need
> to strip sgid since the kernel already did that when it updated the
> mode bits earlier)
Yeah, this could be keyed off fuse_inode_has_local_acls().
>
> > !in_group_or_capable(idmap, inode,
> > i_gid_into_vfsgid(idmap, inode)))
> > extra_flags |= FUSE_SETXATTR_ACL_KILL_SGID;
> > @@ -148,6 +173,22 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> > kfree(value);
> > } else {
> > ret = fuse_removexattr(inode, name);
> > + /* If the acl didn't exist to start with that's fine. */
> > + if (ret == -ENODATA)
> > + ret = 0;
> > + }
> > +
> > + /* If we scheduled a mode update above, push that to userspace now. */
> > + if (!ret) {
> > + struct iattr attr = { };
> > +
> > + if (mode != inode->i_mode) {
> > + attr.ia_valid |= ATTR_MODE;
> > + attr.ia_mode = mode;
> > + }
> > +
> > + if (attr.ia_valid)
> > + ret = fuse_do_setattr(idmap, dentry, &attr, NULL);
> > }
>
> I think this logic reads clearer if it's restructured to
>
> if (!ret && mode != inode->i_mode) {
> struct iattr attr = {
> .ia_valid = ATTR_MODE,
> .ia_mode = mode,
> };
>
> ret = fuse_do_setattr(idmap, dentry, &attr, NULL);
> }
>
> >
> > if (fc->posix_acl) {
> >
>
> For local / exclusive servers, the kernel already has / sets the
> refreshed attributes, so we could probably skip the invalidation logic
> here for that case since the cache is already uptodate?
I could, but down in the iomap patchset I add more logic to update the
ctime:
struct iattr attr = { };
/*
* When we're running in iomap mode, we need to update mode and
* ctime ourselves instead of letting the fuse server figure
* that out.
*/
if (is_iomap) {
attr.ia_valid |= ATTR_CTIME;
inode_set_ctime_current(inode);
attr.ia_ctime = inode_get_ctime(inode);
}
/*
* If we scheduled a mode update above, push that to userspace
* now.
*/
if (mode != inode->i_mode) {
attr.ia_valid |= ATTR_MODE;
attr.ia_mode = mode;
}
if (attr.ia_valid)
ret = fuse_do_setattr(idmap, dentry, &attr, NULL);
In non-iomap "local acls" mode the server's still expected to update
ctime in set/removexattr. OTOH I guess that is ... 65-16=49 patches
from now so maybe it's worth the churn?
Either way thanks for getting back to this. :)
--D
> Thanks,
> Joanne
>
^ permalink raw reply
* Re: [PATCH] ext4: Fix call trace when remounting to read only in data=journal mode
From: Gerald Yang @ 2026-03-26 1:50 UTC (permalink / raw)
To: Jan Kara; +Cc: tytso, adilger.kernel, linux-ext4, gerald.yang.tw
In-Reply-To: <CAMsNC+svSX9AiZbs1dd4qigZqBuOjuCHOjpyXzgaO0sNLUHDYA@mail.gmail.com>
Hi Jan,
I'd like to ask when this will land in upstream kernel? Thanks.
On Thu, Feb 5, 2026 at 8:59 PM Gerald Yang <gerald.yang@canonical.com> wrote:
>
> Thanks Jan for fixing this issue, I can confirm the patch works for me too.
>
>
> On Thu, Feb 5, 2026 at 5:25 PM Jan Kara <jack@suse.cz> wrote:
> >
> > On Tue 03-02-26 15:50:43, Jan Kara wrote:
> > > Hello,
> > >
> > > On Fri 30-01-26 19:38:55, Gerald Yang wrote:
> > > > Thanks for sharing the findings, I'd also like to share some findings:
> > > > I tried to figure out why the buffer is dirty after calling sync_filesystem,
> > > > in mpage_prepare_extent_to_map, first I printed folio_test_dirty(folio):
> > > >
> > > > while (index <= end)
> > > > ...
> > > > for (i = 0; i < nr_folios; i++) {
> > > > ...
> > > > (print if folio is dirty here)
> > > >
> > > > and actually all folios are clean:
> > > > if (!folio_test_dirty(folio) ||
> > > > ...
> > > > folio_unlock(folio);
> > > > continue; <==== continue here without writing anything
> > > >
> > > > Because the call trace happens before going into the above while loop:
> > > >
> > > > if (ext4_should_journal_data(mpd->inode)) {
> > > > handle = ext4_journal_start(mpd->inode, EXT4_HT_WRITE_PAGE,
> > > >
> > > > it checks if the file system is read only and dumps the call trace in
> > > > ext4_journal_check_start, but it doesn't check if there are any real writes
> > > > that will happen later in the loop.
> > > >
> > > > To confirm this, first I added 2 more lines in the reproduce script before
> > > > remounting read only:
> > > > sync <==== it calls ext4_sync_fs to flush all dirty data same as what's
> > > > called during remount read only
> > > > echo 1 > /proc/sys/vm/drop_caches <==== drop clean page cache
> > > > mount -o remount,ro ext4disk mnt
> > > >
> > > > Then I can no longer reproduce the call trace.
> > >
> > > OK, but ext4_do_writepages() has a check at the beginning:
> > >
> > > if (!mapping->nrpages || !mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
> > > goto out_writepages;
> > >
> > > So if there are no dirty pages, mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)
> > > should be false and so we shouldn't go further?
> > >
> > > It all looks like some kind of a race because I'm not always able to
> > > reproduce the problem... I'll try to look more into this.
> >
> > OK, the race is with checkpointing code writing the buffers while flush
> > worker tries to writeback the pages. I've posted a patch which fixes the
> > issue for me.
> >
> > Honza
> > --
> > Jan Kara <jack@suse.com>
> > SUSE Labs, CR
^ permalink raw reply
* Re: [RFC 1/1] ext4: fail fast on repeated metadata reads after IO failure
From: changfengnan @ 2026-03-26 2:26 UTC (permalink / raw)
To: Zhang Yi
Cc: Diangang Li, Andreas Dilger, Diangang Li, tytso, linux-ext4,
linux-fsdevel, linux-kernel
In-Reply-To: <e5c657e6-ffbd-4327-adaf-ae52cb50b96d@gmail.com>
> From: "Zhang Yi"<yizhang089@gmail.com>
> Date: Wed, Mar 25, 2026, 22:27
> Subject: Re: [RFC 1/1] ext4: fail fast on repeated metadata reads after IO failure
> To: "Diangang Li"<lidiangang@bytedance.com>, "Andreas Dilger"<adilger@dilger.ca>, "Diangang Li"<diangangli@gmail.com>
> Cc: <tytso@mit.edu>, <linux-ext4@vger.kernel.org>, <linux-fsdevel@vger.kernel.org>, <linux-kernel@vger.kernel.org>, <changfengnan@bytedance.com>
> Hi, Diangang,
>
> On 3/25/2026 7:13 PM, Diangang Li wrote:
> > Hi Andreas,
> >
> > BH_Read_EIO is cleared on successful read or write.
>
> I think what Andreas means is, since you modified the ext4_read_bh()
> interface, if the bh to be read already has the Read_EIO flag set, then
> subsequent read operations through this interface will directly return
> failure without issuing a read I/O. At the same time, because its state
IMO, we first need to reach a consensus on whether we can expect a
retry to succeed after a read failure.
Given that current SCSI and NVMe drivers already perform multiple
retries for I/O errors.
IMO, this depends on the specific error. If the block layer returns
BLK_STS_RESOURCE or BLK_STS_AGAIN, we can retry; however, if
it returns BLK_STS_MEDIUM or BLK_STS_IOERR, there is no need to retry.
For scenarios requiring a retry, we should also wait for a certain time
window before retrying.
Thanks.
Fengnan.
> is also not uptodate, for an existing block, a write request will not be
> issued either. How can we clear this Read_EIO flag? IIRC, relying solely
> on ext4_read_bh_nowait() doesn't seem sufficient to achieve this.
>
> Thanks,
> Yi.
>
> >
> > In practice bad blocks are typically repaired/remapped on write, so we
> > expect recovery after a successful rewrite. If the block is never
> > rewritten, repeatedly issuing the same failing read does not help.
> >
> > We clear the flag on successful reads so the buffer can recover
> > immediately if the error was transient. Since read-ahead reads are not
> > blocked, a later successful read-ahead will clear the flag and allow
> > subsequent synchronous readers to proceed normally.
> >
> > Best,
> > Diangang
> >
> > On 3/25/26 6:15 PM, Andreas Dilger wrote:
> >> On Mar 25, 2026, at 03:33, Diangang Li <diangangli@gmail.com> wrote:
> >>>
> >>> From: Diangang Li <lidiangang@bytedance.com>
> >>>
> >>> ext4 metadata reads serialize on BH_Lock (lock_buffer). If the read fails,
> >>> the buffer remains !Uptodate. With concurrent callers, each waiter can
> >>> retry the same failing read after the previous holder drops BH_Lock. This
> >>> amplifies device retry latency and may trigger hung tasks.
> >>>
> >>> In the normal read path the block driver already performs its own retries.
> >>> Once the retries keep failing, re-submitting the same metadata read from
> >>> the filesystem just amplifies the latency by serializing waiters on
> >>> BH_Lock.
> >>>
> >>> Remember read failures on buffer_head and fail fast for ext4 metadata reads
> >>> once a buffer has already failed to read. Clear the flag on successful
> >>> read/write completion so the buffer can recover. ext4 read-ahead uses
> >>> ext4_read_bh_nowait(), so it does not set the failure flag and remains
> >>> best-effort.
> >>
> >> Not that the patch is bad, but if the BH_Read_EIO flag is set on a buffer
> >> and it prevents other tasks from reading that block again, how would the
> >> buffer ever become Uptodate to clear the flag? There isn't enough state
> >> in a 1-bit flag to have any kind of expiry and later retry.
> >>
> >> Cheers, Andreas
> >
>
^ permalink raw reply
* Re: [RFC] Proposal: provenance_time (ptime) — a settable timestamp for cross-filesystem migration
From: Sean Smith @ 2026-03-26 2:29 UTC (permalink / raw)
To: Simon Richter
Cc: linux-fsdevel, linux-ext4, tytso, dsterba, david, brauner,
osandov
In-Reply-To: <befb1cd7-f709-4e46-b08f-9c2579b10fd6@hogyros.de>
Setting an xattr user.provenance_time was a solution my AI agents
and I arrived at for meeting my immediate Windows to Linux
migration needs. The idea to submit this ptime proposal was to
help the Linux kernel maintainers better understand the types of
problems that users like me encounter when switching to Linux.
Users like me are working with AI to solve previously neglected,
and untenable problems. I believe I am amongst the first of a wave of
disruptive projects that is going to hit many industries quite hard.
Users like me are unprecedented and working on unprecedented projects.
I think of my proposal being a bit of a heads-up to the Linux maintainers.
To help you plan for what's coming by understanding the vanguard of users
that are now arriving.
My intent with the proposal was to highlight:
1. The friction I encountered in Windows made the switch to Linux
*necessary*.
2. The friction in migrating to Linux can be reduced with simple,
long-overdue changes.
3. While ptime might not be effective proof of a files provenance in terms
of forensic computing, it is metadata that is critical to effective human
and agentic workflows.
Additionally, a sworn affidavit of authenticity is one way to assert the
date created is accurate file provenance. If the system administrator
knows the integrity of the metadata is sound, then they can attest
to that under oath. But if that metadata is destroyed, there is
nothing to attest to. The date created metadata can also be corroborated
by third parties. A plan beneficiary who records a phone call with
their insurer, and the insurer representative enters call notes into
a database. It's an event that 'happened'. With enough third-party data points
verifying a private dataset, the metadata becomes something a reasonable
person should believe to be accurate.
My point isn't to argue rules of evidence or debate how AI deep fakes
will require courts to exercise enhanced scrutiny. It's to illustrate
that the date created metadata has substantive value to legal work.
Additionally, that legal work is going to become an increasingly agentic
and pro se process that can supply substantive value to society by
enabling the under-served to access justice through an open-source
stack.
My proposal for provenance_time is more about reducing friction in migrating
to Linux and optimizing real-world workflows for humans and agents.
I concede that using xattr to add ptime will be effective, but it does
introduce operational inefficiencies and overhead. Overhead that I think
it worthwhile to be mindful of. Having every users AI agents coding up
an xattr fix for an obvious problem is a lot of wasted tokens and
human attention.
Sincerely,
Sean Smith
DefendTheDisabled.org
^ permalink raw reply
* [PATCH -v2] ext4: handle wraparound when searching for blocks for indirect mapped blocks
From: Theodore Ts'o @ 2026-03-26 4:58 UTC (permalink / raw)
To: Ext4 Developers List; +Cc: Theodore Ts'o, Jan Kara
Commit 4865c768b563 ("ext4: always allocate blocks only from groups
inode can use") restricts what blocks will be allocated for indirect
block based files to block numbers that fit within 32-bit block
numbers.
However, when using a review bot running on the latest Gemini LLM to
check this commit when backporting into an LTS based kernel, it raised
this concern:
If ac->ac_g_ex.fe_group is >= ngroups (for instance, if the goal
group was populated via stream allocation from s_mb_last_groups),
then start will be >= ngroups.
Does this allow allocating blocks beyond the 32-bit limit for
indirect block mapped files? The commit message mentions that
ext4_mb_scan_groups_linear() takes care to not select unsupported
groups. However, its loop uses group = *start, and the very first
iteration will call ext4_mb_scan_group() with this unsupported
group because next_linear_group() is only called at the end of the
iteration.
After reviewing the code paths involved and considering the LLM
review, I determined that this can happen when there is a file system
where some files/directories are extent-mapped and others are
indirect-block mapped. To address this, add a safety clamp in
ext4_mb_scan_groups().
Fixes: 4865c768b563 ("ext4: always allocate blocks only from groups inode can use")
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: Jan Kara <jack@suse.cz>
---
v2:
* Remove extra checks that were not needed once we add the clamp
in ext4_mb_scan_groups().
fs/ext4/mballoc.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 20e9fdaf4301..b10db5d7545b 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -1199,6 +1199,8 @@ static int ext4_mb_scan_groups(struct ext4_allocation_context *ac)
/* searching for the right group start from the goal value specified */
start = ac->ac_g_ex.fe_group;
+ if (start >= ngroups)
+ start = 0;
ac->ac_prefetch_grp = start;
ac->ac_prefetch_nr = 0;
--
2.51.0
^ permalink raw reply related
* Re: [PATCH] ext4: add bounds check in ext4_xattr_ibody_get() to prevent out-of-bounds access
From: Theodore Tso @ 2026-03-26 5:47 UTC (permalink / raw)
To: Deepanshu Kartikey
Cc: adilger.kernel, linux-ext4, linux-kernel,
syzbot+fb32afec111a7d61b939
In-Reply-To: <20260224231429.31361-1-kartikey406@gmail.com>
On Wed, Feb 25, 2026 at 04:44:29AM +0530, Deepanshu Kartikey wrote:
> When mounting a corrupted ext4 filesystem, the inode's i_extra_isize
> can be set to a value that leaves insufficient space in the inode for
> the inline xattr header and entries. While ext4_iget() validates that
> i_extra_isize fits within the inode size, it does not account for the
> additional sizeof(ext4_xattr_ibody_header) needed by IHDR/IFIRST.
Actually, it does more than that. It also calls xattr_check_inode()
which should validate the xattr block in the inode.
So instead of adding the check in ext4_xattr_ibody_get(), we should
fix the check in __xattr_check_inode(). This is preferable since it's
more efficient than checking every time we try to fetch an extended
attribute, instead of validating it when the inode is read from the
inode table block.
- Ted
^ permalink raw reply
* Re: [PATCH v5 01/25] fsverity: report validation errors through fserror to fsnotify
From: Christoph Hellwig @ 2026-03-26 6:20 UTC (permalink / raw)
To: Andrey Albershteyn
Cc: Christoph Hellwig, Andrey Albershteyn, linux-xfs, fsverity,
linux-fsdevel, ebiggers, linux-ext4, linux-f2fs-devel,
linux-btrfs, djwong
In-Reply-To: <3lllvimldwcgi7crh3kgwy3a5z2ng2ugcka52ab47o5mwx4dnu@xyzbelhykn7n>
On Wed, Mar 25, 2026 at 12:41:23PM +0100, Andrey Albershteyn wrote:
> > Btw, would it make sense to enhance the interface to tell why the
> > data vs considered lost? i.e. checksum failure vs
>
> > (part of) device disappeared?
>
> isn't it something filesystem should report even before fsverity
> gets the page?
I meant the fserror lost reporting.
^ permalink raw reply
* Re: [RFC 1/1] ext4: fail fast on repeated metadata reads after IO failure
From: Diangang Li @ 2026-03-26 7:42 UTC (permalink / raw)
To: Zhang Yi, Andreas Dilger, Diangang Li
Cc: tytso, linux-ext4, linux-fsdevel, linux-kernel, changfengnan
In-Reply-To: <e5c657e6-ffbd-4327-adaf-ae52cb50b96d@gmail.com>
Hi, Yi,
Thanks. Yes, for existing metadata blocks ext4 is read-modify-write, so
without a successful read (Uptodate) there is no write path to update
that block.
In the case we're seeing, the read keeps failing (repeated I/O errors on
the same LBA), so the write never has a chance to run either. Given
that, would it make sense (as Fengnan suggested) to treat persistent
media errors (e.g. MEDIUM ERROR / IO ERROR) as non-retryable at the
filesystem level, i.e. keep failing fast for that block? That would
avoid the BH_Lock thundering herd and prevent hung tasks.
Thanks,
Diangang
On 3/25/26 10:27 PM, Zhang Yi wrote:
> Hi, Diangang,
>
> On 3/25/2026 7:13 PM, Diangang Li wrote:
>> Hi Andreas,
>>
>> BH_Read_EIO is cleared on successful read or write.
>
> I think what Andreas means is, since you modified the ext4_read_bh()
> interface, if the bh to be read already has the Read_EIO flag set, then
> subsequent read operations through this interface will directly return
> failure without issuing a read I/O. At the same time, because its state
> is also not uptodate, for an existing block, a write request will not be
> issued either. How can we clear this Read_EIO flag? IIRC, relying solely
> on ext4_read_bh_nowait() doesn't seem sufficient to achieve this.
>
> Thanks,
> Yi.
>
>>
>> In practice bad blocks are typically repaired/remapped on write, so we
>> expect recovery after a successful rewrite. If the block is never
>> rewritten, repeatedly issuing the same failing read does not help.
>>
>> We clear the flag on successful reads so the buffer can recover
>> immediately if the error was transient. Since read-ahead reads are not
>> blocked, a later successful read-ahead will clear the flag and allow
>> subsequent synchronous readers to proceed normally.
>>
>> Best,
>> Diangang
>>
>> On 3/25/26 6:15 PM, Andreas Dilger wrote:
>>> On Mar 25, 2026, at 03:33, Diangang Li <diangangli@gmail.com> wrote:
>>>>
>>>> From: Diangang Li <lidiangang@bytedance.com>
>>>>
>>>> ext4 metadata reads serialize on BH_Lock (lock_buffer). If the read
>>>> fails,
>>>> the buffer remains !Uptodate. With concurrent callers, each waiter can
>>>> retry the same failing read after the previous holder drops BH_Lock.
>>>> This
>>>> amplifies device retry latency and may trigger hung tasks.
>>>>
>>>> In the normal read path the block driver already performs its own
>>>> retries.
>>>> Once the retries keep failing, re-submitting the same metadata read
>>>> from
>>>> the filesystem just amplifies the latency by serializing waiters on
>>>> BH_Lock.
>>>>
>>>> Remember read failures on buffer_head and fail fast for ext4
>>>> metadata reads
>>>> once a buffer has already failed to read. Clear the flag on successful
>>>> read/write completion so the buffer can recover. ext4 read-ahead uses
>>>> ext4_read_bh_nowait(), so it does not set the failure flag and remains
>>>> best-effort.
>>>
>>> Not that the patch is bad, but if the BH_Read_EIO flag is set on a
>>> buffer
>>> and it prevents other tasks from reading that block again, how would the
>>> buffer ever become Uptodate to clear the flag? There isn't enough state
>>> in a 1-bit flag to have any kind of expiry and later retry.
>>>
>>> Cheers, Andreas
>>
>
^ permalink raw reply
* Re: [PATCH] ext4: Fix call trace when remounting to read only in data=journal mode
From: Jan Kara @ 2026-03-26 8:54 UTC (permalink / raw)
To: Gerald Yang; +Cc: Jan Kara, tytso, adilger.kernel, linux-ext4, gerald.yang.tw
In-Reply-To: <CAMsNC+vQceRaw9DkbQFo1p2piwcwDbTgohqt=Gtqj27n42kLTQ@mail.gmail.com>
Hi!
On Thu 26-03-26 09:50:39, Gerald Yang wrote:
> I'd like to ask when this will land in upstream kernel? Thanks.
Well, this is more a question to Ted. He didn't pick up the patch [1] to
his tree yet. I guess he'll pick it up for the next merge window which will
start in two weeks or so.
Honza
[1] https://lore.kernel.org/linux-ext4/20260205092223.21287-2-jack@suse.cz/
>
> On Thu, Feb 5, 2026 at 8:59 PM Gerald Yang <gerald.yang@canonical.com> wrote:
> >
> > Thanks Jan for fixing this issue, I can confirm the patch works for me too.
> >
> >
> > On Thu, Feb 5, 2026 at 5:25 PM Jan Kara <jack@suse.cz> wrote:
> > >
> > > On Tue 03-02-26 15:50:43, Jan Kara wrote:
> > > > Hello,
> > > >
> > > > On Fri 30-01-26 19:38:55, Gerald Yang wrote:
> > > > > Thanks for sharing the findings, I'd also like to share some findings:
> > > > > I tried to figure out why the buffer is dirty after calling sync_filesystem,
> > > > > in mpage_prepare_extent_to_map, first I printed folio_test_dirty(folio):
> > > > >
> > > > > while (index <= end)
> > > > > ...
> > > > > for (i = 0; i < nr_folios; i++) {
> > > > > ...
> > > > > (print if folio is dirty here)
> > > > >
> > > > > and actually all folios are clean:
> > > > > if (!folio_test_dirty(folio) ||
> > > > > ...
> > > > > folio_unlock(folio);
> > > > > continue; <==== continue here without writing anything
> > > > >
> > > > > Because the call trace happens before going into the above while loop:
> > > > >
> > > > > if (ext4_should_journal_data(mpd->inode)) {
> > > > > handle = ext4_journal_start(mpd->inode, EXT4_HT_WRITE_PAGE,
> > > > >
> > > > > it checks if the file system is read only and dumps the call trace in
> > > > > ext4_journal_check_start, but it doesn't check if there are any real writes
> > > > > that will happen later in the loop.
> > > > >
> > > > > To confirm this, first I added 2 more lines in the reproduce script before
> > > > > remounting read only:
> > > > > sync <==== it calls ext4_sync_fs to flush all dirty data same as what's
> > > > > called during remount read only
> > > > > echo 1 > /proc/sys/vm/drop_caches <==== drop clean page cache
> > > > > mount -o remount,ro ext4disk mnt
> > > > >
> > > > > Then I can no longer reproduce the call trace.
> > > >
> > > > OK, but ext4_do_writepages() has a check at the beginning:
> > > >
> > > > if (!mapping->nrpages || !mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
> > > > goto out_writepages;
> > > >
> > > > So if there are no dirty pages, mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)
> > > > should be false and so we shouldn't go further?
> > > >
> > > > It all looks like some kind of a race because I'm not always able to
> > > > reproduce the problem... I'll try to look more into this.
> > >
> > > OK, the race is with checkpointing code writing the buffers while flush
> > > worker tries to writeback the pages. I've posted a patch which fixes the
> > > issue for me.
> > >
> > > Honza
> > > --
> > > Jan Kara <jack@suse.com>
> > > SUSE Labs, CR
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply
* Re: [PATCH v2 00/10] ext4: refactor partial block zero-out for iomap conversion
From: Zhang Yi @ 2026-03-26 8:53 UTC (permalink / raw)
To: linux-ext4
Cc: linux-fsdevel, linux-kernel, tytso, adilger.kernel, jack, ojaswin,
ritesh.list, libaokun, yi.zhang, yizhang089, yangerkun, yukuai
In-Reply-To: <20260325072850.3997161-1-yi.zhang@huaweicloud.com>
On 3/25/2026 3:28 PM, Zhang Yi wrote:
> From: Zhang Yi <yi.zhang@huawei.com>
Sashiko found some real issues in patch 09 and 10, I will send v3 to fix them.
https://sashiko.dev/#/patchset/20260325072850.3997161-1-yi.zhang%40huaweicloud.com
Best Regards,
Yi.
>
> Changes since v1:
> - In patch 04, rename ext4_block_get_zero_range() to
> ext4_load_tail_bh() and drop the unused 'length' parameter as Jan
> suggested.
> - In patch 06, modify the commit message, add another reason to drop
> data=ordered mode when zeroing partial blocks in ext4_punch_hole()
> and ext4_punch_hole() as Jan pointed out.
> - In patch 10, modify the commit message, explain the race condition
> between the buffered write and mmap write that pointed out by Jan.
> - Collect reviewed tags from Jan.
>
> v1: https://lore.kernel.org/linux-ext4/20260310014101.4140698-1-yi.zhang@huaweicloud.com/
>
> Original cover letter:
>
> This patch series extracted from my iomap conversion v2 series[1]. It
> refactors the ext4 zero partial block code path in preparation for
> converting buffered I/O to the iomap infrastructure. The main changes
> are:
>
> [1] https://lore.kernel.org/linux-ext4/20260203062523.3869120-1-yi.zhang@huawei.com/
>
> 1. Introduce ext4_block_zero_eof(): Extend and rename
> ext4_block_truncate_page() to handle post-EOF partial block zeroing
> for both append writes and truncate operations.
> 2. Separate ordered data handling: Move data=ordered mode handling from
> __ext4_block_zero_page_range to ext4_block_zero_eof(). Only truncate
> and post-EOF append write/fallocate paths need ordered data mode,
> hole punching and zero range paths don't need ordered data handling.
> 3. Split journal mode handling: Extract
> ext4_block_journalled_zero_range() from
> __ext4_block_zero_page_range() for data=journal mode, leaving
> ext4_block_do_zero_range() for data=ordered/writeback modes.
> 4. Refactor ext4_alloc_file_blocks(): Change parameters to loff_t byte
> granularity to simplify callers and prepares removing the zero call
> from the allocation loop for unaligned append writes.
> 5. Remove handle parameters: Stop passing handle_t * to zero functions.
> Make ext4_block_journalled_zero_range() start its own handle, and
> move zero operations outside active handles. This is required because
> iomap uses "folio lock -> transaction start" lock ordering, opposite
> to the current lock ordering.
> 6. Centralize zeroing in ext4_write_checks(): Move all post-EOF partial
> block zeroing to ext4_write_checks() so it applies to both regular
> buffered writes and the upcoming iomap path.
>
> Thanks
> Yi.
>
> Zhang Yi (10):
> ext4: add did_zero output parameter to ext4_block_zero_page_range()
> ext4: ext4_block_truncate_page() returns zeroed length on success
> ext4: rename and extend ext4_block_truncate_page()
> ext4: factor out journalled block zeroing range
> ext4: rename ext4_block_zero_page_range() to ext4_block_zero_range()
> ext4: move ordered data handling out of ext4_block_do_zero_range()
> ext4: remove handle parameters from zero partial block functions
> ext4: pass allocate range as loff_t to ext4_alloc_file_blocks()
> ext4: move zero partial block range functions out of active handle
> ext4: zero post-EOF partial block before appending write
>
> fs/ext4/ext4.h | 5 +-
> fs/ext4/extents.c | 83 +++++++--------
> fs/ext4/file.c | 14 +++
> fs/ext4/inode.c | 255 ++++++++++++++++++++++++++++------------------
> 4 files changed, 207 insertions(+), 150 deletions(-)
>
^ permalink raw reply
* Re: [PATCH v2] crypto: tegra - Add missing CRYPTO_ALG_ASYNC
From: Herbert Xu @ 2026-03-26 9:13 UTC (permalink / raw)
To: Eric Biggers
Cc: linux-crypto, linux-ext4, linux-fscrypt, Thierry Reding,
Jonathan Hunter, Zorro Lang, stable, Akhil R
In-Reply-To: <20260316202119.13934-1-ebiggers@kernel.org>
On Mon, Mar 16, 2026 at 01:21:19PM -0700, Eric Biggers wrote:
> The tegra crypto driver failed to set the CRYPTO_ALG_ASYNC on its
> asynchronous algorithms, causing the crypto API to select them for users
> that request only synchronous algorithms. This causes crashes (at
> least). Fix this by adding the flag like what the other drivers do.
> Also remove the unnecessary CRYPTO_ALG_TYPE_* flags, since those just
> get ignored and overridden by the registration function anyway.
>
> Reported-by: Zorro Lang <zlang@redhat.com>
> Closes: https://lore.kernel.org/r/20260314080937.pghb4aa7d4je3mhh@dell-per750-06-vm-08.rhts.eng.pek2.redhat.com
> Fixes: 0880bb3b00c8 ("crypto: tegra - Add Tegra Security Engine driver")
> Cc: stable@vger.kernel.org
> Cc: Akhil R <akhilrajeev@nvidia.com>
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>
> ---
>
> This patch is targeting crypto/master.
>
> v2: fix tegra-se-hash.c as well, and remove unnecessary type flags
>
> drivers/crypto/tegra/tegra-se-aes.c | 11 ++++++----
> drivers/crypto/tegra/tegra-se-hash.c | 30 ++++++++++++++++------------
> 2 files changed, 24 insertions(+), 17 deletions(-)
Patch applied. Thanks.
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH -v2] ext4: handle wraparound when searching for blocks for indirect mapped blocks
From: Jan Kara @ 2026-03-26 9:44 UTC (permalink / raw)
To: Theodore Ts'o; +Cc: Ext4 Developers List, Jan Kara
In-Reply-To: <20260326045834.1175822-1-tytso@mit.edu>
On Thu 26-03-26 00:58:34, Theodore Ts'o wrote:
> Commit 4865c768b563 ("ext4: always allocate blocks only from groups
> inode can use") restricts what blocks will be allocated for indirect
> block based files to block numbers that fit within 32-bit block
> numbers.
>
> However, when using a review bot running on the latest Gemini LLM to
> check this commit when backporting into an LTS based kernel, it raised
> this concern:
>
> If ac->ac_g_ex.fe_group is >= ngroups (for instance, if the goal
> group was populated via stream allocation from s_mb_last_groups),
> then start will be >= ngroups.
>
> Does this allow allocating blocks beyond the 32-bit limit for
> indirect block mapped files? The commit message mentions that
> ext4_mb_scan_groups_linear() takes care to not select unsupported
> groups. However, its loop uses group = *start, and the very first
> iteration will call ext4_mb_scan_group() with this unsupported
> group because next_linear_group() is only called at the end of the
> iteration.
>
> After reviewing the code paths involved and considering the LLM
> review, I determined that this can happen when there is a file system
> where some files/directories are extent-mapped and others are
> indirect-block mapped. To address this, add a safety clamp in
> ext4_mb_scan_groups().
>
> Fixes: 4865c768b563 ("ext4: always allocate blocks only from groups inode can use")
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Cc: Jan Kara <jack@suse.cz>
Yeah, this looks like all that's needed. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> v2:
> * Remove extra checks that were not needed once we add the clamp
> in ext4_mb_scan_groups().
>
> fs/ext4/mballoc.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
> index 20e9fdaf4301..b10db5d7545b 100644
> --- a/fs/ext4/mballoc.c
> +++ b/fs/ext4/mballoc.c
> @@ -1199,6 +1199,8 @@ static int ext4_mb_scan_groups(struct ext4_allocation_context *ac)
>
> /* searching for the right group start from the goal value specified */
> start = ac->ac_g_ex.fe_group;
> + if (start >= ngroups)
> + start = 0;
> ac->ac_prefetch_grp = start;
> ac->ac_prefetch_nr = 0;
>
> --
> 2.51.0
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply
* [PATCH 02/42] gfs2: Don't zero i_private_data
From: Jan Kara @ 2026-03-26 9:53 UTC (permalink / raw)
To: linux-fsdevel
Cc: linux-block, Christian Brauner, Al Viro, linux-ext4, Ted Tso,
Tigran A. Aivazian, David Sterba, OGAWA Hirofumi, Muchun Song,
Oscar Salvador, David Hildenbrand, linux-mm, linux-aio,
Benjamin LaHaise, Jan Kara, Andreas Gruenbacher, gfs2
In-Reply-To: <20260326082428.31660-1-jack@suse.cz>
Remove the explicit zeroing of mapping->i_private_data since this
field is no longer used.
CC: Andreas Gruenbacher <agruenba@redhat.com>
CC: gfs2@lists.linux.dev
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Jan Kara <jack@suse.cz>
---
fs/gfs2/glock.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 2acbabccc8ad..b8a144d3a73b 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -1149,7 +1149,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
mapping->flags = 0;
gfp_mask = mapping_gfp_mask(sdp->sd_inode->i_mapping);
mapping_set_gfp_mask(mapping, gfp_mask);
- mapping->i_private_data = NULL;
mapping->writeback_index = 0;
}
--
2.51.0
^ permalink raw reply related
* [PATCH 01/42] ext4: Use inode_has_buffers()
From: Jan Kara @ 2026-03-26 9:53 UTC (permalink / raw)
To: linux-fsdevel
Cc: linux-block, Christian Brauner, Al Viro, linux-ext4, Ted Tso,
Tigran A. Aivazian, David Sterba, OGAWA Hirofumi, Muchun Song,
Oscar Salvador, David Hildenbrand, linux-mm, linux-aio,
Benjamin LaHaise, Jan Kara
In-Reply-To: <20260326082428.31660-1-jack@suse.cz>
Instead of checking i_private_list directly use appropriate wrapper
inode_has_buffers(). Also delete stale comment.
Acked-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Jan Kara <jack@suse.cz>
---
fs/buffer.c | 1 +
fs/ext4/inode.c | 5 +----
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index 22b43642ba57..1bc0f22f3cc2 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -524,6 +524,7 @@ int inode_has_buffers(struct inode *inode)
{
return !list_empty(&inode->i_data.i_private_list);
}
+EXPORT_SYMBOL_GPL(inode_has_buffers);
/*
* osync is designed to support O_SYNC io. It waits synchronously for
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 396dc3a5d16b..d18d94acddcc 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1420,9 +1420,6 @@ static int write_end_fn(handle_t *handle, struct inode *inode,
/*
* We need to pick up the new inode size which generic_commit_write gave us
* `iocb` can be NULL - eg, when called from page_symlink().
- *
- * ext4 never places buffers on inode->i_mapping->i_private_list. metadata
- * buffers are managed internally.
*/
static int ext4_write_end(const struct kiocb *iocb,
struct address_space *mapping,
@@ -3437,7 +3434,7 @@ static bool ext4_inode_datasync_dirty(struct inode *inode)
}
/* Any metadata buffers to write? */
- if (!list_empty(&inode->i_mapping->i_private_list))
+ if (inode_has_buffers(inode))
return true;
return inode_state_read_once(inode) & I_DIRTY_DATASYNC;
}
--
2.51.0
^ permalink raw reply related
* [PATCH 04/42] ocfs2: Drop pointless sync_mapping_buffers() calls
From: Jan Kara @ 2026-03-26 9:53 UTC (permalink / raw)
To: linux-fsdevel
Cc: linux-block, Christian Brauner, Al Viro, linux-ext4, Ted Tso,
Tigran A. Aivazian, David Sterba, OGAWA Hirofumi, Muchun Song,
Oscar Salvador, David Hildenbrand, linux-mm, linux-aio,
Benjamin LaHaise, Jan Kara, Joel Becker, Joseph Qi, ocfs2-devel
In-Reply-To: <20260326082428.31660-1-jack@suse.cz>
ocfs2 never calls mark_buffer_dirty_inode() and thus its metadata
buffers list is always empty. Drop the pointless sync_mapping_buffers()
calls.
CC: Joel Becker <jlbec@evilplan.org>
CC: Joseph Qi <joseph.qi@linux.alibaba.com>
CC: ocfs2-devel@lists.linux.dev
Signed-off-by: Jan Kara <jack@suse.cz>
---
fs/ocfs2/dlmglue.c | 1 -
fs/ocfs2/namei.c | 3 ---
2 files changed, 4 deletions(-)
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index bd2ddb7d841d..7283bb2c5a31 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -3971,7 +3971,6 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
mlog(ML_ERROR, "Could not sync inode %llu for downconvert!",
(unsigned long long)OCFS2_I(inode)->ip_blkno);
}
- sync_mapping_buffers(mapping);
if (blocking == DLM_LOCK_EX) {
truncate_inode_pages(mapping, 0);
} else {
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 268b79339a51..1277666c77cd 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -1683,9 +1683,6 @@ static int ocfs2_rename(struct mnt_idmap *idmap,
if (rename_lock)
ocfs2_rename_unlock(osb);
- if (new_inode)
- sync_mapping_buffers(old_inode->i_mapping);
-
iput(new_inode);
ocfs2_free_dir_lookup_result(&target_lookup_res);
--
2.51.0
^ permalink raw reply related
* [PATCH v3 0/42] fs: Move metadata bh tracking from address_space
From: Jan Kara @ 2026-03-26 9:53 UTC (permalink / raw)
To: linux-fsdevel
Cc: linux-block, Christian Brauner, Al Viro, linux-ext4, Ted Tso,
Tigran A. Aivazian, David Sterba, OGAWA Hirofumi, Muchun Song,
Oscar Salvador, David Hildenbrand, linux-mm, linux-aio,
Benjamin LaHaise, Jan Kara
Hello,
here is a next revision of the patchset cleaning up buffer head metadata
tracking and use of address_space's private_list and private_lock. Functionally
this should be identical to v2, most of the changes were in improving
changelogs, patch ordering, function names, etc. The patches have survived some
testing with fstests and ltp however I didn't test AFFS and KVM guest_memfd
changes so a help with testing those would be very welcome. Thanks.
Changes since v2:
* Added Reviewed-by tags from Christoph
* Dropped the patch unifying fsync implementation in fs/libfs.c and fs/buffer.c
* Put fsync locking change into a separate commit
* Reordered series to place all fsync path modifications close together
* Improved some changelogs
* Renamed some functions based on Christoph's feedback
Changes since v1:
* Fixed hugetlbfs handling of root directory
* Reworked mapping_metadata_bhs handling functions to get the tracking
structure as an argument so we now don't need iops method to fetch the struct
from the inode
* Reordered patches into more sensible order
* Added patch to merge two mostly duplicate generic fsync implementations
* Added Reviewed-by tags
* Couple more minor changes that were requested during review
Original cover letter:
this patch series cleans up the mess that has accumulated over the years in
metadata buffer_head tracking for inodes, moves the tracking into dedicated
structure in filesystem-private part of the inode (so that we don't use
private_list, private_data, and private_lock in struct address_space), and also
moves couple other users of private_data and private_list so these are removed
from struct address_space saving 3 longs in struct inode for 99% of inodes. I
would like to get rid of private_lock in struct address_space as well however
the locking changes for buffer_heads are non-trivial there and the patch series
is long enough as is. So let's leave that for another time.
block/bdev.c | 1
fs/affs/affs.h | 2
fs/affs/dir.c | 1
fs/affs/file.c | 1
fs/affs/inode.c | 2
fs/affs/super.c | 6
fs/affs/symlink.c | 1
fs/aio.c | 78 +++++++-
fs/bfs/bfs.h | 2
fs/bfs/dir.c | 1
fs/bfs/file.c | 4
fs/bfs/inode.c | 9 +
fs/buffer.c | 387 +++++++++++++++++---------------------------
fs/ext2/ext2.h | 2
fs/ext2/file.c | 1
fs/ext2/inode.c | 3
fs/ext2/namei.c | 2
fs/ext2/super.c | 6
fs/ext2/symlink.c | 2
fs/ext4/ext4.h | 4
fs/ext4/file.c | 1
fs/ext4/inode.c | 9 -
fs/ext4/namei.c | 2
fs/ext4/super.c | 9 -
fs/ext4/symlink.c | 3
fs/fat/fat.h | 2
fs/fat/file.c | 1
fs/fat/inode.c | 16 +
fs/fat/namei_msdos.c | 1
fs/fat/namei_vfat.c | 1
fs/gfs2/glock.c | 1
fs/hugetlbfs/inode.c | 10 -
fs/inode.c | 24 +-
fs/minix/file.c | 1
fs/minix/inode.c | 10 +
fs/minix/minix.h | 2
fs/minix/namei.c | 1
fs/ntfs3/file.c | 3
fs/ocfs2/dlmglue.c | 1
fs/ocfs2/namei.c | 3
fs/udf/file.c | 1
fs/udf/inode.c | 2
fs/udf/namei.c | 1
fs/udf/super.c | 6
fs/udf/symlink.c | 1
fs/udf/udf_i.h | 1
fs/udf/udfdecl.h | 1
include/linux/buffer_head.h | 6
include/linux/fs.h | 11 -
include/linux/hugetlb.h | 1
mm/hugetlb.c | 10 -
virt/kvm/guest_memfd.c | 12 -
52 files changed, 360 insertions(+), 309 deletions(-)
Honza
Previous versions:
Link: http://lore.kernel.org/r/20260303101717.27224-1-jack@suse.cz # v1
Link: http://lore.kernel.org/r/20260320131728.6449-1-jack@suse.cz # v2
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox