linux-xfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH] xfs: Fix logbsize validation
@ 2025-08-12 12:43 cem
  2025-08-13  2:16 ` Darrick J. Wong
  2025-08-13 22:23 ` Dave Chinner
  0 siblings, 2 replies; 6+ messages in thread
From: cem @ 2025-08-12 12:43 UTC (permalink / raw)
  To: linux-xfs

From: Carlos Maiolino <cem@kernel.org>

An user reported an inconsistency while mounting a V2 log filesystem
with logbsize equals to the stripe unit being used (192k).

The current validation algorithm for the log buffer size enforces the
user to pass a power_of_2 value between [16k-256k].
The manpage dictates the log buffer size must be a multiple of the log
stripe unit, but doesn't specify it must be a power_of_2. Also, if
logbsize is not specified at mount time, it will be set to
max(32768, log_sunit), where log_sunit not necessarily is a power_of_2.

It does seem to me then that logbsize being a power_of_2 constraint must
be relaxed if there is a configured log stripe unit, so this patch
updates the logbsize validation logic to ensure that:

- It can only be set to a specific range [16k-256k]

- Will be aligned to log stripe unit when the latter is set,
  and will be at least the same size as the log stripe unit.

- Enforce it to be power_of_2 aligned when log stripe unit is not set.

This is achieved by factoring out the logbsize validation to a separated
function to avoid a big chain of if conditionals

While at it, update m_logbufs and m_logbsize conditionals in
xfs_fs_validate_params from:
	(x != -1 && x != 0) to (x > 0)

Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
---

I am sending this as a RFC because although I did some basic testing,
xfstests is still running, so I can't tell yet if it will fail on some configuration even though I am not expecting it to.

 fs/xfs/xfs_super.c | 57 ++++++++++++++++++++++++++++++++--------------
 1 file changed, 40 insertions(+), 17 deletions(-)

diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index bb0a82635a77..38d3d8a0b026 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1059,6 +1059,29 @@ xfs_fs_unfreeze(
 	return 0;
 }
 
