summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2012-08-16 11:59:02 -0700
committerKees Cook <keescook@chromium.org>2012-08-20 12:58:22 -0700
commita2055bbfb35a5c616fcdd06aee37cc83a8cb2517 (patch)
tree95c5a8a99ce81f978453ebf36ce9661c96bb9106
parentf217520215e7e3d2f5ca006992ab5002927c4f87 (diff)
downloadvboot-a2055bbfb35a5c616fcdd06aee37cc83a8cb2517.tar.gz
Cherry-pick: mount-encrypted: calculate inode ratio based on final size
mkfs.ext4 does not use the resize= hint for calculating inode ratios. This means very tiny initial filesystems will not get enough inodes once it has been resized. This calculates the desired inode ratio based on the expected final size of the filesystem. BUG=chrome-os-partner:12678 TEST=lumpy build, manual testing Change-Id: I9fd66a2d997329fde794f1485b00ff7a757687f8 Signed-off-by: Kees Cook <keescook@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/30579 Reviewed-by: Gaurav Shah <gauravsh@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/30891
-rw-r--r--utility/Makefile1
-rw-r--r--utility/mount-helpers.c74
2 files changed, 74 insertions, 1 deletions
diff --git a/utility/Makefile b/utility/Makefile
index 783b1735..4630ff8e 100644
--- a/utility/Makefile
+++ b/utility/Makefile
@@ -187,6 +187,7 @@ ${BUILD_ROOT}/mount-encrypted: mount-encrypted.c mount-encrypted.h \
-I$(HOSTDIR)/include \
$(LDFLAGS) \
$< -o $@ $(shell $(PKG_CONFIG) --libs glib-2.0 openssl) \
+ -lm \
${BUILD_ROOT}/mount-helpers.o $(LIBS)
${BUILD_ROOT}/dev_sign_file: dev_sign_file.c $(LIBS)
diff --git a/utility/mount-helpers.c b/utility/mount-helpers.c
index 893d43e0..7647ffab 100644
--- a/utility/mount-helpers.c
+++ b/utility/mount-helpers.c
@@ -15,6 +15,7 @@
#include <string.h>
#include <errno.h>
#include <fcntl.h>
+#include <math.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
@@ -38,6 +39,9 @@ static const int kLoopMajor = 7;
static const int kLoopMax = 8;
static const unsigned int kResizeStepSeconds = 2;
static const size_t kResizeBlocks = 32768 * 10;
+static const size_t kBlocksPerGroup = 32768;
+static const size_t kInodeRatioDefault = 16384;
+static const size_t kInodeRatioMinimum = 2048;
static const gchar * const kExt4ExtendedOptions = "discard,lazy_itable_init";
int remove_tree(const char *tree)
@@ -444,10 +448,68 @@ out:
return sparsefd;
}
+/* When creating a filesystem that will grow, the inode ratio is calculated
+ * using the starting size not the hinted "resize" size, which means the
+ * number of inodes can be highly constrained on tiny starting filesystems.
+ * Instead, calculate what the correct inode ratio should be for a given
+ * filesystem based on its expected starting and ending sizes.
+ *
+ * inode-ratio_mkfs =
+ *
+ * ceil(blocks_max / group-ratio) * size_mkfs
+ * ------------------------------------------------------------------
+ * ceil(size_max / inode-ratio_max) * ceil(blocks_mkfs / group-ratio)
+ */
+static size_t get_inode_ratio(size_t block_bytes_in, size_t blocks_mkfs_in,
+ size_t blocks_max_in)
+{
+ double block_bytes = (double)block_bytes_in;
+ double blocks_mkfs = (double)blocks_mkfs_in;
+ double blocks_max = (double)blocks_max_in;
+
+ double size_max, size_mkfs, groups_max, groups_mkfs, inodes_max;
+ double denom, inode_ratio_mkfs;
+
+ size_max = block_bytes * blocks_max;
+ size_mkfs = block_bytes * blocks_mkfs;
+
+ groups_max = ceil(blocks_max / kBlocksPerGroup);
+ groups_mkfs = ceil(blocks_mkfs / kBlocksPerGroup);
+
+ inodes_max = ceil(size_max / kInodeRatioDefault);
+
+ denom = inodes_max * groups_mkfs;
+ /* Make sure we never trigger divide-by-zero. */
+ if (denom == 0.0)
+ goto failure;
+ inode_ratio_mkfs = (groups_max * size_mkfs) / denom;
+
+ /* Make sure we never calculate anything totally huge. */
+ if (inode_ratio_mkfs > blocks_mkfs)
+ goto failure;
+ /* Make sure we never calculate anything totally tiny. */
+ if (inode_ratio_mkfs < kInodeRatioMinimum)
+ goto failure;
+
+ return (size_t)inode_ratio_mkfs;
+
+failure:
+ return kInodeRatioDefault;
+}
+
+/* Creates an ext4 filesystem.
+ * device: path to block device to create filesystem on.
+ * block_bytes: bytes per block to use for filesystem.
+ * blocks_min: starting number of blocks on filesystem.
+ * blocks_max: largest expected size in blocks of filesystem, for growth hints.
+ *
+ * Returns 1 on success, 0 on failure.
+ */
int filesystem_build(const char *device, size_t block_bytes, size_t blocks_min,
size_t blocks_max)
{
int rc = 0;
+ size_t inode_ratio;
gchar *blocksize = g_strdup_printf("%zu", block_bytes);
if (!blocksize) {
@@ -474,12 +536,20 @@ int filesystem_build(const char *device, size_t block_bytes, size_t blocks_min,
goto free_blocks_str;
}
+ inode_ratio = get_inode_ratio(block_bytes, blocks_min, blocks_max);
+ gchar *inode_ratio_str = g_strdup_printf("%zu", inode_ratio);
+ if (!inode_ratio_str) {
+ PERROR("g_strdup_printf");
+ goto free_extended;
+ }
+
const gchar *mkfs[] = {
"/sbin/mkfs.ext4",
"-T", "default",
"-b", blocksize,
"-m", "0",
"-O", "^huge_file,^flex_bg",
+ "-i", inode_ratio_str,
"-E", extended,
device,
blocks_str,
@@ -488,7 +558,7 @@ int filesystem_build(const char *device, size_t block_bytes, size_t blocks_min,
rc = (runcmd(mkfs, NULL) == 0);
if (!rc)
- goto free_extended;
+ goto free_inode_ratio_str;
const gchar *tune2fs[] = {
"/sbin/tune2fs",
@@ -499,6 +569,8 @@ int filesystem_build(const char *device, size_t block_bytes, size_t blocks_min,
};
rc = (runcmd(tune2fs, NULL) == 0);
+free_inode_ratio_str:
+ g_free(inode_ratio_str);
free_extended:
g_free(extended);
free_blocks_str: