mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] ocfs2: validate extent list in filecheck repair
@ 2026-09-26 13:18 Jiale Yao
  2026-09-28  1:33 ` Joseph Qi
  0 siblings, 1 reply; 7+ messages in thread
From: Jiale Yao @ 2026-09-26 13:18 UTC (permalink / raw)
  To: Mark Fasheh, Joel Becker, Joseph Qi, Gang He, Andrew Morton,
	ocfs2-devel, linux-kernel
  Cc: Jiale Yao

ocfs2_filecheck_validate_inode_block() does not validate the embedded
extent list, while ocfs2_filecheck_repair_inode_block() only clamps
l_next_free_rec to l_count.  The normal inode read path requires l_count
to be non-zero, limits it to the number of extent records that fit in the
inode, and requires l_next_free_rec not to exceed l_count.

Without the same checks, filecheck can report SUCCESS while leaving an
invalid extent list on disk.  A later read through the normal inode
validation path rejects the inode and makes the filesystem read-only.

Add a shared helper for the filecheck paths to check these invariants.
The filecheck validator now rejects all three cases.  The repair path
still clamps l_next_free_rec, but refuses to repair zero or oversized
l_count values.

Fixes: d56a8f32e4c6 ("ocfs2: check/fix inode block for online file check")
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
 fs/ocfs2/inode.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 180107a11046..57168ed02915 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -249,6 +249,41 @@ static int ocfs2_dinode_has_extents(struct ocfs2_dinode *di)
 	return 1;
 }
 
+enum ocfs2_extent_list_status {
+	OCFS2_EXTENT_LIST_OK,
+	OCFS2_EXTENT_LIST_ZERO_COUNT,
+	OCFS2_EXTENT_LIST_OVERSIZED,
+	OCFS2_EXTENT_LIST_BAD_NEXT_FREE,
+};
+
+static enum ocfs2_extent_list_status
+ocfs2_check_extent_list(struct super_block *sb, struct ocfs2_dinode *di)
+{
+	struct ocfs2_extent_list *el = &di->id2.i_list;
+	u16 count;
+	u16 next_free;
+
+	if (!ocfs2_dinode_has_extents(di))
+		return OCFS2_EXTENT_LIST_OK;
+
+	count = le16_to_cpu(el->l_count);
+	next_free = le16_to_cpu(el->l_next_free_rec);
+	if (count == 0)
+		return OCFS2_EXTENT_LIST_ZERO_COUNT;
+	/*
+	 * The exact capacity depends on i_xattr_inline_size, another
+	 * unvalidated on-disk field. Inline xattrs only shrink the
+	 * list, so the no-xattr maximum is a safe upper bound that a
+	 * valid l_count never exceeds.
+	 */
+	if (count > ocfs2_extent_recs_per_inode(sb))
+		return OCFS2_EXTENT_LIST_OVERSIZED;
+	if (next_free > count)
+		return OCFS2_EXTENT_LIST_BAD_NEXT_FREE;
+
+	return OCFS2_EXTENT_LIST_OK;
+}
+
 /*
  * here's how inodes get read from disk:
  * iget5_locked -> find_actor -> OCFS2_FIND_ACTOR
@@ -1835,6 +1870,33 @@ static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
 		goto bail;
 	}
 
+	switch (ocfs2_check_extent_list(sb, di)) {
+	case OCFS2_EXTENT_LIST_OK:
+		break;
+	case OCFS2_EXTENT_LIST_ZERO_COUNT:
+		mlog(ML_ERROR,
+		     "Filecheck: invalid dinode #%llu: extent list l_count is zero\n",
+		     (unsigned long long)bh->b_blocknr);
+		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
+		goto bail;
+	case OCFS2_EXTENT_LIST_OVERSIZED:
+		mlog(ML_ERROR,
+		     "Filecheck: invalid dinode #%llu: extent list l_count %u exceeds max %u\n",
+		     (unsigned long long)bh->b_blocknr,
+		     le16_to_cpu(di->id2.i_list.l_count),
+		     ocfs2_extent_recs_per_inode(sb));
+		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
+		goto bail;
+	case OCFS2_EXTENT_LIST_BAD_NEXT_FREE:
+		mlog(ML_ERROR,
+		     "Filecheck: invalid dinode #%llu: extent list l_next_free_rec %u exceeds l_count %u\n",
+		     (unsigned long long)bh->b_blocknr,
+		     le16_to_cpu(di->id2.i_list.l_next_free_rec),
+		     le16_to_cpu(di->id2.i_list.l_count));
+		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
+		goto bail;
+	}
+
 	if (ocfs2_dinode_has_size_without_clusters(sb, di)) {
 		if (S_ISDIR(le16_to_cpu(di->i_mode)))
 			mlog(ML_ERROR,
@@ -1893,6 +1955,15 @@ static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
 		return -OCFS2_FILECHECK_ERR_VALIDFLAG;
 	}
 
+	switch (ocfs2_check_extent_list(sb, di)) {
+	case OCFS2_EXTENT_LIST_OK:
+	case OCFS2_EXTENT_LIST_BAD_NEXT_FREE:
+		break;
+	case OCFS2_EXTENT_LIST_ZERO_COUNT:
+	case OCFS2_EXTENT_LIST_OVERSIZED:
+		return -OCFS2_FILECHECK_ERR_INVALIDINO;
+	}
+
 	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
 		di->i_blkno = cpu_to_le64(bh->b_blocknr);
 		changed = 1;
-- 
2.34.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] ocfs2: validate extent list in filecheck repair
  2026-09-26 13:18 [PATCH] ocfs2: validate extent list in filecheck repair Jiale Yao
@ 2026-09-28  1:33 ` Joseph Qi
  2026-09-28  5:18   ` Heming Zhao
  2026-09-28  7:39   ` Heming Zhao
  0 siblings, 2 replies; 7+ messages in thread
From: Joseph Qi @ 2026-09-28  1:33 UTC (permalink / raw)
  To: Jiale Yao
  Cc: Andrew Morton, Mark Fasheh, Joel Becker, Gang He, Heming Zhao,
	ocfs2-devel, linux-kernel



