diff mbox series

[2/2] xfs_db: calculate iext tree geometry in btheight command

Message ID 156944765991.303060.7541074919992777157.stgit@magnolia (mailing list archive)
State Superseded
Headers show
Series xfs_db: fixes to the btheight command | expand

Commit Message

Darrick J. Wong Sept. 25, 2019, 9:40 p.m. UTC
From: Darrick J. Wong <darrick.wong@oracle.com>

(Ab)use the btheight command to calculate the geometry of the incore
extent tree.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 db/btheight.c |   87 +++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 60 insertions(+), 27 deletions(-)

Comments

Carlos Maiolino Sept. 26, 2019, 9:20 a.m. UTC | #1
On Wed, Sep 25, 2019 at 02:40:59PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> (Ab)use the btheight command to calculate the geometry of the incore
> extent tree.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  db/btheight.c |   87 +++++++++++++++++++++++++++++++++++++++------------------
>  1 file changed, 60 insertions(+), 27 deletions(-)
> 
> 
> diff --git a/db/btheight.c b/db/btheight.c
> index e2c9759f..be604ebc 100644
> --- a/db/btheight.c
> +++ b/db/btheight.c
> @@ -22,18 +22,37 @@ static int rmap_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
>  	return libxfs_rmapbt_maxrecs(blocklen, leaf);
>  }
>  
> +static int iext_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
> +{
> +	blocklen -= 2 * sizeof(void *);
> +
> +	return blocklen / sizeof(struct xfs_bmbt_rec);
> +}
> +
> +static int disk_blocksize(struct xfs_mount *mp)

This naming looks confusing to me, disk_blocksize sounds to me like
'sector size', maybe fs_blocksize() or get_fs_blocksize()?
> +{
> +	return mp->m_sb.sb_blocksize;
> +}
> +

Otherwise looks good.


