From 1f1b8be7926480046ead7b98c9850ace7bcd82a3 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Tue, 28 Oct 2003 04:41:37 +0000 Subject: [PATCH] Rework the mkfs allocation group sizing algorithm, making better use of the available bits. This changes the maximum allocation group size enforced by mkfs to be 1TB (from 4GB), which scales alot better for very large filesystems. --- VERSION | 6 +- debian/changelog | 7 ++ doc/CHANGES | 4 + include/xfs_ag.h | 36 +------ mkfs/xfs_mkfs.c | 267 +++++++++++++++++++++++++---------------------- 5 files changed, 160 insertions(+), 160 deletions(-) diff --git a/VERSION b/VERSION index a3d0348fa..b62db7f4a 100644 --- a/VERSION +++ b/VERSION @@ -2,6 +2,6 @@ # This file is used by configure to get version information # PKG_MAJOR=2 -PKG_MINOR=5 -PKG_REVISION=11 -PKG_BUILD=1 +PKG_MINOR=6 +PKG_REVISION=0 +PKG_BUILD=0 diff --git a/debian/changelog b/debian/changelog index 12775c4dc..abb851c87 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +xfsprogs (2.6.0-1) unstable; urgency=low + + * New upstream release. + * Note: change in the mkfs algorithm for sizing allocation groups. + + -- Nathan Scott Tue, 28 Oct 2003 15:23:48 +1100 + xfsprogs (2.5.11-1) unstable; urgency=low * New upstream release. diff --git a/doc/CHANGES b/doc/CHANGES index 6971404be..86747ad8b 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -1,3 +1,7 @@ +xfsprogs-2.6.0 (28 October 2003) + - Change to mkfs strategy for allocation group count and size + default. Scales significantly better for large filesystems. + xfsprogs-2.5.11 (10 October 2003) - Incorporate Jan Derfinaks change to the Linux block ioctls used in libxfs, allowing this code to compile cleanly with diff --git a/include/xfs_ag.h b/include/xfs_ag.h index 58893e32e..1b302a200 100644 --- a/include/xfs_ag.h +++ b/include/xfs_ag.h @@ -230,38 +230,12 @@ typedef struct xfs_perag xfs_perag_busy_t *pagb_list; /* unstable blocks */ } xfs_perag_t; -#define XFS_AG_MIN_BYTES (1LL << 24) /* 16 MB */ -#define XFS_AG_BEST_BYTES (1LL << 30) /* 1 GB */ -#define XFS_AG_MAX_BYTES (1LL << 32) /* 4 GB */ +#define XFS_AG_BYTES(bblog) ((long long)BBSIZE << (bblog)) +#define XFS_AG_MIN_BYTES ((XFS_AG_BYTES(15))) /* 16 MB */ +#define XFS_AG_MIN_BLOCKS(blog) ((XFS_AG_BYTES(15)) >> (blog)) +#define XFS_AG_MAX_BLOCKS(blog) ((XFS_AG_BYTES(31) - 1) >> (blog)) -#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MIN_BLOCKS) -xfs_extlen_t xfs_ag_min_blocks(int bl); -#define XFS_AG_MIN_BLOCKS(bl) xfs_ag_min_blocks(bl) -#else -#define XFS_AG_MIN_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_MIN_BYTES >> bl)) -#endif -#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_BEST_BLOCKS) -xfs_extlen_t xfs_ag_best_blocks(int bl, xfs_drfsbno_t blks); -#define XFS_AG_BEST_BLOCKS(bl,blks) xfs_ag_best_blocks(bl,blks) -#else -/*--#define XFS_AG_BEST_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_BEST_BYTES >> bl))*/ -/* - * Best is XFS_AG_BEST_BLOCKS at and below 64 Gigabyte filesystems, and - * XFS_AG_MAX_BLOCKS above 64 Gigabytes. - */ -#define XFS_AG_BEST_BLOCKS(bl,blks) \ - ((xfs_extlen_t)((1LL << (36 - bl)) >= blks) ? \ - ((xfs_extlen_t)(XFS_AG_BEST_BYTES >> bl)) : \ - XFS_AG_MAX_BLOCKS(bl)) -#endif -#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MAX_BLOCKS) -xfs_extlen_t xfs_ag_max_blocks(int bl); -#define XFS_AG_MAX_BLOCKS(bl) xfs_ag_max_blocks(bl) -#else -#define XFS_AG_MAX_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_MAX_BYTES >> bl)) -#endif - -#define XFS_MAX_AGNUMBER ((xfs_agnumber_t)(NULLAGNUMBER - 1)) +#define XFS_MAX_AGNUMBER ((xfs_agnumber_t)(NULLAGNUMBER - 1)) #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MAXLEVELS) int xfs_ag_maxlevels(struct xfs_mount *mp); diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 7a7768542..01e8ba8da 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -166,6 +166,10 @@ char *sopts[] = { NULL }; +#define TERABYTES(count, blog) ((__uint64_t)(count) << (40 - (blog))) +#define GIGABYTES(count, blog) ((__uint64_t)(count) << (30 - (blog))) +#define MEGABYTES(count, blog) ((__uint64_t)(count) << (20 - (blog))) + /* * Use this macro before we have superblock and mount structure */ @@ -336,6 +340,136 @@ fixup_log_stripe( return logstart; } +void +calc_default_ag_geometry( + int blocklog, + __uint64_t dblocks, + __uint64_t *agsize, + __uint64_t *agcount) +{ + __uint64_t blocks; + __uint64_t count = 0; + int shift = 0; + + /* + * First handle the extremes - the points at which we will + * always use the maximum AG size, the points at which we + * always use the minimum, and a "small-step" for 16-128Mb. + */ + if (dblocks >= TERABYTES(64, blocklog)) { + blocks = XFS_AG_MAX_BLOCKS(blocklog); + goto done; + } else if (dblocks < MEGABYTES(16, blocklog)) { + blocks = dblocks; + count = 1; + goto done; + } else if (dblocks < MEGABYTES(128, blocklog)) { + blocks = MEGABYTES(16, blocklog); + goto done; + } + + /* + * For the remainder we choose an AG size based on the + * number of data blocks available, trying to keep the + * number of AGs relatively small (especially compared + * to the original algorithm). AG count is calculated + * based on the prefered AG size, not vice-versa - the + * count can be increased by growfs, so prefer to use + * smaller counts at mkfs time. + * + * This scales us up smoothly between min/max AG sizes. + */ + if (dblocks > GIGABYTES(512, blocklog)) + shift = 5; + else if (dblocks > GIGABYTES(8, blocklog)) + shift = 4; + else if (dblocks >= MEGABYTES(128, blocklog)) + shift = 3; + else + ASSERT(0); + blocks = dblocks >> shift; + +done: + if (!count) + count = dblocks / blocks + (dblocks % blocks != 0); + *agsize = blocks; + *agcount = count; +} + +static void +validate_ag_geometry( + int blocklog, + __uint64_t dblocks, + __uint64_t agsize, + __uint64_t agcount) +{ + if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) { + fprintf(stderr, + _("agsize (%lldb) too small, need at least %lld blocks\n"), + (long long)agsize, + (long long)XFS_AG_MIN_BLOCKS(blocklog)); + usage(); + } + + if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) { + fprintf(stderr, + _("agsize (%lldb) too big, maximum is %lld blocks\n"), + (long long)agsize, + (long long)XFS_AG_MAX_BLOCKS(blocklog)); + usage(); + } + + if (agsize > dblocks) { + fprintf(stderr, + _("agsize (%lldb) too big, data area is %lld blocks\n"), + (long long)agsize, (long long)dblocks); + usage(); + } + + if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) { + fprintf(stderr, + _("too many allocation groups for size = %lld\n"), + (long long)agsize); + fprintf(stderr, _("need at most %lld allocation groups\n"), + (long long)(dblocks / XFS_AG_MIN_BLOCKS(blocklog) + + (dblocks % XFS_AG_MIN_BLOCKS(blocklog) != 0))); + usage(); + } + + if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) { + fprintf(stderr, + _("too few allocation groups for size = %lld\n"), (long long)agsize); + fprintf(stderr, + _("need at least %lld allocation groups\n"), + (long long)(dblocks / XFS_AG_MAX_BLOCKS(blocklog) + + (dblocks % XFS_AG_MAX_BLOCKS(blocklog) != 0))); + usage(); + } + + /* + * If the last AG is too small, reduce the filesystem size + * and drop the blocks. + */ + if ( dblocks % agsize != 0 && + (dblocks % agsize < XFS_AG_MIN_BLOCKS(blocklog))) { + fprintf(stderr, + _("last AG size %lld blocks too small, minimum size is %lld blocks\n"), + (long long)(dblocks % agsize), + (long long)XFS_AG_MIN_BLOCKS(blocklog)); + usage(); + } + + /* + * If agcount is too large, make it smaller. + */ + if (agcount > XFS_MAX_AGNUMBER + 1) { + fprintf(stderr, + _("%lld allocation groups is too many, maximum is %lld\n"), + (long long)agcount, (long long)XFS_MAX_AGNUMBER + 1); + usage(); + } +} + int main( int argc, @@ -436,7 +570,6 @@ main( bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); - agcount = 8; blflag = bsflag = slflag = ssflag = lslflag = lssflag = 0; blocklog = blocksize = 0; sectorlog = lsectorlog = XFS_MIN_SECTORSIZE_LOG; @@ -1131,9 +1264,6 @@ main( usage(); } - if (!daflag) - agcount = 8; - if (xi.disfile && (!dsize || !xi.dname)) { fprintf(stderr, _("if -d file then -d name and -d size are required\n")); @@ -1483,10 +1613,9 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"), nbmblocks = 0; } - if (dasize) { + if (dasize) { /* User-specified AG size */ /* - * If the specified agsize isn't a multiple of fs blks, - * complain. + * Check specified agsize is a multiple of blocksize. */ if (agsize % blocksize) { fprintf(stderr, @@ -1494,86 +1623,13 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"), (long long)agsize, blocksize); usage(); } - agsize /= blocksize; - - /* - * If the specified agsize is too small, or too large, - * complain. - */ - if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) { - fprintf(stderr, - _("agsize (%lldb) too small, need at least %lld blocks\n"), - (long long)agsize, - (long long)XFS_AG_MIN_BLOCKS(blocklog)); - usage(); - } - - if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) { - fprintf(stderr, - _("agsize (%lldb) too big, maximum is %lld blocks\n"), - (long long)agsize, - (long long)XFS_AG_MAX_BLOCKS(blocklog)); - usage(); - } - - if (agsize > dblocks) { - fprintf(stderr, - _("agsize (%lldb) too big, data area is %lld blocks\n"), - (long long)agsize, (long long)dblocks); - usage(); - } - agcount = dblocks / agsize + (dblocks % agsize != 0); - } else { - agsize = dblocks / agcount + (dblocks % agcount != 0); - } - - /* - * If the ag size is too small, complain if agcount/agsize was - * specified, and fix it otherwise. - */ - if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) { - if (daflag || dasize) { - fprintf(stderr, - _("too many allocation groups for size = %lld\n"), - (long long)agsize); - fprintf(stderr, - _("need at most %lld allocation groups\n"), - (long long) - (dblocks / XFS_AG_MIN_BLOCKS(blocklog) + - (dblocks % XFS_AG_MIN_BLOCKS(blocklog) != 0))); - usage(); - } - agsize = XFS_AG_MIN_BLOCKS(blocklog); - if (dblocks < agsize) { - agcount = 1; - agsize = dblocks; - } else { - agcount = dblocks / agsize; - agsize = dblocks / agcount +(dblocks % agcount != 0); - } - } - /* - * If the ag size is too large, complain if agcount/agsize was - * specified, and fix it otherwise. - */ - else if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) { - if (daflag || dasize) { - fprintf(stderr, - _("too few allocation groups for size = %lld\n"), - (long long)agsize); - fprintf(stderr, - _("need at least %lld allocation groups\n"), - (long long) - (dblocks / XFS_AG_MAX_BLOCKS(blocklog) + - (dblocks % XFS_AG_MAX_BLOCKS(blocklog) != 0))); - usage(); - } - agsize = XFS_AG_MAX_BLOCKS(blocklog); - agcount = dblocks / agsize + (dblocks % agsize != 0); - } + } else if (daflag) /* User-specified AG size */ + agsize = dblocks / agcount + (dblocks % agcount != 0); + else + calc_default_ag_geometry(blocklog, dblocks, &agsize, &agcount); /* * If the last AG is too small, reduce the filesystem size @@ -1586,48 +1642,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"), ASSERT(agcount != 0); } - /* - * If agcount was not specified, and agsize is larger than - * we'd like, make it the size we want. - */ - if (!daflag && !dasize && - (agsize > XFS_AG_BEST_BLOCKS(blocklog,dblocks))) { - agsize = XFS_AG_BEST_BLOCKS(blocklog,dblocks); - agcount = dblocks / agsize + (dblocks % agsize != 0); - /* - * If the last AG is too small, reduce the filesystem size - * and drop the blocks. - */ - if ( dblocks % agsize != 0 && - (dblocks % agsize < XFS_AG_MIN_BLOCKS(blocklog))) { - dblocks = (xfs_drfsbno_t)((agcount - 1) * agsize); - agcount--; - ASSERT(agcount != 0); - } - } - - /* - * If agcount is too large, make it smaller. - */ - if (agcount > XFS_MAX_AGNUMBER + 1) { - agcount = XFS_MAX_AGNUMBER + 1; - agsize = dblocks / agcount + (dblocks % agcount != 0); - - if (dasize || daflag) - fprintf(stderr, - _("agsize set to %lld, agcount %lld > max (%lld)\n"), - (long long)agsize, (long long)agcount, - (long long)XFS_MAX_AGNUMBER+1); - - if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) { - /* - * We're confused. - */ - fprintf(stderr, _("%s: can't compute agsize/agcount\n"), - progname); - exit(1); - } - } + validate_ag_geometry(blocklog, dblocks, agsize, agcount); xlv_dsunit = xlv_dswidth = 0; if (!xi.disfile) -- 2.47.2