On 9/26/26 9:18 PM, Jiale Yao wrote:
> ocfs2_filecheck_validate_inode_block() does not validate the embedded
> extent list, while ocfs2_filecheck_repair_inode_block() only clamps
> l_next_free_rec to l_count.  The normal inode read path requires l_count
> to be non-zero, limits it to the number of extent records that fit in the
> inode, and requires l_next_free_rec not to exceed l_count.
> 
> Without the same checks, filecheck can report SUCCESS while leaving an
> invalid extent list on disk.  A later read through the normal inode
> validation path rejects the inode and makes the filesystem read-only.
> 
> Add a shared helper for the filecheck paths to check these invariants.
> The filecheck validator now rejects all three cases.  The repair path
> still clamps l_next_free_rec, but refuses to repair zero or oversized
> l_count values.
> 
> Fixes: d56a8f32e4c6 ("ocfs2: check/fix inode block for online file check")

I'd like make this as a new ability rather than a bug fix.

> Signed-off-by: Jiale Yao <yaojiale02@163.com>
> ---
>  fs/ocfs2/inode.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 71 insertions(+)
> 
> diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
> index 180107a11046..57168ed02915 100644
> --- a/fs/ocfs2/inode.c
> +++ b/fs/ocfs2/inode.c
> @@ -249,6 +249,41 @@ static int ocfs2_dinode_has_extents(struct ocfs2_dinode *di)
>  	return 1;
>  }
>  
> +enum ocfs2_extent_list_status {
> +	OCFS2_EXTENT_LIST_OK,
> +	OCFS2_EXTENT_LIST_ZERO_COUNT,
> +	OCFS2_EXTENT_LIST_OVERSIZED,
> +	OCFS2_EXTENT_LIST_BAD_NEXT_FREE,
> +};
> +
> +static enum ocfs2_extent_list_status
> +ocfs2_check_extent_list(struct super_block *sb, struct ocfs2_dinode *di)
> +{
> +	struct ocfs2_extent_list *el = &di->id2.i_list;
> +	u16 count;
> +	u16 next_free;
> +
> +	if (!ocfs2_dinode_has_extents(di))
> +		return OCFS2_EXTENT_LIST_OK;
> +
> +	count = le16_to_cpu(el->l_count);
> +	next_free = le16_to_cpu(el->l_next_free_rec);
> +	if (count == 0)
> +		return OCFS2_EXTENT_LIST_ZERO_COUNT;
> +	/*
> +	 * The exact capacity depends on i_xattr_inline_size, another
> +	 * unvalidated on-disk field. Inline xattrs only shrink the
> +	 * list, so the no-xattr maximum is a safe upper bound that a
> +	 * valid l_count never exceeds.
> +	 */
> +	if (count > ocfs2_extent_recs_per_inode(sb))
> +		return OCFS2_EXTENT_LIST_OVERSIZED;
> +	if (next_free > count)
> +		return OCFS2_EXTENT_LIST_BAD_NEXT_FREE;
> +
> +	return OCFS2_EXTENT_LIST_OK;
> +}

This seems a duplicated check in ocfs2_validate_inode_block().
So I sugguest just extract the helper from it instead of duplicating
a new one.

BTW, seems we don't have to introduce enum ocfs2_extent_list_status,
to make the checks simple.

Thanks,
Joseph

