From: Dave Chinner <dchinner@xxxxxxxxxx> XFS_IFEXTENT has two incompatible meanings to the code. The first meaning is that the fork is in extent format, the second meaning is that the extent list has been read into memory. When the inode fork is in extent format, we automatically read the extent list into memory and indexed by the inode extent btree when the inode is brought into memory off disk. Hence we set the flag to mean both "in extent format and in memory". That requires all new fork allocations where the default state is "extent format with zero extents" to set the XFS_IFEXTENT to indicate we've initialised the in-memory state even though we've really done no such thing. This fixes a scrub regression because it assumes XFS_IFEXTENT means "on disk format" and not "read into memory" and e6a688c33238 assumed it mean "read into memory". In reality, the XFS_IFEXTENT flag needs to be split up into two flags - one for the on disk fork format and one for the in-memory "extent btree has been populated" state. Fixes: e6a688c33238 ("xfs: initialise attr fork on inode create") Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx> --- fs/xfs/libxfs/xfs_bmap.c | 1 - fs/xfs/libxfs/xfs_inode_fork.c | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 5574d345d066..2f72849c05f9 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -1095,7 +1095,6 @@ xfs_bmap_add_attrfork( ASSERT(ip->i_afp == NULL); ip->i_afp = xfs_ifork_alloc(XFS_DINODE_FMT_EXTENTS, 0); - ip->i_afp->if_flags = XFS_IFEXTENTS; logflags = 0; switch (ip->i_df.if_format) { case XFS_DINODE_FMT_LOCAL: diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c index 1851d6f266d0..03e1a21848eb 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.c +++ b/fs/xfs/libxfs/xfs_inode_fork.c @@ -292,6 +292,15 @@ xfs_ifork_alloc( ifp = kmem_cache_zalloc(xfs_ifork_zone, GFP_NOFS | __GFP_NOFAIL); ifp->if_format = format; ifp->if_nextents = nextents; + + /* + * If this is a caller initialising a newly created fork, we need to + * set XFS_IFEXTENTS to indicate the fork state is completely up to + * date. Otherwise it is up to the caller to initialise the in-memory + * state of the inode fork from the on-disk state. + */ + if (format == XFS_DINODE_FMT_EXTENTS && nextents == 0) + ifp->if_flags |= XFS_IFEXTENTS; return ifp; } -- 2.31.0