+STATIC int
+xfs_validate_logbsize(
+	struct xfs_mount	*mp)
+{
+	int			logbsize = mp->m_logbsize;
+	uint32_t		logsunit = mp->m_sb.sb_logsunit;
+
+	if (logsunit > 1) {
+		if (logbsize < logsunit ||
+		    logbsize % logsunit) {
+			xfs_warn(mp,
+		"logbuf size must be a multiple of the log stripe unit");
+			return -EINVAL;
+		}
+	} else {
+		if (!is_power_of_2(logbsize)) {
+		    xfs_warn(mp,
+		     "invalid logbufsize: %d [not a power of 2]", logbsize);
+		    return -EINVAL;
+		}
+	}
+	return 0;
+}
 /*
  * This function fills in xfs_mount_t fields based on mount args.
  * Note: the superblock _has_ now been read in.
@@ -1067,16 +1090,13 @@ STATIC int
 xfs_finish_flags(
 	struct xfs_mount	*mp)
 {
-	/* Fail a mount where the logbuf is smaller than the log stripe */
 	if (xfs_has_logv2(mp)) {
-		if (mp->m_logbsize <= 0 &&
-		    mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE) {
-			mp->m_logbsize = mp->m_sb.sb_logsunit;
-		} else if (mp->m_logbsize > 0 &&
-			   mp->m_logbsize < mp->m_sb.sb_logsunit) {
-			xfs_warn(mp,
-		"logbuf size must be greater than or equal to log stripe size");
-			return -EINVAL;
+		if (mp->m_logbsize > 0) {
+			if (xfs_validate_logbsize(mp))
+				return -EINVAL;
+		} else {
+			if (mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE)
+				mp->m_logbsize = mp->m_sb.sb_logsunit;
 		}
 	} else {
 		/* Fail a mount if the logbuf is larger than 32K */
@@ -1628,8 +1648,7 @@ xfs_fs_validate_params(
 		return -EINVAL;
 	}
 
-	if (mp->m_logbufs != -1 &&
-	    mp->m_logbufs != 0 &&
+	if (mp->m_logbufs > 0 &&
 	    (mp->m_logbufs < XLOG_MIN_ICLOGS ||
 	     mp->m_logbufs > XLOG_MAX_ICLOGS)) {
 		xfs_warn(mp, "invalid logbufs value: %d [not %d-%d]",
@@ -1637,14 +1656,18 @@ xfs_fs_validate_params(
 		return -EINVAL;
 	}
 
-	if (mp->m_logbsize != -1 &&
-	    mp->m_logbsize !=  0 &&
+	/*
+	 * We have not yet read the superblock, so we can't check against
+	 * logsunit here.
+	 */
+	if (mp->m_logbsize > 0 &&
 	    (mp->m_logbsize < XLOG_MIN_RECORD_BSIZE ||
-	     mp->m_logbsize > XLOG_MAX_RECORD_BSIZE ||
-	     !is_power_of_2(mp->m_logbsize))) {
+	     mp->m_logbsize > XLOG_MAX_RECORD_BSIZE)) {
 		xfs_warn(mp,
-			"invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
-			mp->m_logbsize);
+			"invalid logbufsize: %d [not in range %dk-%dk]",
+			mp->m_logbsize,
+			(XLOG_MIN_RECORD_BSIZE/1024),
+			(XLOG_MAX_RECORD_BSIZE/1024));
 		return -EINVAL;
 	}
 
-- 
2.50.1


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

* Re: [RFC PATCH] xfs: Fix logbsize validation
  2025-08-12 12:43 [RFC PATCH] xfs: Fix logbsize validation cem
@ 2025-08-13  2:16 ` Darrick J. Wong
  2025-08-13  7:55   ` Carlos Maiolino
  2025-08-13 17:58   ` Carlos Maiolino
  2025-08-13 22:23 ` Dave Chinner
  1 sibling, 2 replies; 6+ messages in thread
From: Darrick J. Wong @ 2025-08-13  2:16 UTC (permalink / raw)
  To: cem; +Cc: linux-xfs

On Tue, Aug 12, 2025 at 02:43:41PM +0200, cem@kernel.org wrote:
> From: Carlos Maiolino <cem@kernel.org>
> 
> An user reported an inconsistency while mounting a V2 log filesystem
> with logbsize equals to the stripe unit being used (192k).
> 
> The current validation algorithm for the log buffer size enforces the
> user to pass a power_of_2 value between [16k-256k].
> The manpage dictates the log buffer size must be a multiple of the log
> stripe unit, but doesn't specify it must be a power_of_2. Also, if
> logbsize is not specified at mount time, it will be set to
> max(32768, log_sunit), where log_sunit not necessarily is a power_of_2.
> 
> It does seem to me then that logbsize being a power_of_2 constraint must
> be relaxed if there is a configured log stripe unit, so this patch
> updates the logbsize validation logic to ensure that:
> 
> - It can only be set to a specific range [16k-256k]
> 
> - Will be aligned to log stripe unit when the latter is set,
>   and will be at least the same size as the log stripe unit.
> 
> - Enforce it to be power_of_2 aligned when log stripe unit is not set.
> 
> This is achieved by factoring out the logbsize validation to a separated
> function to avoid a big chain of if conditionals
> 
> While at it, update m_logbufs and m_logbsize conditionals in
> xfs_fs_validate_params from:
> 	(x != -1 && x != 0) to (x > 0)
> 
> Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
> ---
> 
> I am sending this as a RFC because although I did some basic testing,
> xfstests is still running, so I can't tell yet if it will fail on some configuration even though I am not expecting it to.

Heheh, how did that go?

>  fs/xfs/xfs_super.c | 57 ++++++++++++++++++++++++++++++++--------------
>  1 file changed, 40 insertions(+), 17 deletions(-)
> 
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index bb0a82635a77..38d3d8a0b026 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -1059,6 +1059,29 @@ xfs_fs_unfreeze(
>  	return 0;
>  }
>  
> +STATIC int
> +xfs_validate_logbsize(
> +	struct xfs_mount	*mp)
> +{
> +	int			logbsize = mp->m_logbsize;
> +	uint32_t		logsunit = mp->m_sb.sb_logsunit;

Why not access the fields directly instead of going through convenience
variables?

> +	if (logsunit > 1) {
> +		if (logbsize < logsunit ||
> +		    logbsize % logsunit) {
> +			xfs_warn(mp,
> +		"logbuf size must be a multiple of the log stripe unit");
> +			return -EINVAL;
> +		}
> +	} else {
> +		if (!is_power_of_2(logbsize)) {
> +		    xfs_warn(mp,

Odd indenting here  ^^^

> +		     "invalid logbufsize: %d [not a power of 2]", logbsize);
> +		    return -EINVAL;
> +		}
> +	}
> +	return 0;
> +}
>  /*
>   * This function fills in xfs_mount_t fields based on mount args.
>   * Note: the superblock _has_ now been read in.
> @@ -1067,16 +1090,13 @@ STATIC int
>  xfs_finish_flags(
>  	struct xfs_mount	*mp)
>  {
> -	/* Fail a mount where the logbuf is smaller than the log stripe */
>  	if (xfs_has_logv2(mp)) {
> -		if (mp->m_logbsize <= 0 &&
> -		    mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE) {
> -			mp->m_logbsize = mp->m_sb.sb_logsunit;
> -		} else if (mp->m_logbsize > 0 &&
> -			   mp->m_logbsize < mp->m_sb.sb_logsunit) {
> -			xfs_warn(mp,
> -		"logbuf size must be greater than or equal to log stripe size");
> -			return -EINVAL;
> +		if (mp->m_logbsize > 0) {
> +			if (xfs_validate_logbsize(mp))
> +				return -EINVAL;

If you're going to have xfs_validate_logbsize return an errno, then
capture it and return that, instead squashing them all to EINVAL.

AFAICT it's no big deal to have non-power-of-two log buffers, right?
I *think* everything looks ok, but I'm no expert in the bottom levels of
the xfs logging code. :/

--D

> +		} else {
> +			if (mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE)
> +				mp->m_logbsize = mp->m_sb.sb_logsunit;
>  		}
>  	} else {
>  		/* Fail a mount if the logbuf is larger than 32K */
> @@ -1628,8 +1648,7 @@ xfs_fs_validate_params(
>  		return -EINVAL;
>  	}
>  
> -	if (mp->m_logbufs != -1 &&
> -	    mp->m_logbufs != 0 &&
> +	if (mp->m_logbufs > 0 &&
>  	    (mp->m_logbufs < XLOG_MIN_ICLOGS ||
>  	     mp->m_logbufs > XLOG_MAX_ICLOGS)) {
>  		xfs_warn(mp, "invalid logbufs value: %d [not %d-%d]",
> @@ -1637,14 +1656,18 @@ xfs_fs_validate_params(
>  		return -EINVAL;
>  	}
>  
> -	if (mp->m_logbsize != -1 &&
> -	    mp->m_logbsize !=  0 &&
> +	/*
> +	 * We have not yet read the superblock, so we can't check against
> +	 * logsunit here.
> +	 */
> +	if (mp->m_logbsize > 0 &&
>  	    (mp->m_logbsize < XLOG_MIN_RECORD_BSIZE ||
> -	     mp->m_logbsize > XLOG_MAX_RECORD_BSIZE ||
> -	     !is_power_of_2(mp->m_logbsize))) {
> +	     mp->m_logbsize > XLOG_MAX_RECORD_BSIZE)) {
>  		xfs_warn(mp,
> -			"invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
> -			mp->m_logbsize);
> +			"invalid logbufsize: %d [not in range %dk-%dk]",
> +			mp->m_logbsize,
> +			(XLOG_MIN_RECORD_BSIZE/1024),
> +			(XLOG_MAX_RECORD_BSIZE/1024));
>  		return -EINVAL;
>  	}
>  
> -- 
> 2.50.1
> 
> 

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

* Re: [RFC PATCH] xfs: Fix logbsize validation
  2025-08-13  2:16 ` Darrick J. Wong
@ 2025-08-13  7:55   ` Carlos Maiolino
  2025-08-13 17:58   ` Carlos Maiolino
  1 sibling, 0 replies; 6+ messages in thread
From: Carlos Maiolino @ 2025-08-13  7:55 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Tue, Aug 12, 2025 at 07:16:55PM -0700, Darrick J. Wong wrote:
> On Tue, Aug 12, 2025 at 02:43:41PM +0200, cem@kernel.org wrote:
> > From: Carlos Maiolino <cem@kernel.org>
> >
> > An user reported an inconsistency while mounting a V2 log filesystem
> > with logbsize equals to the stripe unit being used (192k).
> >
> > The current validation algorithm for the log buffer size enforces the
> > user to pass a power_of_2 value between [16k-256k].
> > The manpage dictates the log buffer size must be a multiple of the log
> > stripe unit, but doesn't specify it must be a power_of_2. Also, if
> > logbsize is not specified at mount time, it will be set to
> > max(32768, log_sunit), where log_sunit not necessarily is a power_of_2.
> >
> > It does seem to me then that logbsize being a power_of_2 constraint must
> > be relaxed if there is a configured log stripe unit, so this patch
> > updates the logbsize validation logic to ensure that:
> >
> > - It can only be set to a specific range [16k-256k]
> >
> > - Will be aligned to log stripe unit when the latter is set,
> >   and will be at least the same size as the log stripe unit.
> >
> > - Enforce it to be power_of_2 aligned when log stripe unit is not set.
> >
> > This is achieved by factoring out the logbsize validation to a separated
> > function to avoid a big chain of if conditionals
> >
> > While at it, update m_logbufs and m_logbsize conditionals in
> > xfs_fs_validate_params from:
> > 	(x != -1 && x != 0) to (x > 0)
> >
> > Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
> > ---
> >
> > I am sending this as a RFC because although I did some basic testing,
> > xfstests is still running, so I can't tell yet if it will fail on some configuration even though I am not expecting it to.
> 
> Heheh, how did that go?

quick group seems ok, I'll run something more complete today

> 
> >  fs/xfs/xfs_super.c | 57 ++++++++++++++++++++++++++++++++--------------
> >  1 file changed, 40 insertions(+), 17 deletions(-)
> >
> > diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> > index bb0a82635a77..38d3d8a0b026 100644
> > --- a/fs/xfs/xfs_super.c
> > +++ b/fs/xfs/xfs_super.c
> > @@ -1059,6 +1059,29 @@ xfs_fs_unfreeze(
> >  	return 0;
> >  }
> >
> > +STATIC int
> > +xfs_validate_logbsize(
> > +	struct xfs_mount	*mp)
> > +{
> > +	int			logbsize = mp->m_logbsize;
> > +	uint32_t		logsunit = mp->m_sb.sb_logsunit;
> 
> Why not access the fields directly instead of going through convenience
> variables?

I did this to pack the lines length a bit, I initially was writing it
inline to xfs_finish_flags(), then decided to move it to a different
function and I kept the local vars.

> 
> > +	if (logsunit > 1) {
> > +		if (logbsize < logsunit ||
> > +		    logbsize % logsunit) {
> > +			xfs_warn(mp,
> > +		"logbuf size must be a multiple of the log stripe unit");
> > +			return -EINVAL;
> > +		}
> > +	} else {
> > +		if (!is_power_of_2(logbsize)) {
> > +		    xfs_warn(mp,
> 
> Odd indenting here  ^^^

Yeah, sorry, will fix that.

> 
> > +		     "invalid logbufsize: %d [not a power of 2]", logbsize);
> > +		    return -EINVAL;
> > +		}
> > +	}
> > +	return 0;
> > +}
> >  /*
> >   * This function fills in xfs_mount_t fields based on mount args.
> >   * Note: the superblock _has_ now been read in.
> > @@ -1067,16 +1090,13 @@ STATIC int
> >  xfs_finish_flags(
> >  	struct xfs_mount	*mp)
> >  {
> > -	/* Fail a mount where the logbuf is smaller than the log stripe */
> >  	if (xfs_has_logv2(mp)) {
> > -		if (mp->m_logbsize <= 0 &&
> > -		    mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE) {
> > -			mp->m_logbsize = mp->m_sb.sb_logsunit;
> > -		} else if (mp->m_logbsize > 0 &&
> > -			   mp->m_logbsize < mp->m_sb.sb_logsunit) {
> > -			xfs_warn(mp,
> > -		"logbuf size must be greater than or equal to log stripe size");
> > -			return -EINVAL;
> > +		if (mp->m_logbsize > 0) {
> > +			if (xfs_validate_logbsize(mp))
> > +				return -EINVAL;
> 
> If you're going to have xfs_validate_logbsize return an errno, then
> capture it and return that, instead squashing them all to EINVAL.

Fair enough.

> 
> AFAICT it's no big deal to have non-power-of-two log buffers, right?
> I *think* everything looks ok, but I'm no expert in the bottom levels of
> the xfs logging code. :/

Heh, I couldn't find anything that really prevents log buffers to be
non-power-of-to, in fact, that's what happens today when we don't
specify a logbsize, but we have a non-power-of-2 log stripe unit.

FWIW, I thought a bit about the possibility to simply prevent log stripe
units to be a non-power-of-2, but the whole reason the user who reported
this hit this problem was that he's using a SSD reporting 192k stripe.
Quoting his own words:

"if you are wondering why I am using a 48b stripe, ask the ssd
manufacturer"

So, it seems to me that restricting log sunit to be power-of-2 aligned,
is not gonna play well with some hardware out there.


> 
> --D
> 
> > +		} else {
> > +			if (mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE)
> > +				mp->m_logbsize = mp->m_sb.sb_logsunit;
> >  		}
> >  	} else {
> >  		/* Fail a mount if the logbuf is larger than 32K */
> > @@ -1628,8 +1648,7 @@ xfs_fs_validate_params(
> >  		return -EINVAL;
> >  	}
> >
> > -	if (mp->m_logbufs != -1 &&
> > -	    mp->m_logbufs != 0 &&
> > +	if (mp->m_logbufs > 0 &&
> >  	    (mp->m_logbufs < XLOG_MIN_ICLOGS ||
> >  	     mp->m_logbufs > XLOG_MAX_ICLOGS)) {
> >  		xfs_warn(mp, "invalid logbufs value: %d [not %d-%d]",
> > @@ -1637,14 +1656,18 @@ xfs_fs_validate_params(
> >  		return -EINVAL;
> >  	}
> >
> > -	if (mp->m_logbsize != -1 &&
> > -	    mp->m_logbsize !=  0 &&
> > +	/*
> > +	 * We have not yet read the superblock, so we can't check against
> > +	 * logsunit here.
> > +	 */
> > +	if (mp->m_logbsize > 0 &&
> >  	    (mp->m_logbsize < XLOG_MIN_RECORD_BSIZE ||
> > -	     mp->m_logbsize > XLOG_MAX_RECORD_BSIZE ||
> > -	     !is_power_of_2(mp->m_logbsize))) {
> > +	     mp->m_logbsize > XLOG_MAX_RECORD_BSIZE)) {
> >  		xfs_warn(mp,
> > -			"invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
> > -			mp->m_logbsize);
> > +			"invalid logbufsize: %d [not in range %dk-%dk]",
> > +			mp->m_logbsize,
> > +			(XLOG_MIN_RECORD_BSIZE/1024),
> > +			(XLOG_MAX_RECORD_BSIZE/1024));
> >  		return -EINVAL;
> >  	}
> >
> > --
> > 2.50.1
> >
> >

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

* Re: [RFC PATCH] xfs: Fix logbsize validation
  2025-08-13  2:16 ` Darrick J. Wong
  2025-08-13  7:55   ` Carlos Maiolino
@ 2025-08-13 17:58   ` Carlos Maiolino
  1 sibling, 0 replies; 6+ messages in thread
From: Carlos Maiolino @ 2025-08-13 17:58 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Tue, Aug 12, 2025 at 07:16:55PM -0700, Darrick J. Wong wrote:
> On Tue, Aug 12, 2025 at 02:43:41PM +0200, cem@kernel.org wrote:
> > From: Carlos Maiolino <cem@kernel.org>
> >
> > An user reported an inconsistency while mounting a V2 log filesystem
> > with logbsize equals to the stripe unit being used (192k).
> >
> > The current validation algorithm for the log buffer size enforces the
> > user to pass a power_of_2 value between [16k-256k].
> > The manpage dictates the log buffer size must be a multiple of the log
> > stripe unit, but doesn't specify it must be a power_of_2. Also, if
> > logbsize is not specified at mount time, it will be set to
> > max(32768, log_sunit), where log_sunit not necessarily is a power_of_2.
> >
> > It does seem to me then that logbsize being a power_of_2 constraint must
> > be relaxed if there is a configured log stripe unit, so this patch
> > updates the logbsize validation logic to ensure that:
> >
> > - It can only be set to a specific range [16k-256k]
> >
> > - Will be aligned to log stripe unit when the latter is set,
> >   and will be at least the same size as the log stripe unit.
> >
> > - Enforce it to be power_of_2 aligned when log stripe unit is not set.
> >
> > This is achieved by factoring out the logbsize validation to a separated
> > function to avoid a big chain of if conditionals
> >
> > While at it, update m_logbufs and m_logbsize conditionals in
> > xfs_fs_validate_params from:
> > 	(x != -1 && x != 0) to (x > 0)
> >
> > Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
> > ---
> >
> > I am sending this as a RFC because although I did some basic testing,
> > xfstests is still running, so I can't tell yet if it will fail on some configuration even though I am not expecting it to.
> 
> Heheh, how did that go?

Tests looks mostly fine, there were a few extra failures which seemed
all related to tests which uses a custom geometry, not compatible with
those I was forcing on all the tests, I'll double check if there is
anything suspicious, and if everything is ok, I'll send a proper non-rfc
version.

> 
> >  fs/xfs/xfs_super.c | 57 ++++++++++++++++++++++++++++++++--------------
> >  1 file changed, 40 insertions(+), 17 deletions(-)
> >
> > diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> > index bb0a82635a77..38d3d8a0b026 100644
> > --- a/fs/xfs/xfs_super.c
> > +++ b/fs/xfs/xfs_super.c
> > @@ -1059,6 +1059,29 @@ xfs_fs_unfreeze(
> >  	return 0;
> >  }
> >
> > +STATIC int
> > +xfs_validate_logbsize(
> > +	struct xfs_mount	*mp)
> > +{
> > +	int			logbsize = mp->m_logbsize;
> > +	uint32_t		logsunit = mp->m_sb.sb_logsunit;
> 
> Why not access the fields directly instead of going through convenience
> variables?
> 
> > +	if (logsunit > 1) {
> > +		if (logbsize < logsunit ||
> > +		    logbsize % logsunit) {
> > +			xfs_warn(mp,
> > +		"logbuf size must be a multiple of the log stripe unit");
> > +			return -EINVAL;
> > +		}
> > +	} else {
> > +		if (!is_power_of_2(logbsize)) {
> > +		    xfs_warn(mp,
> 
> Odd indenting here  ^^^
> 
> > +		     "invalid logbufsize: %d [not a power of 2]", logbsize);
> > +		    return -EINVAL;
> > +		}
> > +	}
> > +	return 0;
> > +}
> >  /*
> >   * This function fills in xfs_mount_t fields based on mount args.
> >   * Note: the superblock _has_ now been read in.
> > @@ -1067,16 +1090,13 @@ STATIC int
> >  xfs_finish_flags(
> >  	struct xfs_mount	*mp)
> >  {
> > -	/* Fail a mount where the logbuf is smaller than the log stripe */
> >  	if (xfs_has_logv2(mp)) {
> > -		if (mp->m_logbsize <= 0 &&
> > -		    mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE) {
> > -			mp->m_logbsize = mp->m_sb.sb_logsunit;
> > -		} else if (mp->m_logbsize > 0 &&
> > -			   mp->m_logbsize < mp->m_sb.sb_logsunit) {
> > -			xfs_warn(mp,
> > -		"logbuf size must be greater than or equal to log stripe size");
> > -			return -EINVAL;
> > +		if (mp->m_logbsize > 0) {
> > +			if (xfs_validate_logbsize(mp))
> > +				return -EINVAL;
> 
> If you're going to have xfs_validate_logbsize return an errno, then
> capture it and return that, instead squashing them all to EINVAL.
> 
> AFAICT it's no big deal to have non-power-of-two log buffers, right?
> I *think* everything looks ok, but I'm no expert in the bottom levels of
> the xfs logging code. :/
> 
> --D
> 
> > +		} else {
> > +			if (mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE)
> > +				mp->m_logbsize = mp->m_sb.sb_logsunit;
> >  		}
> >  	} else {
> >  		/* Fail a mount if the logbuf is larger than 32K */
> > @@ -1628,8 +1648,7 @@ xfs_fs_validate_params(
> >  		return -EINVAL;
> >  	}
> >
> > -	if (mp->m_logbufs != -1 &&
> > -	    mp->m_logbufs != 0 &&
> > +	if (mp->m_logbufs > 0 &&
> >  	    (mp->m_logbufs < XLOG_MIN_ICLOGS ||
> >  	     mp->m_logbufs > XLOG_MAX_ICLOGS)) {
> >  		xfs_warn(mp, "invalid logbufs value: %d [not %d-%d]",
> > @@ -1637,14 +1656,18 @@ xfs_fs_validate_params(
> >  		return -EINVAL;
> >  	}
> >
> > -	if (mp->m_logbsize != -1 &&
> > -	    mp->m_logbsize !=  0 &&
> > +	/*
> > +	 * We have not yet read the superblock, so we can't check against
> > +	 * logsunit here.
> > +	 */
> > +	if (mp->m_logbsize > 0 &&
> >  	    (mp->m_logbsize < XLOG_MIN_RECORD_BSIZE ||
> > -	     mp->m_logbsize > XLOG_MAX_RECORD_BSIZE ||
> > -	     !is_power_of_2(mp->m_logbsize))) {
> > +	     mp->m_logbsize > XLOG_MAX_RECORD_BSIZE)) {
> >  		xfs_warn(mp,
> > -			"invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
> > -			mp->m_logbsize);
> > +			"invalid logbufsize: %d [not in range %dk-%dk]",
> > +			mp->m_logbsize,
> > +			(XLOG_MIN_RECORD_BSIZE/1024),
> > +			(XLOG_MAX_RECORD_BSIZE/1024));
> >  		return -EINVAL;
> >  	}
> >
> > --
> > 2.50.1
> >
> >
> 

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

* Re: [RFC PATCH] xfs: Fix logbsize validation
  2025-08-12 12:43 [RFC PATCH] xfs: Fix logbsize validation cem
  2025-08-13  2:16 ` Darrick J. Wong
@ 2025-08-13 22:23 ` Dave Chinner
  2025-08-18 11:42   ` Carlos Maiolino
  1 sibling, 1 reply; 6+ messages in thread
From: Dave Chinner @ 2025-08-13 22:23 UTC (permalink / raw)
  To: cem; +Cc: linux-xfs

On Tue, Aug 12, 2025 at 02:43:41PM +0200, cem@kernel.org wrote:
> From: Carlos Maiolino <cem@kernel.org>
> 
> An user reported an inconsistency while mounting a V2 log filesystem
> with logbsize equals to the stripe unit being used (192k).
> 
> The current validation algorithm for the log buffer size enforces the
> user to pass a power_of_2 value between [16k-256k].
> The manpage dictates the log buffer size must be a multiple of the log
> stripe unit, but doesn't specify it must be a power_of_2.

The xfs(5) man page explicitly lists a set of fixed sizes that are
supported, all of which are a power of two.

> Also, if
> logbsize is not specified at mount time, it will be set to
> max(32768, log_sunit), where log_sunit not necessarily is a power_of_2.

log_sunit is set by mkfs, so the user cannot change that
dynmaically. LSU is generally something that should not be
overridden by users - it is set by mkfs for optimal performance on
devices that require specific write alignment to avoid costly RMW
cycles...

> It does seem to me then that logbsize being a power_of_2 constraint must
> be relaxed if there is a configured log stripe unit, so this patch
> updates the logbsize validation logic to ensure that:
> 
> - It can only be set to a specific range [16k-256k]
> 
> - Will be aligned to log stripe unit when the latter is set,
>   and will be at least the same size as the log stripe unit.

Have you tested what happens when LSU is set to, say 72kB and
logbsize is set to 216kB? (i.e. integer multiple of 3). What about a
LSU of 19kB on a 1kB filesystem and a logbsize of 247kB? 

These are weird and wacky configurations, but this change allows
users to create them. i.e. it greatly expands the test matrix for
these mount and mkfs options by adding an entirely new
dimension to LSU configuration testing matrix.

Does the benefit that this change provide outweigh the risk of
uncovering some hidden corner case in the iclog alignment code? And
failure here will result in journal corruption, and that may be very
difficult to detect as it will only be noticed if there are
subsequent recovery failures. That's a pretty nasty failure mode -
it's difficult to triage and find the root cause, and it guarantees
data loss and downtime for the user because it can only be fixed by
running xfs_repair to zero the log.

So, do the risks associated with greatly expanding the supported
iclogbuf/LSU configurations outweigh the benefits that users will
gain from having this expanded functionality?

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [RFC PATCH] xfs: Fix logbsize validation
  2025-08-13 22:23 ` Dave Chinner
@ 2025-08-18 11:42   ` Carlos Maiolino
  0 siblings, 0 replies; 6+ messages in thread
From: Carlos Maiolino @ 2025-08-18 11:42 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, Aug 14, 2025 at 08:23:58AM +1000, Dave Chinner wrote:
> On Tue, Aug 12, 2025 at 02:43:41PM +0200, cem@kernel.org wrote:
> > From: Carlos Maiolino <cem@kernel.org>
> >
> > An user reported an inconsistency while mounting a V2 log filesystem
> > with logbsize equals to the stripe unit being used (192k).
> >
> > The current validation algorithm for the log buffer size enforces the
> > user to pass a power_of_2 value between [16k-256k].
> > The manpage dictates the log buffer size must be a multiple of the log
> > stripe unit, but doesn't specify it must be a power_of_2.
> 
> The xfs(5) man page explicitly lists a set of fixed sizes that are
> supported, all of which are a power of two.

Right, but yet if a log sunit is set, mount will automatically set to a
different value (if sunit is not any of those values). This is when it
gets confused.

> 
> > Also, if
> > logbsize is not specified at mount time, it will be set to
> > max(32768, log_sunit), where log_sunit not necessarily is a power_of_2.
> 
> log_sunit is set by mkfs, so the user cannot change that
> dynmaically. LSU is generally something that should not be
> overridden by users - it is set by mkfs for optimal performance on
> devices that require specific write alignment to avoid costly RMW
> cycles...
> 
> > It does seem to me then that logbsize being a power_of_2 constraint must
> > be relaxed if there is a configured log stripe unit, so this patch
> > updates the logbsize validation logic to ensure that:
> >
> > - It can only be set to a specific range [16k-256k]
> >
> > - Will be aligned to log stripe unit when the latter is set,
> >   and will be at least the same size as the log stripe unit.
> 
> Have you tested what happens when LSU is set to, say 72kB and
> logbsize is set to 216kB? (i.e. integer multiple of 3). What about a
> LSU of 19kB on a 1kB filesystem and a logbsize of 247kB?

So far I did test only a 96k logbsize with 32k LSU, I need more time to
test different configurations, but I see where you are getting to.


> 
> These are weird and wacky configurations, but this change allows
> users to create them. i.e. it greatly expands the test matrix for
> these mount and mkfs options by adding an entirely new
> dimension to LSU configuration testing matrix.

Right, agreed.

> 
> Does the benefit that this change provide outweigh the risk of
> uncovering some hidden corner case in the iclog alignment code? And
> failure here will result in journal corruption, and that may be very
> difficult to detect as it will only be noticed if there are
> subsequent recovery failures. That's a pretty nasty failure mode -
> it's difficult to triage and find the root cause, and it guarantees
> data loss and downtime for the user because it can only be fixed by
> running xfs_repair to zero the log.
> 
> So, do the risks associated with greatly expanding the supported
> iclogbuf/LSU configurations outweigh the benefits that users will
> gain from having this expanded functionality?

Agree. It's not worth the increased complexity, I'll update the manpage
only to reflect the current behavior.

Thanks for the review Dave.

Carlos,

> 
> Cheers,
> 
> Dave.
> --
> Dave Chinner
> david@fromorbit.com

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

end of thread, other threads:[~2025-08-18 11:42 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-12 12:43 [RFC PATCH] xfs: Fix logbsize validation cem
2025-08-13  2:16 ` Darrick J. Wong
2025-08-13  7:55   ` Carlos Maiolino
2025-08-13 17:58   ` Carlos Maiolino
2025-08-13 22:23 ` Dave Chinner
2025-08-18 11:42   ` Carlos Maiolino

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