> +
>  /*
>   * here's how inodes get read from disk:
>   * iget5_locked -> find_actor -> OCFS2_FIND_ACTOR
> @@ -1835,6 +1870,33 @@ static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
>  		goto bail;
>  	}
>  
> +	switch (ocfs2_check_extent_list(sb, di)) {
> +	case OCFS2_EXTENT_LIST_OK:
> +		break;
> +	case OCFS2_EXTENT_LIST_ZERO_COUNT:
> +		mlog(ML_ERROR,
> +		     "Filecheck: invalid dinode #%llu: extent list l_count is zero\n",
> +		     (unsigned long long)bh->b_blocknr);
> +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> +		goto bail;
> +	case OCFS2_EXTENT_LIST_OVERSIZED:
> +		mlog(ML_ERROR,
> +		     "Filecheck: invalid dinode #%llu: extent list l_count %u exceeds max %u\n",
> +		     (unsigned long long)bh->b_blocknr,
> +		     le16_to_cpu(di->id2.i_list.l_count),
> +		     ocfs2_extent_recs_per_inode(sb));
> +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> +		goto bail;
> +	case OCFS2_EXTENT_LIST_BAD_NEXT_FREE:
> +		mlog(ML_ERROR,
> +		     "Filecheck: invalid dinode #%llu: extent list l_next_free_rec %u exceeds l_count %u\n",
> +		     (unsigned long long)bh->b_blocknr,
> +		     le16_to_cpu(di->id2.i_list.l_next_free_rec),
> +		     le16_to_cpu(di->id2.i_list.l_count));
> +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> +		goto bail;
> +	}
> +
>  	if (ocfs2_dinode_has_size_without_clusters(sb, di)) {
>  		if (S_ISDIR(le16_to_cpu(di->i_mode)))
>  			mlog(ML_ERROR,
> @@ -1893,6 +1955,15 @@ static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
>  		return -OCFS2_FILECHECK_ERR_VALIDFLAG;
>  	}
>  
> +	switch (ocfs2_check_extent_list(sb, di)) {
> +	case OCFS2_EXTENT_LIST_OK:
> +	case OCFS2_EXTENT_LIST_BAD_NEXT_FREE:
> +		break;
> +	case OCFS2_EXTENT_LIST_ZERO_COUNT:
> +	case OCFS2_EXTENT_LIST_OVERSIZED:
> +		return -OCFS2_FILECHECK_ERR_INVALIDINO;
> +	}
> +
>  	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
>  		di->i_blkno = cpu_to_le64(bh->b_blocknr);
>  		changed = 1;


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] ocfs2: validate extent list in filecheck repair
  2026-09-28  1:33 ` Joseph Qi
@ 2026-09-28  5:18   ` Heming Zhao
  2026-09-28  9:56     ` Joseph Qi
  2026-09-28  7:39   ` Heming Zhao
  1 sibling, 1 reply; 7+ messages in thread
From: Heming Zhao @ 2026-09-28  5:18 UTC (permalink / raw)
  To: Joseph Qi, yaojiale02
  Cc: Andrew Morton, Mark Fasheh, Joel Becker, ocfs2-devel, linux-kernel

On Mon, Sep 28, 2026 at 09:33:12AM +0800, Joseph Qi wrote:
> 
> 
> On 9/26/26 9:18 PM, Jiale Yao wrote:
> > ocfs2_filecheck_validate_inode_block() does not validate the embedded
> > extent list, while ocfs2_filecheck_repair_inode_block() only clamps
> > l_next_free_rec to l_count.  The normal inode read path requires l_count
> > to be non-zero, limits it to the number of extent records that fit in the
> > inode, and requires l_next_free_rec not to exceed l_count.
> > 
> > Without the same checks, filecheck can report SUCCESS while leaving an
> > invalid extent list on disk.  A later read through the normal inode
> > validation path rejects the inode and makes the filesystem read-only.
> > 
> > Add a shared helper for the filecheck paths to check these invariants.
> > The filecheck validator now rejects all three cases.  The repair path
> > still clamps l_next_free_rec, but refuses to repair zero or oversized
> > l_count values.
> > 
> > Fixes: d56a8f32e4c6 ("ocfs2: check/fix inode block for online file check")
> 
> I'd like make this as a new ability rather than a bug fix.
> 
> > Signed-off-by: Jiale Yao <yaojiale02@163.com>
> > ---
> >  fs/ocfs2/inode.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 71 insertions(+)
> > 
> > diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
> > index 180107a11046..57168ed02915 100644
> > --- a/fs/ocfs2/inode.c
> > +++ b/fs/ocfs2/inode.c
> > @@ -249,6 +249,41 @@ static int ocfs2_dinode_has_extents(struct ocfs2_dinode *di)
> >  	return 1;
> >  }
> >  
> > +enum ocfs2_extent_list_status {
> > +	OCFS2_EXTENT_LIST_OK,
> > +	OCFS2_EXTENT_LIST_ZERO_COUNT,
> > +	OCFS2_EXTENT_LIST_OVERSIZED,
> > +	OCFS2_EXTENT_LIST_BAD_NEXT_FREE,
> > +};
> > +
> > +static enum ocfs2_extent_list_status
> > +ocfs2_check_extent_list(struct super_block *sb, struct ocfs2_dinode *di)
> > +{
> > +	struct ocfs2_extent_list *el = &di->id2.i_list;
> > +	u16 count;
> > +	u16 next_free;
> > +
> > +	if (!ocfs2_dinode_has_extents(di))
> > +		return OCFS2_EXTENT_LIST_OK;
> > +
> > +	count = le16_to_cpu(el->l_count);
> > +	next_free = le16_to_cpu(el->l_next_free_rec);
> > +	if (count == 0)
> > +		return OCFS2_EXTENT_LIST_ZERO_COUNT;
> > +	/*
> > +	 * The exact capacity depends on i_xattr_inline_size, another
> > +	 * unvalidated on-disk field. Inline xattrs only shrink the
> > +	 * list, so the no-xattr maximum is a safe upper bound that a
> > +	 * valid l_count never exceeds.
> > +	 */
> > +	if (count > ocfs2_extent_recs_per_inode(sb))
> > +		return OCFS2_EXTENT_LIST_OVERSIZED;
> > +	if (next_free > count)
> > +		return OCFS2_EXTENT_LIST_BAD_NEXT_FREE;
> > +
> > +	return OCFS2_EXTENT_LIST_OK;
> > +}
> 
> This seems a duplicated check in ocfs2_validate_inode_block().
> So I sugguest just extract the helper from it instead of duplicating
> a new one.
> 
> BTW, seems we don't have to introduce enum ocfs2_extent_list_status,
> to make the checks simple.
> 
> Thanks,
> Joseph

Hi Joseph,

The code logic is identical for ocfs2_validate_inode_block() and
ocfs2_filecheck_validate_inode_block(), except for their error handling style.
It seems possible to merge them into ocfs2_validate_inode_block() by adding
a bool check parameter to distinguish between the two behaviors, and then remove
ocfs2_filecheck_validate_inode_block().

The new code logic: replace ocfs2_error() with mlog(), and then "goto bail".
At the bail label, handle the two cases separately using "if (check)".

i.e.:
//adding a new parameter "check"
int ocfs2_validate_inode_block(struct super_block *sb,
			       struct buffer_head *bh, bool check)


code change from:
```
	int rc;

	... ...

	if (!OCFS2_IS_VALID_DINODE(di))
                rc = ocfs2_error(sb, "Invalid dinode #%llu: signature = %.*s\n",
		     (unsigned long long)bh->b_blocknr, 7,
                     di->i_signature);
                goto bail;
        }
```

to
```
	int rc = 0;

	... ...

	if (!OCFS2_IS_VALID_DINODE(di))
                mlog(sb, "Invalid dinode #%llu: signature = %.*s\n",
		     (unsigned long long)bh->b_blocknr, 7,
                     di->i_signature);
                goto bail;
        }

	... ...

	return rc;

bail:
	if (check) {
		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
	} else {
		rc = ocfs2_error(sb, "invalid dinode\n");
	}

	return rc;
}
```

Thanks,
Heming