> +static int iext_blocksize(struct xfs_mount *mp)
> +{
> +	return 256;
> +}
> +
>  struct btmap {
>  	const char	*tag;
>  	int		(*maxrecs)(struct xfs_mount *mp, int blocklen,
>  				   int leaf);
> +	int		(*default_blocksize)(struct xfs_mount *mp);
>  } maps[] = {
> -	{"bnobt", libxfs_allocbt_maxrecs},
> -	{"cntbt", libxfs_allocbt_maxrecs},
> -	{"inobt", libxfs_inobt_maxrecs},
> -	{"finobt", libxfs_inobt_maxrecs},
> -	{"bmapbt", libxfs_bmbt_maxrecs},
> -	{"refcountbt", refc_maxrecs},
> -	{"rmapbt", rmap_maxrecs},
> +	{"bnobt", libxfs_allocbt_maxrecs, disk_blocksize},
> +	{"cntbt", libxfs_allocbt_maxrecs, disk_blocksize},
> +	{"inobt", libxfs_inobt_maxrecs, disk_blocksize},
> +	{"finobt", libxfs_inobt_maxrecs, disk_blocksize},
> +	{"bmapbt", libxfs_bmbt_maxrecs, disk_blocksize},
> +	{"refcountbt", refc_maxrecs, disk_blocksize},
> +	{"rmapbt", rmap_maxrecs, disk_blocksize},
> +	{"iext", iext_maxrecs, iext_blocksize},
>  };
>  
>  static void
> @@ -108,7 +127,7 @@ calc_height(
>  static int
>  construct_records_per_block(
>  	char		*tag,
> -	int		blocksize,
> +	int		*blocksize,
>  	unsigned int	*records_per_block)
>  {
>  	char		*toktag;
> @@ -119,8 +138,10 @@ construct_records_per_block(
>  
>  	for (i = 0, m = maps; i < ARRAY_SIZE(maps); i++, m++) {
>  		if (!strcmp(m->tag, tag)) {
> -			records_per_block[0] = m->maxrecs(mp, blocksize, 1);
> -			records_per_block[1] = m->maxrecs(mp, blocksize, 0);
> +			if (*blocksize < 0)
> +				*blocksize = m->default_blocksize(mp);
> +			records_per_block[0] = m->maxrecs(mp, *blocksize, 1);
> +			records_per_block[1] = m->maxrecs(mp, *blocksize, 0);
>  			return 0;
>  		}
>  	}
> @@ -178,38 +199,50 @@ construct_records_per_block(
>  		fprintf(stderr, _("%s: header type not found.\n"), tag);
>  		goto out;
>  	}
> -	if (!strcmp(p, "short"))
> +	if (!strcmp(p, "short")) {
> +		if (*blocksize < 0)
> +			*blocksize = mp->m_sb.sb_blocksize;
>  		blocksize -= XFS_BTREE_SBLOCK_LEN;
> -	else if (!strcmp(p, "shortcrc"))
> +	} else if (!strcmp(p, "shortcrc")) {
> +		if (*blocksize < 0)
> +			*blocksize = mp->m_sb.sb_blocksize;
>  		blocksize -= XFS_BTREE_SBLOCK_CRC_LEN;
> -	else if (!strcmp(p, "long"))
> +	} else if (!strcmp(p, "long")) {
> +		if (*blocksize < 0)
> +			*blocksize = mp->m_sb.sb_blocksize;
>  		blocksize -= XFS_BTREE_LBLOCK_LEN;
> -	else if (!strcmp(p, "longcrc"))
> +	} else if (!strcmp(p, "longcrc")) {
> +		if (*blocksize < 0)
> +			*blocksize = mp->m_sb.sb_blocksize;
>  		blocksize -= XFS_BTREE_LBLOCK_CRC_LEN;
> -	else {
> +	} else if (!strcmp(p, "iext")) {
> +		if (*blocksize < 0)
> +			*blocksize = 256;
> +		blocksize -= 2 * sizeof(void *);
> +	} else {
>  		fprintf(stderr, _("%s: unrecognized btree header type."),
>  				p);
>  		goto out;
>  	}
>  
> -	if (record_size > blocksize) {
> +	if (record_size > *blocksize) {
>  		fprintf(stderr,
>  			_("%s: record size must be less than %u bytes.\n"),
> -			tag, blocksize);
> +			tag, *blocksize);
>  		goto out;
>  	}
>  
> -	if (key_size > blocksize) {
> +	if (key_size > *blocksize) {
>  		fprintf(stderr,
>  			_("%s: key size must be less than %u bytes.\n"),
> -			tag, blocksize);
> +			tag, *blocksize);
>  		goto out;
>  	}
>  
> -	if (ptr_size > blocksize) {
> +	if (ptr_size > *blocksize) {
>  		fprintf(stderr,
>  			_("%s: pointer size must be less than %u bytes.\n"),
> -			tag, blocksize);
> +			tag, *blocksize);
>  		goto out;
>  	}
>  
> @@ -221,8 +254,8 @@ construct_records_per_block(
>  		goto out;
>  	}
>  
> -	records_per_block[0] = blocksize / record_size;
> -	records_per_block[1] = blocksize / (key_size + ptr_size);
> +	records_per_block[0] = *blocksize / record_size;
> +	records_per_block[1] = *blocksize / (key_size + ptr_size);
>  	ret = 0;
>  out:
>  	free(toktag);
> @@ -238,12 +271,12 @@ report(
>  	char			*tag,
>  	unsigned int		report_what,
>  	unsigned long long	nr_records,
> -	unsigned int		blocksize)
> +	int			blocksize)
>  {
>  	unsigned int		records_per_block[2];
>  	int			ret;
>  
> -	ret = construct_records_per_block(tag, blocksize, records_per_block);
> +	ret = construct_records_per_block(tag, &blocksize, records_per_block);
>  	if (ret)
>  		return;
>  
> @@ -302,7 +335,7 @@ btheight_f(
>  	int		argc,
>  	char		**argv)
>  {
> -	long long	blocksize = mp->m_sb.sb_blocksize;
> +	long long	blocksize = -1;
>  	uint64_t	nr_records = 0;
>  	int		report_what = REPORT_DEFAULT;
>  	int		i, c;
> @@ -355,7 +388,7 @@ _("The largest block size this command will consider is %u bytes.\n"),
>  		return 0;
>  	}
>  
> -	if (blocksize < 128) {
> +	if (blocksize >= 0 && blocksize < 128) {
>  		fprintf(stderr,
>  _("The smallest block size this command will consider is 128 bytes.\n"));
>  		return 0;
>
Darrick J. Wong Sept. 26, 2019, 5:40 p.m. UTC | #2
On Thu, Sep 26, 2019 at 11:20:42AM +0200, Carlos Maiolino wrote:
> On Wed, Sep 25, 2019 at 02:40:59PM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> > 
> > (Ab)use the btheight command to calculate the geometry of the incore
> > extent tree.
> > 
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  db/btheight.c |   87 +++++++++++++++++++++++++++++++++++++++------------------
> >  1 file changed, 60 insertions(+), 27 deletions(-)
> > 
> > 
> > diff --git a/db/btheight.c b/db/btheight.c
> > index e2c9759f..be604ebc 100644
> > --- a/db/btheight.c
> > +++ b/db/btheight.c
> > @@ -22,18 +22,37 @@ static int rmap_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
> >  	return libxfs_rmapbt_maxrecs(blocklen, leaf);
> >  }
> >  
> > +static int iext_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
> > +{
> > +	blocklen -= 2 * sizeof(void *);
> > +
> > +	return blocklen / sizeof(struct xfs_bmbt_rec);
> > +}
> > +
> > +static int disk_blocksize(struct xfs_mount *mp)
> 
> This naming looks confusing to me, disk_blocksize sounds to me like
> 'sector size', maybe fs_blocksize() or get_fs_blocksize()?

Fixed.

--D

> > +{
> > +	return mp->m_sb.sb_blocksize;
> > +}
> > +
> 
> Otherwise looks good.
> 
> 
> > +static int iext_blocksize(struct xfs_mount *mp)
> > +{
> > +	return 256;
> > +}
> > +
> >  struct btmap {
> >  	const char	*tag;
> >  	int		(*maxrecs)(struct xfs_mount *mp, int blocklen,
> >  				   int leaf);
> > +	int		(*default_blocksize)(struct xfs_mount *mp);
> >  } maps[] = {
> > -	{"bnobt", libxfs_allocbt_maxrecs},
> > -	{"cntbt", libxfs_allocbt_maxrecs},
> > -	{"inobt", libxfs_inobt_maxrecs},
> > -	{"finobt", libxfs_inobt_maxrecs},
> > -	{"bmapbt", libxfs_bmbt_maxrecs},
> > -	{"refcountbt", refc_maxrecs},
> > -	{"rmapbt", rmap_maxrecs},
> > +	{"bnobt", libxfs_allocbt_maxrecs, disk_blocksize},
> > +	{"cntbt", libxfs_allocbt_maxrecs, disk_blocksize},
> > +	{"inobt", libxfs_inobt_maxrecs, disk_blocksize},
> > +	{"finobt", libxfs_inobt_maxrecs, disk_blocksize},
> > +	{"bmapbt", libxfs_bmbt_maxrecs, disk_blocksize},
> > +	{"refcountbt", refc_maxrecs, disk_blocksize},
> > +	{"rmapbt", rmap_maxrecs, disk_blocksize},
> > +	{"iext", iext_maxrecs, iext_blocksize},
> >  };
> >  
> >  static void
> > @@ -108,7 +127,7 @@ calc_height(
> >  static int
> >  construct_records_per_block(
> >  	char		*tag,
> > -	int		blocksize,
> > +	int		*blocksize,
> >  	unsigned int	*records_per_block)
> >  {
> >  	char		*toktag;
> > @@ -119,8 +138,10 @@ construct_records_per_block(
> >  
> >  	for (i = 0, m = maps; i < ARRAY_SIZE(maps); i++, m++) {
> >  		if (!strcmp(m->tag, tag)) {
> > -			records_per_block[0] = m->maxrecs(mp, blocksize, 1);
> > -			records_per_block[1] = m->maxrecs(mp, blocksize, 0);
> > +			if (*blocksize < 0)
> > +				*blocksize = m->default_blocksize(mp);
> > +			records_per_block[0] = m->maxrecs(mp, *blocksize, 1);
> > +			records_per_block[1] = m->maxrecs(mp, *blocksize, 0);
> >  			return 0;
> >  		}
> >  	}
> > @@ -178,38 +199,50 @@ construct_records_per_block(
> >  		fprintf(stderr, _("%s: header type not found.\n"), tag);
> >  		goto out;
> >  	}
> > -	if (!strcmp(p, "short"))
> > +	if (!strcmp(p, "short")) {
> > +		if (*blocksize < 0)
> > +			*blocksize = mp->m_sb.sb_blocksize;
> >  		blocksize -= XFS_BTREE_SBLOCK_LEN;
> > -	else if (!strcmp(p, "shortcrc"))
> > +	} else if (!strcmp(p, "shortcrc")) {
> > +		if (*blocksize < 0)
> > +			*blocksize = mp->m_sb.sb_blocksize;
> >  		blocksize -= XFS_BTREE_SBLOCK_CRC_LEN;
> > -	else if (!strcmp(p, "long"))
> > +	} else if (!strcmp(p, "long")) {
> > +		if (*blocksize < 0)
> > +			*blocksize = mp->m_sb.sb_blocksize;
> >  		blocksize -= XFS_BTREE_LBLOCK_LEN;
> > -	else if (!strcmp(p, "longcrc"))
> > +	} else if (!strcmp(p, "longcrc")) {
> > +		if (*blocksize < 0)
> > +			*blocksize = mp->m_sb.sb_blocksize;
> >  		blocksize -= XFS_BTREE_LBLOCK_CRC_LEN;
> > -	else {
> > +	} else if (!strcmp(p, "iext")) {
> > +		if (*blocksize < 0)
> > +			*blocksize = 256;
> > +		blocksize -= 2 * sizeof(void *);
> > +	} else {
> >  		fprintf(stderr, _("%s: unrecognized btree header type."),
> >  				p);
> >  		goto out;
> >  	}
> >  
> > -	if (record_size > blocksize) {
> > +	if (record_size > *blocksize) {
> >  		fprintf(stderr,
> >  			_("%s: record size must be less than %u bytes.\n"),
> > -			tag, blocksize);
> > +			tag, *blocksize);
> >  		goto out;
> >  	}
> >  
> > -	if (key_size > blocksize) {
> > +	if (key_size > *blocksize) {
> >  		fprintf(stderr,
> >  			_("%s: key size must be less than %u bytes.\n"),
> > -			tag, blocksize);
> > +			tag, *blocksize);
> >  		goto out;
> >  	}
> >  
> > -	if (ptr_size > blocksize) {
> > +	if (ptr_size > *blocksize) {
> >  		fprintf(stderr,
> >  			_("%s: pointer size must be less than %u bytes.\n"),
> > -			tag, blocksize);
> > +			tag, *blocksize);
> >  		goto out;
> >  	}
> >  
> > @@ -221,8 +254,8 @@ construct_records_per_block(
> >  		goto out;
> >  	}
> >  
> > -	records_per_block[0] = blocksize / record_size;
> > -	records_per_block[1] = blocksize / (key_size + ptr_size);
> > +	records_per_block[0] = *blocksize / record_size;
> > +	records_per_block[1] = *blocksize / (key_size + ptr_size);
> >  	ret = 0;
> >  out:
> >  	free(toktag);
> > @@ -238,12 +271,12 @@ report(
> >  	char			*tag,
> >  	unsigned int		report_what,
> >  	unsigned long long	nr_records,
> > -	unsigned int		blocksize)
> > +	int			blocksize)
> >  {
> >  	unsigned int		records_per_block[2];
> >  	int			ret;
> >  
> > -	ret = construct_records_per_block(tag, blocksize, records_per_block);
> > +	ret = construct_records_per_block(tag, &blocksize, records_per_block);
> >  	if (ret)
> >  		return;
> >  
> > @@ -302,7 +335,7 @@ btheight_f(
> >  	int		argc,
> >  	char		**argv)
> >  {
> > -	long long	blocksize = mp->m_sb.sb_blocksize;
> > +	long long	blocksize = -1;
> >  	uint64_t	nr_records = 0;
> >  	int		report_what = REPORT_DEFAULT;
> >  	int		i, c;
> > @@ -355,7 +388,7 @@ _("The largest block size this command will consider is %u bytes.\n"),
> >  		return 0;
> >  	}
> >  
> > -	if (blocksize < 128) {
> > +	if (blocksize >= 0 && blocksize < 128) {
> >  		fprintf(stderr,
> >  _("The smallest block size this command will consider is 128 bytes.\n"));
> >  		return 0;
> > 
> 
> -- 
> Carlos
>
Dave Chinner Sept. 26, 2019, 9:41 p.m. UTC | #3
On Wed, Sep 25, 2019 at 02:40:59PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> (Ab)use the btheight command to calculate the geometry of the incore
> extent tree.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  db/btheight.c |   87 +++++++++++++++++++++++++++++++++++++++------------------
>  1 file changed, 60 insertions(+), 27 deletions(-)
> 
> 
> diff --git a/db/btheight.c b/db/btheight.c
> index e2c9759f..be604ebc 100644
> --- a/db/btheight.c
> +++ b/db/btheight.c
> @@ -22,18 +22,37 @@ static int rmap_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
>  	return libxfs_rmapbt_maxrecs(blocklen, leaf);
>  }
>  
> +static int iext_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
> +{
> +	blocklen -= 2 * sizeof(void *);
> +
> +	return blocklen / sizeof(struct xfs_bmbt_rec);
> +}

This isn't correct for the iext nodes. They hold 16 key/ptr pairs,
not 15.

I suspect you should be lifting the iext btree format definitions
like this one:

enum {                                                                           
        NODE_SIZE       = 256,                                                   
        KEYS_PER_NODE   = NODE_SIZE / (sizeof(uint64_t) + sizeof(void *)),       
        RECS_PER_LEAF   = (NODE_SIZE - (2 * sizeof(struct xfs_iext_leaf *))) /   
                                sizeof(struct xfs_iext_rec),                     
};                                                                               

from libxfs/xfs_iext_tree.c to a libxfs header file and then using
KEYS_PER_NODE and RECS_PER_LEAF here. See the patch below, lifted
from a varaint of my range locking prototypes...

However, these are not on-disk values and so are subject to change,
hence it may be that a warning might be needed when xfs_db is used
to calculate the height of this tree.

> +static int disk_blocksize(struct xfs_mount *mp)
> +{
> +	return mp->m_sb.sb_blocksize;
> +}
> +
> +static int iext_blocksize(struct xfs_mount *mp)
> +{
> +	return 256;
> +}

NODE_SIZE....

Cheers,

Dave.
Darrick J. Wong Sept. 27, 2019, 2:58 a.m. UTC | #4
On Fri, Sep 27, 2019 at 07:41:02AM +1000, Dave Chinner wrote:
> On Wed, Sep 25, 2019 at 02:40:59PM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> > 
> > (Ab)use the btheight command to calculate the geometry of the incore
> > extent tree.
> > 
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  db/btheight.c |   87 +++++++++++++++++++++++++++++++++++++++------------------
> >  1 file changed, 60 insertions(+), 27 deletions(-)
> > 
> > 
> > diff --git a/db/btheight.c b/db/btheight.c
> > index e2c9759f..be604ebc 100644
> > --- a/db/btheight.c
> > +++ b/db/btheight.c
> > @@ -22,18 +22,37 @@ static int rmap_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
> >  	return libxfs_rmapbt_maxrecs(blocklen, leaf);
> >  }
> >  
> > +static int iext_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
> > +{
> > +	blocklen -= 2 * sizeof(void *);
> > +
> > +	return blocklen / sizeof(struct xfs_bmbt_rec);
> > +}
> 
> This isn't correct for the iext nodes. They hold 16 key/ptr pairs,
> not 15.
> 
> I suspect you should be lifting the iext btree format definitions
> like this one:
> 
> enum {                                                                           
>         NODE_SIZE       = 256,                                                   
>         KEYS_PER_NODE   = NODE_SIZE / (sizeof(uint64_t) + sizeof(void *)),       
>         RECS_PER_LEAF   = (NODE_SIZE - (2 * sizeof(struct xfs_iext_leaf *))) /   
>                                 sizeof(struct xfs_iext_rec),                     
> };                                                                               
> 
> from libxfs/xfs_iext_tree.c to a libxfs header file and then using
> KEYS_PER_NODE and RECS_PER_LEAF here. See the patch below, lifted
> from a varaint of my range locking prototypes...
> 
> However, these are not on-disk values and so are subject to change,
> hence it may be that a warning might be needed when xfs_db is used
> to calculate the height of this tree.

Er... I don't mind lifting the iext values, but I don't see a patch?

--D

> > +static int disk_blocksize(struct xfs_mount *mp)
> > +{
> > +	return mp->m_sb.sb_blocksize;
> > +}
> > +
> > +static int iext_blocksize(struct xfs_mount *mp)
> > +{
> > +	return 256;
> > +}
> 
> NODE_SIZE....
> 
> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com
Dave Chinner Sept. 27, 2019, 10:08 p.m. UTC | #5
On Thu, Sep 26, 2019 at 07:58:57PM -0700, Darrick J. Wong wrote:
> On Fri, Sep 27, 2019 at 07:41:02AM +1000, Dave Chinner wrote:
> > On Wed, Sep 25, 2019 at 02:40:59PM -0700, Darrick J. Wong wrote:
> > > From: Darrick J. Wong <darrick.wong@oracle.com>
> > > 
> > > (Ab)use the btheight command to calculate the geometry of the incore
> > > extent tree.
> > > 
> > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > > ---
> > >  db/btheight.c |   87 +++++++++++++++++++++++++++++++++++++++------------------
> > >  1 file changed, 60 insertions(+), 27 deletions(-)
> > > 
> > > 
> > > diff --git a/db/btheight.c b/db/btheight.c
> > > index e2c9759f..be604ebc 100644
> > > --- a/db/btheight.c
> > > +++ b/db/btheight.c
> > > @@ -22,18 +22,37 @@ static int rmap_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
> > >  	return libxfs_rmapbt_maxrecs(blocklen, leaf);
> > >  }
> > >  
> > > +static int iext_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
> > > +{
> > > +	blocklen -= 2 * sizeof(void *);
> > > +
> > > +	return blocklen / sizeof(struct xfs_bmbt_rec);
> > > +}
> > 
> > This isn't correct for the iext nodes. They hold 16 key/ptr pairs,
> > not 15.
> > 
> > I suspect you should be lifting the iext btree format definitions
> > like this one:
> > 
> > enum {                                                                           
> >         NODE_SIZE       = 256,                                                   
> >         KEYS_PER_NODE   = NODE_SIZE / (sizeof(uint64_t) + sizeof(void *)),       
> >         RECS_PER_LEAF   = (NODE_SIZE - (2 * sizeof(struct xfs_iext_leaf *))) /   
> >                                 sizeof(struct xfs_iext_rec),                     
> > };                                                                               
> > 
> > from libxfs/xfs_iext_tree.c to a libxfs header file and then using
> > KEYS_PER_NODE and RECS_PER_LEAF here. See the patch below, lifted
> > from a varaint of my range locking prototypes...
> > 
> > However, these are not on-disk values and so are subject to change,
> > hence it may be that a warning might be needed when xfs_db is used
> > to calculate the height of this tree.
> 
> Er... I don't mind lifting the iext values, but I don't see a patch?

Ah, sorry, I realised it wouldn't apply at all - there's several
precursor patches that move stuff about (reworking the xfs_ifork
structure) and it didn't lift the enum (but could have) and so I
didn't attach it.  Of course, I then forgot to edit email... I'll
attach it anyway...

Cheers,

Dave.
Christoph Hellwig Sept. 30, 2019, 7:58 a.m. UTC | #6
On Fri, Sep 27, 2019 at 07:41:02AM +1000, Dave Chinner wrote:
> > +static int iext_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
> > +{
> > +	blocklen -= 2 * sizeof(void *);
> > +
> > +	return blocklen / sizeof(struct xfs_bmbt_rec);
> > +}
> 
> This isn't correct for the iext nodes. They hold 16 key/ptr pairs,
> not 15.
> 
> I suspect you should be lifting the iext btree format definitions
> like this one:

Is the command supposed to deal with the on-disk or in-memory nodes?
The ones your quote are the in-memory btrees, but the file seems
(the way I read it, the documentation seems to be lacking) with the
on-disk btrees.
Darrick J. Wong Sept. 30, 2019, 4:11 p.m. UTC | #7
On Mon, Sep 30, 2019 at 12:58:54AM -0700, Christoph Hellwig wrote:
> On Fri, Sep 27, 2019 at 07:41:02AM +1000, Dave Chinner wrote:
> > > +static int iext_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
> > > +{
> > > +	blocklen -= 2 * sizeof(void *);
> > > +
> > > +	return blocklen / sizeof(struct xfs_bmbt_rec);
> > > +}
> > 
> > This isn't correct for the iext nodes. They hold 16 key/ptr pairs,
> > not 15.
> > 
> > I suspect you should be lifting the iext btree format definitions
> > like this one:
> 
> Is the command supposed to deal with the on-disk or in-memory nodes?
> The ones your quote are the in-memory btrees, but the file seems
> (the way I read it, the documentation seems to be lacking) with the
> on-disk btrees.

It started as a command for calculating ondisk btree geometry but then
we were discussing the iext tree geometry on irc so I extended it to
handle that too.

(Ugh, where /did/ the documentation go...)

--D
Christoph Hellwig Oct. 1, 2019, 6:24 a.m. UTC | #8
On Mon, Sep 30, 2019 at 09:11:52AM -0700, Darrick J. Wong wrote:
> > Is the command supposed to deal with the on-disk or in-memory nodes?
> > The ones your quote are the in-memory btrees, but the file seems
> > (the way I read it, the documentation seems to be lacking) with the
> > on-disk btrees.
> 
> It started as a command for calculating ondisk btree geometry but then
> we were discussing the iext tree geometry on irc so I extended it to
> handle that too.

I think mixing the on-disk trees an an in-memory structure in the same
command is a really bad idea.  In fact I'm not sure what use the
calculation for the iext tree is.  It is an implementation detail that
can (and did) change from release to release, unlike the other trees
that not going to change without an on-disk format change.
diff mbox series

Patch

diff --git a/db/btheight.c b/db/btheight.c
index e2c9759f..be604ebc 100644
--- a/db/btheight.c
+++ b/db/btheight.c
@@ -22,18 +22,37 @@  static int rmap_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
 	return libxfs_rmapbt_maxrecs(blocklen, leaf);
 }
 
+static int iext_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
+{
+	blocklen -= 2 * sizeof(void *);
+
+	return blocklen / sizeof(struct xfs_bmbt_rec);
+}
+
+static int disk_blocksize(struct xfs_mount *mp)
+{
+	return mp->m_sb.sb_blocksize;
+}
+
+static int iext_blocksize(struct xfs_mount *mp)
+{
+	return 256;
+}
+
 struct btmap {
 	const char	*tag;
 	int		(*maxrecs)(struct xfs_mount *mp, int blocklen,
 				   int leaf);
+	int		(*default_blocksize)(struct xfs_mount *mp);
 } maps[] = {
-	{"bnobt", libxfs_allocbt_maxrecs},
-	{"cntbt", libxfs_allocbt_maxrecs},
-	{"inobt", libxfs_inobt_maxrecs},
-	{"finobt", libxfs_inobt_maxrecs},
-	{"bmapbt", libxfs_bmbt_maxrecs},
-	{"refcountbt", refc_maxrecs},
-	{"rmapbt", rmap_maxrecs},
+	{"bnobt", libxfs_allocbt_maxrecs, disk_blocksize},
+	{"cntbt", libxfs_allocbt_maxrecs, disk_blocksize},
+	{"inobt", libxfs_inobt_maxrecs, disk_blocksize},
+	{"finobt", libxfs_inobt_maxrecs, disk_blocksize},
+	{"bmapbt", libxfs_bmbt_maxrecs, disk_blocksize},
+	{"refcountbt", refc_maxrecs, disk_blocksize},
+	{"rmapbt", rmap_maxrecs, disk_blocksize},
+	{"iext", iext_maxrecs, iext_blocksize},
 };
 
 static void
@@ -108,7 +127,7 @@  calc_height(
 static int
 construct_records_per_block(
 	char		*tag,
-	int		blocksize,
+	int		*blocksize,
 	unsigned int	*records_per_block)
 {
 	char		*toktag;
@@ -119,8 +138,10 @@  construct_records_per_block(
 
 	for (i = 0, m = maps; i < ARRAY_SIZE(maps); i++, m++) {
 		if (!strcmp(m->tag, tag)) {
-			records_per_block[0] = m->maxrecs(mp, blocksize, 1);
-			records_per_block[1] = m->maxrecs(mp, blocksize, 0);
+			if (*blocksize < 0)
+				*blocksize = m->default_blocksize(mp);
+			records_per_block[0] = m->maxrecs(mp, *blocksize, 1);
+			records_per_block[1] = m->maxrecs(mp, *blocksize, 0);
 			return 0;
 		}
 	}
@@ -178,38 +199,50 @@  construct_records_per_block(
 		fprintf(stderr, _("%s: header type not found.\n"), tag);
 		goto out;
 	}
-	if (!strcmp(p, "short"))
+	if (!strcmp(p, "short")) {
+		if (*blocksize < 0)
+			*blocksize = mp->m_sb.sb_blocksize;
 		blocksize -= XFS_BTREE_SBLOCK_LEN;
-	else if (!strcmp(p, "shortcrc"))
+	} else if (!strcmp(p, "shortcrc")) {
+		if (*blocksize < 0)
+			*blocksize = mp->m_sb.sb_blocksize;
 		blocksize -= XFS_BTREE_SBLOCK_CRC_LEN;
-	else if (!strcmp(p, "long"))
+	} else if (!strcmp(p, "long")) {
+		if (*blocksize < 0)
+			*blocksize = mp->m_sb.sb_blocksize;
 		blocksize -= XFS_BTREE_LBLOCK_LEN;
-	else if (!strcmp(p, "longcrc"))
+	} else if (!strcmp(p, "longcrc")) {
+		if (*blocksize < 0)
+			*blocksize = mp->m_sb.sb_blocksize;
 		blocksize -= XFS_BTREE_LBLOCK_CRC_LEN;
-	else {
+	} else if (!strcmp(p, "iext")) {
+		if (*blocksize < 0)
+			*blocksize = 256;
+		blocksize -= 2 * sizeof(void *);
+	} else {
 		fprintf(stderr, _("%s: unrecognized btree header type."),
 				p);
 		goto out;
 	}
 
-	if (record_size > blocksize) {
+	if (record_size > *blocksize) {
 		fprintf(stderr,
 			_("%s: record size must be less than %u bytes.\n"),
-			tag, blocksize);
+			tag, *blocksize);
 		goto out;
 	}
 
-	if (key_size > blocksize) {
+	if (key_size > *blocksize) {
 		fprintf(stderr,
 			_("%s: key size must be less than %u bytes.\n"),
-			tag, blocksize);
+			tag, *blocksize);
 		goto out;
 	}
 
-	if (ptr_size > blocksize) {
+	if (ptr_size > *blocksize) {
 		fprintf(stderr,
 			_("%s: pointer size must be less than %u bytes.\n"),
-			tag, blocksize);
+			tag, *blocksize);
 		goto out;
 	}
 
@@ -221,8 +254,8 @@  construct_records_per_block(
 		goto out;
 	}
 
-	records_per_block[0] = blocksize / record_size;
-	records_per_block[1] = blocksize / (key_size + ptr_size);
+	records_per_block[0] = *blocksize / record_size;
+	records_per_block[1] = *blocksize / (key_size + ptr_size);
 	ret = 0;
 out:
 	free(toktag);
@@ -238,12 +271,12 @@  report(
 	char			*tag,
 	unsigned int		report_what,
 	unsigned long long	nr_records,
-	unsigned int		blocksize)
+	int			blocksize)
 {
 	unsigned int		records_per_block[2];
 	int			ret;
 
-	ret = construct_records_per_block(tag, blocksize, records_per_block);
+	ret = construct_records_per_block(tag, &blocksize, records_per_block);
 	if (ret)
 		return;
 
@@ -302,7 +335,7 @@  btheight_f(
 	int		argc,
 	char		**argv)
 {
-	long long	blocksize = mp->m_sb.sb_blocksize;
+	long long	blocksize = -1;
 	uint64_t	nr_records = 0;
 	int		report_what = REPORT_DEFAULT;
 	int		i, c;
@@ -355,7 +388,7 @@  _("The largest block size this command will consider is %u bytes.\n"),
 		return 0;
 	}
 
-	if (blocksize < 128) {
+	if (blocksize >= 0 && blocksize < 128) {
 		fprintf(stderr,
 _("The smallest block size this command will consider is 128 bytes.\n"));
 		return 0;