linux-xfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Darrick J. Wong" <djwong@kernel.org>
To: Dave Chinner <david@fromorbit.com>
Cc: linux-xfs@vger.kernel.org
Subject: Re: [PATCH 2/4] xfs: inode fork allocation depends on XFS_IFEXTENT flag
Date: Tue, 30 Mar 2021 11:06:17 -0700	[thread overview]
Message-ID: <20210330180617.GR4090233@magnolia> (raw)
In-Reply-To: <20210330053059.1339949-3-david@fromorbit.com>

On Tue, Mar 30, 2021 at 04:30:57PM +1100, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> 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.

I don't agree that IFEXTENTS has two meanings.  This is what I
understand of how xfs_ifork fields and surrounding code are supposed to
work; can you point out what's wrong?

 1. xfs_ifork.if_format == XFS_DINODE_FMT_EXTENTS tells us if the fork
    is in extent format.

 2. (xfs_ifork.if_flags & XFS_IFEXTENTS) tells us if the incore extent
    map is initialized.

 3. If we are creating a fork with if_format == EXTENTS, the incore map
    is trivially initialized, and therefore IFEXTENTS should be set
    because no further work is required.

 4. If we are reading an if_format == EXTENTS fork in from disk (during
    xfs_iread), we always populate the incore map and set IFEXTENTS.

 5. If if_format == BTREE and IFEXTENTS is not set, the incore map is
    *not* initialized, and we must call xfs_iread_extents to walk the
    ondisk btree to initialize the incore btree, and to set IFEXTENTS.

 6. xfs_iread_extents requires that if_format == BTREE and will return
    an error and log a corruption report if it sees another fork format.

From points 3 and 4, I conclude that (prior to xfs-5.13-merge) IFEXTENTS
is always set if if_format is FMT_EXTENTS.

From point 6, I conclude that it's not possible for IFEXTENTS not to be
set if if_format is FMT_EXTENTS, because if an inode fork ever ended up
in that state, there would not be any way to escape.

> 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.

Agreed, that's #4 above.

> Hence we set the flag to mean both "in extent format and in memory".

I don't agree.  I think #1 tells us "in extent format" and #2 tells us
"in memory"; and #3 and #4 are how we guarantee that.

> 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.

<shrug> IMHO we initialized it trivially, but that's splitting hairs and
doesn't warrant further argument, so I'll move on.

> 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.

Let's look at the relevant code in xchk_bmap(), since I wrote that
function:

	/* Check the fork values */
	switch (ifp->if_format) {
	...
	case XFS_DINODE_FMT_EXTENTS:
		if (!(ifp->if_flags & XFS_IFEXTENTS)) {
			xchk_fblock_set_corrupt(sc, whichfork, 0);
			goto out;
		}
		break;

The switch statement checks the format (#1), and the flag test checks
that the incore state (#3 and #4) hold true.  Perhaps it was unwise of
scrub to check *incore* state flags here, but as of the time the code
was written, it was always the case that FMT_EXTENTS and IFEXTENTS went
together.  Setting SCRUB_OFLAG_CORRUPT is how scrub signals that
something is wrong and administrator intervention is needed.

I agree with the code fix, but not with the justification.

--D

> Fixes: e6a688c33238 ("xfs: initialise attr fork on inode create")
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  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
> 

  reply	other threads:[~2021-03-30 18:07 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-30  5:30 [PATCH 0/4] xfs: fix eager attr fork init regressions Dave Chinner
2021-03-30  5:30 ` [PATCH 1/4] xfs: eager inode attr fork init needs attr feature awareness Dave Chinner
2021-03-30 18:10   ` Darrick J. Wong
2021-04-02  6:48   ` Christoph Hellwig
2021-03-30  5:30 ` [PATCH 2/4] xfs: inode fork allocation depends on XFS_IFEXTENT flag Dave Chinner
2021-03-30 18:06   ` Darrick J. Wong [this message]
2021-03-30 21:40     ` Dave Chinner
2021-04-02  7:02       ` Christoph Hellwig
2021-04-03 22:21         ` Dave Chinner
2021-04-04  3:25       ` Darrick J. Wong
2021-04-02  7:06   ` Christoph Hellwig
2021-03-30  5:30 ` [PATCH 3/4] xfs: default attr fork size does not handle device inodes Dave Chinner
2021-03-30 18:10   ` Darrick J. Wong
2021-04-02  7:08   ` Christoph Hellwig
2021-03-30  5:30 ` [PATCH 4/4] xfs: precalculate default inode attribute offset Dave Chinner
2021-03-30 18:10   ` Darrick J. Wong
2021-04-02  7:10   ` Christoph Hellwig
2021-04-03 22:16     ` Dave Chinner
2021-04-06 11:59 [PATCH 0/4 v2] xfs: fix eager attr fork init regressions Dave Chinner
2021-04-06 11:59 ` [PATCH 2/4] xfs: inode fork allocation depends on XFS_IFEXTENT flag Dave Chinner
2021-04-06 13:10   ` Christoph Hellwig
2021-04-06 20:07   ` Allison Henderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210330180617.GR4090233@magnolia \
    --to=djwong@kernel.org \
    --cc=david@fromorbit.com \
    --cc=linux-xfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).