> 
> > +
> >  /*
> >   * here's how inodes get read from disk:
> >   * iget5_locked -> find_actor -> OCFS2_FIND_ACTOR
> > @@ -1835,6 +1870,33 @@ static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
> >  		goto bail;
> >  	}
> >  
> > +	switch (ocfs2_check_extent_list(sb, di)) {
> > +	case OCFS2_EXTENT_LIST_OK:
> > +		break;
> > +	case OCFS2_EXTENT_LIST_ZERO_COUNT:
> > +		mlog(ML_ERROR,
> > +		     "Filecheck: invalid dinode #%llu: extent list l_count is zero\n",
> > +		     (unsigned long long)bh->b_blocknr);
> > +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> > +		goto bail;
> > +	case OCFS2_EXTENT_LIST_OVERSIZED:
> > +		mlog(ML_ERROR,
> > +		     "Filecheck: invalid dinode #%llu: extent list l_count %u exceeds max %u\n",
> > +		     (unsigned long long)bh->b_blocknr,
> > +		     le16_to_cpu(di->id2.i_list.l_count),
> > +		     ocfs2_extent_recs_per_inode(sb));
> > +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> > +		goto bail;
> > +	case OCFS2_EXTENT_LIST_BAD_NEXT_FREE:
> > +		mlog(ML_ERROR,
> > +		     "Filecheck: invalid dinode #%llu: extent list l_next_free_rec %u exceeds l_count %u\n",
> > +		     (unsigned long long)bh->b_blocknr,
> > +		     le16_to_cpu(di->id2.i_list.l_next_free_rec),
> > +		     le16_to_cpu(di->id2.i_list.l_count));
> > +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> > +		goto bail;
> > +	}
> > +
> >  	if (ocfs2_dinode_has_size_without_clusters(sb, di)) {
> >  		if (S_ISDIR(le16_to_cpu(di->i_mode)))
> >  			mlog(ML_ERROR,
> > @@ -1893,6 +1955,15 @@ static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
> >  		return -OCFS2_FILECHECK_ERR_VALIDFLAG;
> >  	}
> >  
> > +	switch (ocfs2_check_extent_list(sb, di)) {
> > +	case OCFS2_EXTENT_LIST_OK:
> > +	case OCFS2_EXTENT_LIST_BAD_NEXT_FREE:
> > +		break;
> > +	case OCFS2_EXTENT_LIST_ZERO_COUNT:
> > +	case OCFS2_EXTENT_LIST_OVERSIZED:
> > +		return -OCFS2_FILECHECK_ERR_INVALIDINO;
> > +	}
> > +
> >  	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
> >  		di->i_blkno = cpu_to_le64(bh->b_blocknr);
> >  		changed = 1;
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] ocfs2: validate extent list in filecheck repair
  2026-09-28  1:33 ` Joseph Qi
  2026-09-28  5:18   ` Heming Zhao
@ 2026-09-28  7:39   ` Heming Zhao
  2026-09-28  8:02     ` jiale yao
  1 sibling, 1 reply; 7+ messages in thread
From: Heming Zhao @ 2026-09-28  7:39 UTC (permalink / raw)
  To: Joseph Qi, yaojiale02
  Cc: Andrew Morton, Mark Fasheh, Joel Becker, ocfs2-devel, linux-kernel

On Mon, Sep 28, 2026 at 09:33:12AM +0800, Joseph Qi wrote:
> 
> 
> On 9/26/26 9:18 PM, Jiale Yao wrote:
> > ocfs2_filecheck_validate_inode_block() does not validate the embedded
> > extent list, while ocfs2_filecheck_repair_inode_block() only clamps
> > l_next_free_rec to l_count.  The normal inode read path requires l_count
> > to be non-zero, limits it to the number of extent records that fit in the
> > inode, and requires l_next_free_rec not to exceed l_count.
> > 
> > Without the same checks, filecheck can report SUCCESS while leaving an
> > invalid extent list on disk.  A later read through the normal inode
> > validation path rejects the inode and makes the filesystem read-only.
> > 
> > Add a shared helper for the filecheck paths to check these invariants.
> > The filecheck validator now rejects all three cases.  The repair path
> > still clamps l_next_free_rec, but refuses to repair zero or oversized
> > l_count values.
> > 
> > Fixes: d56a8f32e4c6 ("ocfs2: check/fix inode block for online file check")
> 
> I'd like make this as a new ability rather than a bug fix.

Agree

In my experience, users run online file checks only when inode data is corrupted,
or when fsck/debugfs has already reported an inode issue prior to the check.

The Fixes tag should only be used for the patch that fixes the unintended panic
and read-only issue introduced by commit d56a8f32e4c6.

- Heming

> 
> > Signed-off-by: Jiale Yao <yaojiale02@163.com>
> > ---
> >  fs/ocfs2/inode.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 71 insertions(+)
> > 
> > diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
> > index 180107a11046..57168ed02915 100644
> > --- a/fs/ocfs2/inode.c
> > +++ b/fs/ocfs2/inode.c
> > @@ -249,6 +249,41 @@ static int ocfs2_dinode_has_extents(struct ocfs2_dinode *di)
> >  	return 1;
> >  }
> >  
> > +enum ocfs2_extent_list_status {
> > +	OCFS2_EXTENT_LIST_OK,
> > +	OCFS2_EXTENT_LIST_ZERO_COUNT,
> > +	OCFS2_EXTENT_LIST_OVERSIZED,
> > +	OCFS2_EXTENT_LIST_BAD_NEXT_FREE,
> > +};
> > +
> > +static enum ocfs2_extent_list_status
> > +ocfs2_check_extent_list(struct super_block *sb, struct ocfs2_dinode *di)
> > +{
> > +	struct ocfs2_extent_list *el = &di->id2.i_list;
> > +	u16 count;
> > +	u16 next_free;
> > +
> > +	if (!ocfs2_dinode_has_extents(di))
> > +		return OCFS2_EXTENT_LIST_OK;
> > +
> > +	count = le16_to_cpu(el->l_count);
> > +	next_free = le16_to_cpu(el->l_next_free_rec);
> > +	if (count == 0)
> > +		return OCFS2_EXTENT_LIST_ZERO_COUNT;
> > +	/*
> > +	 * The exact capacity depends on i_xattr_inline_size, another
> > +	 * unvalidated on-disk field. Inline xattrs only shrink the
> > +	 * list, so the no-xattr maximum is a safe upper bound that a
> > +	 * valid l_count never exceeds.
> > +	 */
> > +	if (count > ocfs2_extent_recs_per_inode(sb))
> > +		return OCFS2_EXTENT_LIST_OVERSIZED;
> > +	if (next_free > count)
> > +		return OCFS2_EXTENT_LIST_BAD_NEXT_FREE;
> > +
> > +	return OCFS2_EXTENT_LIST_OK;
> > +}
> 
> This seems a duplicated check in ocfs2_validate_inode_block().
> So I sugguest just extract the helper from it instead of duplicating
> a new one.
> 
> BTW, seems we don't have to introduce enum ocfs2_extent_list_status,
> to make the checks simple.
> 
> Thanks,
> Joseph
> 
> > +
> >  /*
> >   * here's how inodes get read from disk:
> >   * iget5_locked -> find_actor -> OCFS2_FIND_ACTOR
> > @@ -1835,6 +1870,33 @@ static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
> >  		goto bail;
> >  	}
> >  
> > +	switch (ocfs2_check_extent_list(sb, di)) {
> > +	case OCFS2_EXTENT_LIST_OK:
> > +		break;
> > +	case OCFS2_EXTENT_LIST_ZERO_COUNT:
> > +		mlog(ML_ERROR,
> > +		     "Filecheck: invalid dinode #%llu: extent list l_count is zero\n",
> > +		     (unsigned long long)bh->b_blocknr);
> > +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> > +		goto bail;
> > +	case OCFS2_EXTENT_LIST_OVERSIZED:
> > +		mlog(ML_ERROR,
> > +		     "Filecheck: invalid dinode #%llu: extent list l_count %u exceeds max %u\n",
> > +		     (unsigned long long)bh->b_blocknr,
> > +		     le16_to_cpu(di->id2.i_list.l_count),
> > +		     ocfs2_extent_recs_per_inode(sb));
> > +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> > +		goto bail;
> > +	case OCFS2_EXTENT_LIST_BAD_NEXT_FREE:
> > +		mlog(ML_ERROR,
> > +		     "Filecheck: invalid dinode #%llu: extent list l_next_free_rec %u exceeds l_count %u\n",
> > +		     (unsigned long long)bh->b_blocknr,
> > +		     le16_to_cpu(di->id2.i_list.l_next_free_rec),
> > +		     le16_to_cpu(di->id2.i_list.l_count));
> > +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> > +		goto bail;
> > +	}
> > +
> >  	if (ocfs2_dinode_has_size_without_clusters(sb, di)) {
> >  		if (S_ISDIR(le16_to_cpu(di->i_mode)))
> >  			mlog(ML_ERROR,
> > @@ -1893,6 +1955,15 @@ static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
> >  		return -OCFS2_FILECHECK_ERR_VALIDFLAG;
> >  	}
> >  
> > +	switch (ocfs2_check_extent_list(sb, di)) {
> > +	case OCFS2_EXTENT_LIST_OK:
> > +	case OCFS2_EXTENT_LIST_BAD_NEXT_FREE:
> > +		break;
> > +	case OCFS2_EXTENT_LIST_ZERO_COUNT:
> > +	case OCFS2_EXTENT_LIST_OVERSIZED:
> > +		return -OCFS2_FILECHECK_ERR_INVALIDINO;
> > +	}
> > +
> >  	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
> >  		di->i_blkno = cpu_to_le64(bh->b_blocknr);
> >  		changed = 1;
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] ocfs2: validate extent list in filecheck repair
  2026-09-28  7:39   ` Heming Zhao
@ 2026-09-28  8:02     ` jiale yao
  0 siblings, 0 replies; 7+ messages in thread
From: jiale yao @ 2026-09-28  8:02 UTC (permalink / raw)
  To: Heming Zhao
  Cc: Joseph Qi, Andrew Morton, Mark Fasheh, Joel Becker, ocfs2-devel,
	linux-kernel

Thanks for the review. I agree that this should be treated as an
extension of online filecheck rather than a fix for d56a8f32e4c6.

I will prepare a v2 with the following changes:

- Drop the Fixes and stable tags and describe the change as additional
   filecheck validation.
- Extract the existing extent-list checks from
   ocfs2_validate_inode_block() into a small shared helper instead of
   duplicating them.
- Remove enum ocfs2_extent_list_status.
- Keep the repair policy unchanged: reject an invalid l_count, while
   allowing the existing code to clamp l_next_free_rec to l_count.

Thanks,
Jiale


At 2026-09-28 15:39:14, "Heming Zhao" <heming.zhao@suse.com> wrote:
>On Mon, Sep 28, 2026 at 09:33:12AM +0800, Joseph Qi wrote:
>> 
>> 
>> On 9/26/26 9:18 PM, Jiale Yao wrote:
>> > ocfs2_filecheck_validate_inode_block() does not validate the embedded
>> > extent list, while ocfs2_filecheck_repair_inode_block() only clamps
>> > l_next_free_rec to l_count.  The normal inode read path requires l_count
>> > to be non-zero, limits it to the number of extent records that fit in the
>> > inode, and requires l_next_free_rec not to exceed l_count.
>> > 
>> > Without the same checks, filecheck can report SUCCESS while leaving an
>> > invalid extent list on disk.  A later read through the normal inode
>> > validation path rejects the inode and makes the filesystem read-only.
>> > 
>> > Add a shared helper for the filecheck paths to check these invariants.
>> > The filecheck validator now rejects all three cases.  The repair path
>> > still clamps l_next_free_rec, but refuses to repair zero or oversized
>> > l_count values.
>> > 
>> > Fixes: d56a8f32e4c6 ("ocfs2: check/fix inode block for online file check")
>> 
>> I'd like make this as a new ability rather than a bug fix.
>
>Agree
>
>In my experience, users run online file checks only when inode data is corrupted,
>or when fsck/debugfs has already reported an inode issue prior to the check.
>
>The Fixes tag should only be used for the patch that fixes the unintended panic
>and read-only issue introduced by commit d56a8f32e4c6.
>
>- Heming
>
>> 
>> > Signed-off-by: Jiale Yao <yaojiale02@163.com>
>> > ---
>> >  fs/ocfs2/inode.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
>> >  1 file changed, 71 insertions(+)
>> > 
>> > diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
>> > index 180107a11046..57168ed02915 100644
>> > --- a/fs/ocfs2/inode.c
>> > +++ b/fs/ocfs2/inode.c
>> > @@ -249,6 +249,41 @@ static int ocfs2_dinode_has_extents(struct ocfs2_dinode *di)
>> >  	return 1;
>> >  }
>> >  
>> > +enum ocfs2_extent_list_status {
>> > +	OCFS2_EXTENT_LIST_OK,
>> > +	OCFS2_EXTENT_LIST_ZERO_COUNT,
>> > +	OCFS2_EXTENT_LIST_OVERSIZED,
>> > +	OCFS2_EXTENT_LIST_BAD_NEXT_FREE,
>> > +};
>> > +
>> > +static enum ocfs2_extent_list_status
>> > +ocfs2_check_extent_list(struct super_block *sb, struct ocfs2_dinode *di)
>> > +{
>> > +	struct ocfs2_extent_list *el = &di->id2.i_list;
>> > +	u16 count;
>> > +	u16 next_free;
>> > +
>> > +	if (!ocfs2_dinode_has_extents(di))
>> > +		return OCFS2_EXTENT_LIST_OK;
>> > +
>> > +	count = le16_to_cpu(el->l_count);
>> > +	next_free = le16_to_cpu(el->l_next_free_rec);
>> > +	if (count == 0)
>> > +		return OCFS2_EXTENT_LIST_ZERO_COUNT;
>> > +	/*
>> > +	 * The exact capacity depends on i_xattr_inline_size, another
>> > +	 * unvalidated on-disk field. Inline xattrs only shrink the
>> > +	 * list, so the no-xattr maximum is a safe upper bound that a
>> > +	 * valid l_count never exceeds.
>> > +	 */
>> > +	if (count > ocfs2_extent_recs_per_inode(sb))
>> > +		return OCFS2_EXTENT_LIST_OVERSIZED;
>> > +	if (next_free > count)
>> > +		return OCFS2_EXTENT_LIST_BAD_NEXT_FREE;
>> > +
>> > +	return OCFS2_EXTENT_LIST_OK;
>> > +}
>> 
>> This seems a duplicated check in ocfs2_validate_inode_block().
>> So I sugguest just extract the helper from it instead of duplicating
>> a new one.
>> 
>> BTW, seems we don't have to introduce enum ocfs2_extent_list_status,
>> to make the checks simple.
>> 
>> Thanks,
>> Joseph
>> 
>> > +
>> >  /*
>> >   * here's how inodes get read from disk:
>> >   * iget5_locked -> find_actor -> OCFS2_FIND_ACTOR
>> > @@ -1835,6 +1870,33 @@ static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
>> >  		goto bail;
>> >  	}
>> >  
>> > +	switch (ocfs2_check_extent_list(sb, di)) {
>> > +	case OCFS2_EXTENT_LIST_OK:
>> > +		break;
>> > +	case OCFS2_EXTENT_LIST_ZERO_COUNT:
>> > +		mlog(ML_ERROR,
>> > +		     "Filecheck: invalid dinode #%llu: extent list l_count is zero\n",
>> > +		     (unsigned long long)bh->b_blocknr);
>> > +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
>> > +		goto bail;
>> > +	case OCFS2_EXTENT_LIST_OVERSIZED:
>> > +		mlog(ML_ERROR,
>> > +		     "Filecheck: invalid dinode #%llu: extent list l_count %u exceeds max %u\n",
>> > +		     (unsigned long long)bh->b_blocknr,
>> > +		     le16_to_cpu(di->id2.i_list.l_count),
>> > +		     ocfs2_extent_recs_per_inode(sb));
>> > +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
>> > +		goto bail;
>> > +	case OCFS2_EXTENT_LIST_BAD_NEXT_FREE:
>> > +		mlog(ML_ERROR,
>> > +		     "Filecheck: invalid dinode #%llu: extent list l_next_free_rec %u exceeds l_count %u\n",
>> > +		     (unsigned long long)bh->b_blocknr,
>> > +		     le16_to_cpu(di->id2.i_list.l_next_free_rec),
>> > +		     le16_to_cpu(di->id2.i_list.l_count));
>> > +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
>> > +		goto bail;
>> > +	}
>> > +
>> >  	if (ocfs2_dinode_has_size_without_clusters(sb, di)) {
>> >  		if (S_ISDIR(le16_to_cpu(di->i_mode)))
>> >  			mlog(ML_ERROR,
>> > @@ -1893,6 +1955,15 @@ static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
>> >  		return -OCFS2_FILECHECK_ERR_VALIDFLAG;
>> >  	}
>> >  
>> > +	switch (ocfs2_check_extent_list(sb, di)) {
>> > +	case OCFS2_EXTENT_LIST_OK:
>> > +	case OCFS2_EXTENT_LIST_BAD_NEXT_FREE:
>> > +		break;
>> > +	case OCFS2_EXTENT_LIST_ZERO_COUNT:
>> > +	case OCFS2_EXTENT_LIST_OVERSIZED:
>> > +		return -OCFS2_FILECHECK_ERR_INVALIDINO;
>> > +	}
>> > +
>> >  	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
>> >  		di->i_blkno = cpu_to_le64(bh->b_blocknr);
>> >  		changed = 1;
>> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] ocfs2: validate extent list in filecheck repair
  2026-09-28  5:18   ` Heming Zhao
@ 2026-09-28  9:56     ` Joseph Qi
  2026-09-28 14:33       ` Heming Zhao
  0 siblings, 1 reply; 7+ messages in thread
From: Joseph Qi @ 2026-09-28  9:56 UTC (permalink / raw)
  To: Heming Zhao, yaojiale02
  Cc: Andrew Morton, Mark Fasheh, Joel Becker, ocfs2-devel, linux-kernel



On 9/28/26 1:18 PM, Heming Zhao wrote:
> On Mon, Sep 28, 2026 at 09:33:12AM +0800, Joseph Qi wrote:
>>
>>
>> On 9/26/26 9:18 PM, Jiale Yao wrote:
>>> ocfs2_filecheck_validate_inode_block() does not validate the embedded
>>> extent list, while ocfs2_filecheck_repair_inode_block() only clamps
>>> l_next_free_rec to l_count.  The normal inode read path requires l_count
>>> to be non-zero, limits it to the number of extent records that fit in the
>>> inode, and requires l_next_free_rec not to exceed l_count.
>>>
>>> Without the same checks, filecheck can report SUCCESS while leaving an
>>> invalid extent list on disk.  A later read through the normal inode
>>> validation path rejects the inode and makes the filesystem read-only.
>>>
>>> Add a shared helper for the filecheck paths to check these invariants.
>>> The filecheck validator now rejects all three cases.  The repair path
>>> still clamps l_next_free_rec, but refuses to repair zero or oversized
>>> l_count values.
>>>
>>> Fixes: d56a8f32e4c6 ("ocfs2: check/fix inode block for online file check")
>>
>> I'd like make this as a new ability rather than a bug fix.
>>
>>> Signed-off-by: Jiale Yao <yaojiale02@163.com>
>>> ---
>>>  fs/ocfs2/inode.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>  1 file changed, 71 insertions(+)
>>>
>>> diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
>>> index 180107a11046..57168ed02915 100644
>>> --- a/fs/ocfs2/inode.c
>>> +++ b/fs/ocfs2/inode.c
>>> @@ -249,6 +249,41 @@ static int ocfs2_dinode_has_extents(struct ocfs2_dinode *di)
>>>  	return 1;
>>>  }
>>>  
>>> +enum ocfs2_extent_list_status {
>>> +	OCFS2_EXTENT_LIST_OK,
>>> +	OCFS2_EXTENT_LIST_ZERO_COUNT,
>>> +	OCFS2_EXTENT_LIST_OVERSIZED,
>>> +	OCFS2_EXTENT_LIST_BAD_NEXT_FREE,
>>> +};
>>> +
>>> +static enum ocfs2_extent_list_status
>>> +ocfs2_check_extent_list(struct super_block *sb, struct ocfs2_dinode *di)
>>> +{
>>> +	struct ocfs2_extent_list *el = &di->id2.i_list;
>>> +	u16 count;
>>> +	u16 next_free;
>>> +
>>> +	if (!ocfs2_dinode_has_extents(di))
>>> +		return OCFS2_EXTENT_LIST_OK;
>>> +
>>> +	count = le16_to_cpu(el->l_count);
>>> +	next_free = le16_to_cpu(el->l_next_free_rec);
>>> +	if (count == 0)
>>> +		return OCFS2_EXTENT_LIST_ZERO_COUNT;
>>> +	/*
>>> +	 * The exact capacity depends on i_xattr_inline_size, another
>>> +	 * unvalidated on-disk field. Inline xattrs only shrink the
>>> +	 * list, so the no-xattr maximum is a safe upper bound that a
>>> +	 * valid l_count never exceeds.
>>> +	 */
>>> +	if (count > ocfs2_extent_recs_per_inode(sb))
>>> +		return OCFS2_EXTENT_LIST_OVERSIZED;
>>> +	if (next_free > count)
>>> +		return OCFS2_EXTENT_LIST_BAD_NEXT_FREE;
>>> +
>>> +	return OCFS2_EXTENT_LIST_OK;
>>> +}
>>
>> This seems a duplicated check in ocfs2_validate_inode_block().
>> So I sugguest just extract the helper from it instead of duplicating
>> a new one.
>>
>> BTW, seems we don't have to introduce enum ocfs2_extent_list_status,
>> to make the checks simple.
>>
>> Thanks,
>> Joseph
> 
> Hi Joseph,
> 
> The code logic is identical for ocfs2_validate_inode_block() and
> ocfs2_filecheck_validate_inode_block(), except for their error handling style.
> It seems possible to merge them into ocfs2_validate_inode_block() by adding
> a bool check parameter to distinguish between the two behaviors, and then remove
> ocfs2_filecheck_validate_inode_block().
> 
> The new code logic: replace ocfs2_error() with mlog(), and then "goto bail".
> At the bail label, handle the two cases separately using "if (check)".
> 
> i.e.:
> //adding a new parameter "check"
> int ocfs2_validate_inode_block(struct super_block *sb,
> 			       struct buffer_head *bh, bool check)
> 
> 
> code change from:
> ```
> 	int rc;
> 
> 	... ...
> 
> 	if (!OCFS2_IS_VALID_DINODE(di))
>                 rc = ocfs2_error(sb, "Invalid dinode #%llu: signature = %.*s\n",
> 		     (unsigned long long)bh->b_blocknr, 7,
>                      di->i_signature);
>                 goto bail;
>         }
> ```
> 
> to
> ```
> 	int rc = 0;
> 
> 	... ...
> 
> 	if (!OCFS2_IS_VALID_DINODE(di))
>                 mlog(sb, "Invalid dinode #%llu: signature = %.*s\n",
> 		     (unsigned long long)bh->b_blocknr, 7,
>                      di->i_signature);
>                 goto bail;
>         }
> 
> 	... ...
> 
> 	return rc;
> 
> bail:
> 	if (check) {
> 		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> 	} else {
> 		rc = ocfs2_error(sb, "invalid dinode\n");
> 	}
> 
> 	return rc;
> }
> ```

