]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
Rework the mkfs allocation group sizing algorithm, making better use of the available... v2.6.0
authorNathan Scott <nathans@sgi.com>
Tue, 28 Oct 2003 04:41:37 +0000 (04:41 +0000)
committerNathan Scott <nathans@sgi.com>
Tue, 28 Oct 2003 04:41:37 +0000 (04:41 +0000)
VERSION
debian/changelog
doc/CHANGES
include/xfs_ag.h
mkfs/xfs_mkfs.c

diff --git a/VERSION b/VERSION
index a3d0348facfcb6d0902e70d9773663914e9d845d..b62db7f4a0324f0db918ab43bc2dc4ccad86cec3 100644 (file)
--- 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
index 12775c4dcd65bd030c385be4e6ff3101b8b3f836..abb851c8724caa9b2f592ab4c9e9f96d2e8cacb8 100644 (file)
@@ -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 <nathans@debian.org>  Tue, 28 Oct 2003 15:23:48 +1100
+
 xfsprogs (2.5.11-1) unstable; urgency=low
 
   * New upstream release.
index 6971404beda31231860965fa3cba3c18e6f0a82d..86747ad8b78b501eae6fbb81df733cb3e737ec18 100644 (file)
@@ -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
index 58893e32e7c4dea145ee85b6bb72553e9438ef9f..1b302a2000f0c85d53a65b578164e92358f8e672 100644 (file)
@@ -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);
index 7a776854207d16d7a647f8fe717d991311ef8607..01e8ba8dafb1f4725ae84da175c86dc7953e7b64 100644 (file)
@@ -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)