From: Heming Zhao <heming.zhao@suse.com>
To: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Andrew Morton <akpm@linux-foundation.org>,
Mark Fasheh <mark@fasheh.com>, Joel Becker <jlbec@evilplan.org>,
ocfs2-devel@lists.linux.dev, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] ocfs2: validate the xattr tree root of an indexed xattr block
Date: Wed, 14 Oct 2026 22:35:29 +0800 [thread overview]
Message-ID: <as-SUraepqsded7n@p15> (raw)
In-Reply-To: <20261014105856.2909777-1-joseph.qi@linux.alibaba.com>
On Wed, Oct 14, 2026 at 06:58:56PM +0800, Joseph Qi wrote:
> ocfs2_validate_xattr_block() checks an xattr block's signature, blkno,
> generation and suballocator fields, and for a non-indexed block the entry
> array it carries. An indexed block is passed straight through, so the
> extent list in its xattr tree root is never looked at.
>
> Both fields that describe the list are bounded. The two places that
> create a root set l_count from ocfs2_xattr_recs_per_xb() and nothing
> rewrites it, and the insert path asserts in ocfs2_rotate_leaf() that
> l_next_free_rec stays within l_count. Check both when the block is
> first read, so a root that disagrees with the block size, or claims more
> records than it has room for, is caught before anything indexes into
> l_recs[].
>
> An empty root is deliberately not rejected. Emptying the tree leaves it
> that way: ocfs2_rm_xattr_cluster() removes one extent per transaction,
> and the last one ends in ocfs2_truncate_rec(), whose closing
> ocfs2_rotate_tree_left() reaches ocfs2_remove_empty_extent() on the
> depth-zero root and takes l_next_free_rec to zero. That transaction
> commits before ocfs2_xattr_free_block() frees the block, and before
> ocfs2_xattr_remove() clears i_xattr_loc, in two later transactions, so a
> crash in between leaves an orphan inode pointing at an xattr block whose
> root has no extents. Both readers already cope with it:
> __ocfs2_xattr_index_block_find() answers -ENODATA, and
> ocfs2_iterate_xattr_index_block() returns without iterating.
>
> Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
LGTM.
Reviewed-by: Heming Zhao <heming.zhao@suse.com>
> ---
> fs/ocfs2/xattr.c | 25 +++++++++++++++++++++++++
> 1 file changed, 25 insertions(+)
>
> diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
> index 18d920b30602..b2bd06083a14 100644
> --- a/fs/ocfs2/xattr.c
> +++ b/fs/ocfs2/xattr.c
> @@ -491,6 +491,7 @@ static int ocfs2_validate_xattr_block(struct super_block *sb,
> struct buffer_head *bh)
> {
> int rc;
> + struct ocfs2_extent_list *el;
> struct ocfs2_xattr_block *xb =
> (struct ocfs2_xattr_block *)bh->b_data;
>
> @@ -573,6 +574,30 @@ static int ocfs2_validate_xattr_block(struct super_block *sb,
> region_offset);
> }
>
> + /*
> + * An indexed xattr block carries the root of the xattr tree. Its
> + * record count is fixed by the block size and l_next_free_rec never
> + * exceeds it. A zero l_next_free_rec is valid: emptying the tree on
> + * the inode deletion path leaves the root with no extents.
> + */
> + el = &xb->xb_attrs.xb_root.xt_list;
> +
> + if (le16_to_cpu(el->l_count) != ocfs2_xattr_recs_per_xb(sb)) {
> + return ocfs2_error(sb,
> + "Xattr tree root #%llu has invalid l_count %u (expected %u)\n",
> + (unsigned long long)bh->b_blocknr,
> + le16_to_cpu(el->l_count),
> + ocfs2_xattr_recs_per_xb(sb));
> + }
> +
> + if (le16_to_cpu(el->l_next_free_rec) > le16_to_cpu(el->l_count)) {
> + return ocfs2_error(sb,
> + "Xattr tree root #%llu has l_next_free_rec %u past the end of its list (l_count %u)\n",
> + (unsigned long long)bh->b_blocknr,
> + le16_to_cpu(el->l_next_free_rec),
> + le16_to_cpu(el->l_count));
> + }
> +
> return 0;
> }
>
> --
> 2.39.3
>
prev parent reply other threads:[~2026-10-14 14:35 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-14 10:58 Joseph Qi
2026-10-14 14:35 ` Heming Zhao [this message]
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=as-SUraepqsded7n@p15 \
--to=heming.zhao@suse.com \
--cc=akpm@linux-foundation.org \
--cc=jlbec@evilplan.org \
--cc=joseph.qi@linux.alibaba.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mark@fasheh.com \
--cc=ocfs2-devel@lists.linux.dev \
/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
all inboxes | Powered by JetHome®