Ummm... This may make the code messy.
I'd like only abtract the check condition, and let the return code and
log message as in its own validation function.
e.g. ocfs2_dinode_has_size_without_clusters().

Thanks,
Joseph

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] ocfs2: validate extent list in filecheck repair
  2026-09-28  9:56     ` Joseph Qi
@ 2026-09-28 14:33       ` Heming Zhao
  0 siblings, 0 replies; 7+ messages in thread
From: Heming Zhao @ 2026-09-28 14:33 UTC (permalink / raw)
  To: Joseph Qi
  Cc: yaojiale02, Andrew Morton, Mark Fasheh, Joel Becker, ocfs2-devel,
	linux-kernel

On Mon, Sep 28, 2026 at 05:56:27PM +0800, Joseph Qi wrote:
> 
> 
> On 9/28/26 1:18 PM, Heming Zhao wrote:
> > On Mon, Sep 28, 2026 at 09:33:12AM +0800, Joseph Qi wrote:
> >>
> >>
> >> On 9/26/26 9:18 PM, Jiale Yao wrote:
> >>> ocfs2_filecheck_validate_inode_block() does not validate the embedded
> >>> extent list, while ocfs2_filecheck_repair_inode_block() only clamps
> >>> l_next_free_rec to l_count.  The normal inode read path requires l_count
> >>> to be non-zero, limits it to the number of extent records that fit in the
> >>> inode, and requires l_next_free_rec not to exceed l_count.
> >>>
> >>> Without the same checks, filecheck can report SUCCESS while leaving an
> >>> invalid extent list on disk.  A later read through the normal inode
> >>> validation path rejects the inode and makes the filesystem read-only.
> >>>
> >>> Add a shared helper for the filecheck paths to check these invariants.
> >>> The filecheck validator now rejects all three cases.  The repair path
> >>> still clamps l_next_free_rec, but refuses to repair zero or oversized
> >>> l_count values.
> >>>
> >>> Fixes: d56a8f32e4c6 ("ocfs2: check/fix inode block for online file check")
> >>
> >> I'd like make this as a new ability rather than a bug fix.
> >>
> >>> Signed-off-by: Jiale Yao <yaojiale02@163.com>
> >>> ---
> >>>  fs/ocfs2/inode.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>>  1 file changed, 71 insertions(+)
> >>>
> >>> diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
> >>> index 180107a11046..57168ed02915 100644
> >>> --- a/fs/ocfs2/inode.c
> >>> +++ b/fs/ocfs2/inode.c
> >>> @@ -249,6 +249,41 @@ static int ocfs2_dinode_has_extents(struct ocfs2_dinode *di)
> >>>  	return 1;
> >>>  }
> >>>  
> >>> +enum ocfs2_extent_list_status {
> >>> +	OCFS2_EXTENT_LIST_OK,
> >>> +	OCFS2_EXTENT_LIST_ZERO_COUNT,
> >>> +	OCFS2_EXTENT_LIST_OVERSIZED,
> >>> +	OCFS2_EXTENT_LIST_BAD_NEXT_FREE,
> >>> +};
> >>> +
> >>> +static enum ocfs2_extent_list_status
> >>> +ocfs2_check_extent_list(struct super_block *sb, struct ocfs2_dinode *di)
> >>> +{
> >>> +	struct ocfs2_extent_list *el = &di->id2.i_list;
> >>> +	u16 count;
> >>> +	u16 next_free;
> >>> +
> >>> +	if (!ocfs2_dinode_has_extents(di))
> >>> +		return OCFS2_EXTENT_LIST_OK;
> >>> +
> >>> +	count = le16_to_cpu(el->l_count);
> >>> +	next_free = le16_to_cpu(el->l_next_free_rec);
> >>> +	if (count == 0)
> >>> +		return OCFS2_EXTENT_LIST_ZERO_COUNT;
> >>> +	/*
> >>> +	 * The exact capacity depends on i_xattr_inline_size, another
> >>> +	 * unvalidated on-disk field. Inline xattrs only shrink the
> >>> +	 * list, so the no-xattr maximum is a safe upper bound that a
> >>> +	 * valid l_count never exceeds.
> >>> +	 */
> >>> +	if (count > ocfs2_extent_recs_per_inode(sb))
> >>> +		return OCFS2_EXTENT_LIST_OVERSIZED;
> >>> +	if (next_free > count)
> >>> +		return OCFS2_EXTENT_LIST_BAD_NEXT_FREE;
> >>> +
> >>> +	return OCFS2_EXTENT_LIST_OK;
> >>> +}
> >>
> >> This seems a duplicated check in ocfs2_validate_inode_block().
> >> So I sugguest just extract the helper from it instead of duplicating
> >> a new one.
> >>
> >> BTW, seems we don't have to introduce enum ocfs2_extent_list_status,
> >> to make the checks simple.
> >>
> >> Thanks,
> >> Joseph
> > 
> > Hi Joseph,
> > 
> > The code logic is identical for ocfs2_validate_inode_block() and
> > ocfs2_filecheck_validate_inode_block(), except for their error handling style.
> > It seems possible to merge them into ocfs2_validate_inode_block() by adding
> > a bool check parameter to distinguish between the two behaviors, and then remove
> > ocfs2_filecheck_validate_inode_block().
> > 
> > The new code logic: replace ocfs2_error() with mlog(), and then "goto bail".
> > At the bail label, handle the two cases separately using "if (check)".
> > 
> > i.e.:
> > //adding a new parameter "check"
> > int ocfs2_validate_inode_block(struct super_block *sb,
> > 			       struct buffer_head *bh, bool check)
> > 
> > 
> > code change from:
> > ```
> > 	int rc;
> > 
> > 	... ...
> > 
> > 	if (!OCFS2_IS_VALID_DINODE(di))
> >                 rc = ocfs2_error(sb, "Invalid dinode #%llu: signature = %.*s\n",
> > 		     (unsigned long long)bh->b_blocknr, 7,
> >                      di->i_signature);
> >                 goto bail;
> >         }
> > ```
> > 
> > to
> > ```
> > 	int rc = 0;
> > 
> > 	... ...
> > 
> > 	if (!OCFS2_IS_VALID_DINODE(di))
> >                 mlog(sb, "Invalid dinode #%llu: signature = %.*s\n",
> > 		     (unsigned long long)bh->b_blocknr, 7,
> >                      di->i_signature);
> >                 goto bail;
> >         }
> > 
> > 	... ...
> > 
> > 	return rc;
> > 
> > bail:
> > 	if (check) {
> > 		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> > 	} else {
> > 		rc = ocfs2_error(sb, "invalid dinode\n");
> > 	}
> > 
> > 	return rc;
> > }
> > ```
> 
> Ummm... This may make the code messy.
> I'd like only abtract the check condition, and let the return code and
> log message as in its own validation function.
> e.g. ocfs2_dinode_has_size_without_clusters().
> 
> Thanks,
> Joseph

Got it and agreed.

- Heming

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-09-28 14:33 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-26 13:18 [PATCH] ocfs2: validate extent list in filecheck repair Jiale Yao
2026-09-28  1:33 ` Joseph Qi
2026-09-28  5:18   ` Heming Zhao
2026-09-28  9:56     ` Joseph Qi
2026-09-28 14:33       ` Heming Zhao
2026-09-28  7:39   ` Heming Zhao
2026-09-28  8:02     ` jiale yao

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®