This is an automated email from the git hooks/post-receive script.
andyp pushed a commit to branch RHEL7
in repository gfs2-utils.
commit cc079a4d907eedd24c69ab2a88e9e0fcdef58a5d
Author: Andrew Price <anprice(a)redhat.com>
Date: Mon Feb 12 19:27:48 2018 +0000
mkfs.gfs2: Scale down journal size for smaller devices
Currently the default behaviour when the journal size is not specified
is to use a default size of 128M, which means that mkfs.gfs2 can run out
of space while writing to a small device. The hard default also means
that some xfstests fail with gfs2 as they try to create small file
systems.
This patch addresses these problems by setting sensible default journal
sizes depending on the size of the file system. Journal sizes specified
by the user are limited to half of the fs. As the minimum journal size
is 8MB that means we effectively get a hard minimum file system size of
16MB (per journal).
Resolves: rhbz#1498068
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/libgfs2/libgfs2.h | 2 ++
gfs2/man/mkfs.gfs2.8 | 5 +++--
gfs2/mkfs/main_mkfs.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++--
tests/edit.at | 2 +-
tests/mkfs.at | 10 ++++++++++
tests/testsuite.at | 6 ++++++
6 files changed, 74 insertions(+), 5 deletions(-)
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index ebf6bca..570c89b 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -319,6 +319,8 @@ struct metapath {
#define GFS2_DEFAULT_BSIZE (4096)
#define GFS2_DEFAULT_JSIZE (128)
+#define GFS2_MAX_JSIZE (1024)
+#define GFS2_MIN_JSIZE (8)
#define GFS2_DEFAULT_RGSIZE (256)
#define GFS2_DEFAULT_UTSIZE (1)
#define GFS2_DEFAULT_QCSIZE (1)
diff --git a/gfs2/man/mkfs.gfs2.8 b/gfs2/man/mkfs.gfs2.8
index 342a636..35e355a 100644
--- a/gfs2/man/mkfs.gfs2.8
+++ b/gfs2/man/mkfs.gfs2.8
@@ -32,8 +32,9 @@ Enable debugging output.
Print out a help message describing the available options, then exit.
.TP
\fB-J\fP \fImegabytes\fR
-The size of each journal. The default journal size is 128 megabytes and the
-minimum size is 8 megabytes.
+The size of each journal. The minimum size is 8 megabytes and the maximum is
+1024. If this is not specified, a value based on a sensible proportion of the
+file system will be chosen.
.TP
\fB-j\fP \fIjournals\fR
The number of journals for mkfs.gfs2 to create. At least one journal is
diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c
index 2e08bc6..24e5a85 100644
--- a/gfs2/mkfs/main_mkfs.c
+++ b/gfs2/mkfs/main_mkfs.c
@@ -552,7 +552,7 @@ static void opts_check(struct mkfs_opts *opts)
if (!opts->journals)
die( _("no journals specified\n"));
- if (opts->jsize < 8 || opts->jsize > 1024)
+ if (opts->jsize < GFS2_MIN_JSIZE || opts->jsize > GFS2_MAX_JSIZE)
die( _("bad journal size\n"));
if (!opts->qcsize || opts->qcsize > 64)
@@ -575,6 +575,7 @@ static void print_results(struct gfs2_sb *sb, struct mkfs_opts *opts, uint64_t r
printf("%-27s%.2f %s (%"PRIu64" %s)\n", _("Filesystem size:"),
(fssize / ((float)(1 << 30)) * sb->sb_bsize), _("GB"), fssize, _("blocks"));
printf("%-27s%u\n", _("Journals:"), opts->journals);
+ printf("%-27s%uMB\n", _("Journal size:"), opts->jsize);
printf("%-27s%"PRIu64"\n", _("Resource groups:"), rgrps);
printf("%-27s\"%s\"\n", _("Locking protocol:"), opts->lockproto);
printf("%-27s\"%s\"\n", _("Lock table:"), opts->locktable);
@@ -823,6 +824,36 @@ static int place_rgrps(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts
return 0;
}
+/*
+ * Find a reasonable journal file size (in blocks) given the number of blocks
+ * in the filesystem. For very small filesystems, it is not reasonable to
+ * have a journal that fills more than half of the filesystem.
+ *
+ * n.b. comments assume 4k blocks
+ *
+ * This was copied and adapted from e2fsprogs.
+ */
+static int default_journal_size(unsigned bsize, uint64_t num_blocks)
+{
+ int min_blocks = (GFS2_MIN_JSIZE << 20) / bsize;
+
+ if (num_blocks < 2 * min_blocks)
+ return -1;
+ if (num_blocks < 131072) /* 512 MB */
+ return min_blocks; /* 8 MB */
+ if (num_blocks < 512*1024) /* 2 GB */
+ return (4096); /* 16 MB */
+ if (num_blocks < 2048*1024) /* 8 GB */
+ return (8192); /* 32 MB */
+ if (num_blocks < 4096*1024) /* 16 GB */
+ return (16384); /* 64 MB */
+ if (num_blocks < 262144*1024) /* 1 TB */
+ return (32768); /* 128 MB */
+ if (num_blocks < 2621440*1024) /* 10 TB */
+ return (131072); /* 512 MB */
+ return 262144; /* 1 GB */
+}
+
static void sbd_init(struct gfs2_sbd *sdp, struct mkfs_opts *opts, unsigned bsize)
{
memset(sdp, 0, sizeof(struct gfs2_sbd));
@@ -847,9 +878,28 @@ static void sbd_init(struct gfs2_sbd *sdp, struct mkfs_opts *opts, unsigned bsiz
opts->dev.size / ((float)(1 << 30)), _("GB"),
opts->dev.size / sdp->bsize, _("blocks"));
}
- /* TODO: Check if the fssize is too small, somehow */
sdp->device.length = opts->fssize;
}
+ /* opts->jsize has already been max/min checked but we need to check it
+ makes sense for the device size, or set a sensible default, if one
+ will fit. For user-provided journal sizes, limit it to half of the fs. */
+ if (!opts->got_jsize) {
+ int default_jsize = default_journal_size(sdp->bsize, sdp->device.length / opts->journals);
+ if (default_jsize < 0) {
+ fprintf(stderr, _("gfs2 will not fit on this device.\n"));
+ exit(1);
+ }
+ opts->jsize = (default_jsize * sdp->bsize) >> 20;
+ } else if ((((opts->jsize * opts->journals) << 20) / sdp->bsize) > (sdp->device.length / 2)) {
+ unsigned max_jsize = (sdp->device.length / 2 * sdp->bsize / opts->journals) >> 20;
+
+ fprintf(stderr, _("gfs2 will not fit on this device.\n"));
+ if (max_jsize >= GFS2_MIN_JSIZE)
+ fprintf(stderr, _("Maximum size for %u journals on this device is %uMB.\n"),
+ opts->journals, max_jsize);
+ exit(1);
+ }
+ sdp->jsize = opts->jsize;
}
static int probe_contents(struct mkfs_dev *dev)
diff --git a/tests/edit.at b/tests/edit.at
index 3bd4163..e1a0fca 100644
--- a/tests/edit.at
+++ b/tests/edit.at
@@ -6,7 +6,7 @@ AT_KEYWORDS(gfs2_edit edit)
GFS_TGT_REGEN
AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT $(($(gfs_max_blocks 4096)/2))], 0, [ignore], [ignore])
AT_CHECK([gfs2_edit savemeta $GFS_TGT test.meta > savemeta.log], 0, [ignore], [ignore])
-AT_CHECK([head -2 savemeta.log], 0, [There are 1310718 blocks of 4096 bytes in the filesystem.
+AT_CHECK([head -2 savemeta.log], 0, [There are 1310716 blocks of 4096 bytes in the filesystem.
Filesystem size: 4.1023GB
], [ignore])
GFS_TGT_REGEN
diff --git a/tests/mkfs.at b/tests/mkfs.at
index 274a81d..68195e9 100644
--- a/tests/mkfs.at
+++ b/tests/mkfs.at
@@ -123,3 +123,13 @@ AT_CHECK([$GFS_MKFS -p lock_nolock -o test_topology=0:512:65536:393216:512 $GFS_
# Check rgrp alignment to minimum_io_size: 65536 / 4096 == 16
AT_CHECK([gfs2_edit -p rindex $GFS_TGT | grep ri_addr | awk '{print $2, $2 % 16; if ($2 % 16 != 0) { exit 1 }}'], 0, [ignore], [ignore])
AT_CLEANUP
+
+AT_SETUP([Small filesystems])
+AT_KEYWORDS(mkfs.gfs2 mkfs)
+GFS_TGT_SIZE(32M)
+AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT], 0, [ignore], [ignore])
+AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])
+GFS_TGT_SIZE(64M)
+AT_CHECK([$GFS_MKFS -p lock_nolock -j2 $GFS_TGT], 0, [ignore], [ignore])
+AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore])
+AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index cc1bd54..522ac1c 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -4,6 +4,12 @@ m4_define([GFS_TGT_REGEN],
[AT_CHECK([rm -f $GFS_TGT && truncate -s ${GFS_TGT_SZ}G ${GFS_TGT}], [ignore], [ignore], [ignore])
AT_SKIP_IF([test ! -f ${GFS_TGT}])])
+# Regenerate the sparse file used for testing, with a given size, and skip the test if it fails
+# Usage: GFS_TGT_REGEN(<size>)
+m4_define([GFS_TGT_SIZE],
+[AT_CHECK([rm -f $GFS_TGT && truncate -s $1 ${GFS_TGT}], [ignore], [ignore], [ignore])
+AT_SKIP_IF([test ! -f ${GFS_TGT}])])
+
# Regenerate, check, fsck is used a lot so combine it into one macro
# Usage: GFS_FSCK_CHECK ([mkfs.gfs2 ... $GFS_TGT])
m4_define([GFS_FSCK_CHECK],
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.