Add support for creating and checking 8192-byte blocksize filesystems.
We complain if you try to create such a filesystem on a system with 4096
byte PAGE_SIZE.

Add checks for valid inode size for undocumented -I option.

diff --git a/configure.in b/configure.in
index 3449cdd..6bcc570 100644
--- a/configure.in
+++ b/configure.in
@@ -437,7 +437,7 @@
 else
   AC_CHECK_PROGS(BUILD_CC, gcc cc)
 fi
-AC_CHECK_HEADERS(stdlib.h unistd.h stdarg.h errno.h malloc.h mntent.h paths.h dirent.h getopt.h setjmp.h signal.h termios.h linux/fd.h linux/major.h sys/disklabel.h sys/ioctl.h sys/mkdev.h sys/mount.h sys/sockio.h sys/sysmacros.h sys/time.h sys/stat.h sys/types.h net/if.h netinet/in.h)
+AC_CHECK_HEADERS(stdlib.h unistd.h stdarg.h errno.h malloc.h mntent.h paths.h dirent.h getopt.h setjmp.h signal.h termios.h linux/fd.h linux/major.h sys/disklabel.h sys/ioctl.h sys/mkdev.h sys/mount.h sys/sockio.h sys/sysmacros.h sys/time.h sys/stat.h sys/types.h net/if.h netinet/in.h asm/page.h)
 AC_FUNC_VPRINTF
 dnl
 dnl See if struct dirent has a d_namlen field (like bsd systems), implying
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 6a52024..9d04114 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -266,19 +266,17 @@
 	mtrace_print("Pass 1");
 #endif
 
-#define EXT2_BPP(bits) (1UL << ((bits) - 2))
+#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
 
-	for (i=0; i < 4; i++) {
-		max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(10+i);
-		max_sizes = max_sizes + EXT2_BPP(10+i) * EXT2_BPP(10+i);
-		max_sizes = (max_sizes +
-			     (__u64) EXT2_BPP(10+i) * EXT2_BPP(10+i) *
-			     EXT2_BPP(10+i));
-		max_sizes = (max_sizes * (1UL << (10+i))) - 1;
-		max_sect_limit = 512ULL * ((1LL << 32) - (1 << (i+1)));
+	for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
+		max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
+		max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
+		max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
+		max_sizes = (max_sizes * (1UL << i)) - 1;
+		max_sect_limit = 512ULL * ((1LL << 32) - (1 << i));
 		if (max_sizes > max_sect_limit)
 			max_sizes = max_sect_limit;
-		ext2_max_sizes[i] = max_sizes;
+		ext2_max_sizes[i - 10] = max_sizes;
 	}
 #undef EXT2_BPP
 
@@ -451,11 +449,6 @@
 		} else if (ino == EXT2_JOURNAL_INO) {
 			ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
 			if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) {
-				/*
-				 * XXX arguably this check should be
-				 * in journal.c, before we decide it's
-				 * safe to run the journal...
-				 */
 				if (!LINUX_S_ISREG(inode.i_mode) &&
 				    fix_problem(ctx, PR_1_JOURNAL_BAD_MODE,
 						&pctx)) {
diff --git a/e2fsck/super.c b/e2fsck/super.c
index df78469..e57fd8b 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -334,11 +334,10 @@
 			  MIN_CHECK, 1, 0);
 	check_super_value(ctx, "first_data_block", sb->s_first_data_block,
 			  MAX_CHECK, 0, sb->s_blocks_count);
-	check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
-			  MAX_CHECK, 0, 2);
 	check_super_value(ctx, "log_block_size", sb->s_log_block_size,
-			  MIN_CHECK | MAX_CHECK, sb->s_log_frag_size,
-			  2);
+			  MIN_CHECK | MAX_CHECK, 0, EXT2_MAX_BLOCK_LOG_SIZE);
+	check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
+			  MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
 	check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
 			  MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
 			  8 * EXT2_BLOCK_SIZE(sb));
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index e424ac7..e231888 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -51,8 +51,6 @@
 static int replace_bad_blocks = 0;
 static char *bad_blocks_file = 0;
 
-static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
-
 static int root_filesystem = 0;
 static int read_only_root = 0;
 
@@ -663,7 +661,6 @@
 {
 	errcode_t	retval = 0;
 	int		exit_value = FSCK_OK;
-	int		i;
 	ext2_filsys	fs = 0;
 	io_manager	io_ptr;
 	struct ext2_super_block *sb;
@@ -742,10 +739,11 @@
 				     ctx->superblock, ctx->blocksize,
 				     io_ptr, &fs);
 	} else if (ctx->superblock) {
-		for (i=0; possible_block_sizes[i]; i++) {
+		int blocksize;
+		for (blocksize = EXT2_MIN_BLOCK_SIZE;
+		     blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
 			retval = ext2fs_open(ctx->filesystem_name, flags,
-					     ctx->superblock,
-					     possible_block_sizes[i],
+					     ctx->superblock, blocksize,
 					     io_ptr, &fs);
 			if (!retval)
 				break;
diff --git a/e2fsck/util.c b/e2fsck/util.c
index 227e41d..19d4685 100644
--- a/e2fsck/util.c
+++ b/e2fsck/util.c
@@ -359,7 +359,8 @@
 		goto cleanup;
 	sb = (struct ext2_super_block *) buf;
 
-	for (blocksize=1024; blocksize <= 8192 ; blocksize = blocksize*2) {
+	for (blocksize = EXT2_MIN_BLOCK_SIZE;
+	     blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
 		superblock = blocksize*8;
 		if (blocksize == 1024)
 			superblock++;
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 1143965..b4d5ae6 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -67,9 +67,10 @@
 /*
  * Macro-instructions used to manage several block sizes
  */
-#define EXT2_MIN_BLOCK_SIZE		1024
-#define	EXT2_MAX_BLOCK_SIZE		4096
-#define EXT2_MIN_BLOCK_LOG_SIZE		  10
+#define EXT2_MIN_BLOCK_LOG_SIZE		10	/* 1024 */
+#define EXT2_MAX_BLOCK_LOG_SIZE		13	/* 8192 */
+#define EXT2_MIN_BLOCK_SIZE		(1 << EXT2_MIN_BLOCK_LOG_SIZE)
+#define	EXT2_MAX_BLOCK_SIZE		(1 << EXT2_MAX_BLOCK_LOG_SIZE)
 #ifdef __KERNEL__
 # define EXT2_BLOCK_SIZE(s)		((s)->s_blocksize)
 #else
@@ -98,9 +99,9 @@
 /*
  * Macro-instructions used to manage fragments
  */
-#define EXT2_MIN_FRAG_SIZE		1024
-#define	EXT2_MAX_FRAG_SIZE		4096
-#define EXT2_MIN_FRAG_LOG_SIZE		  10
+#define EXT2_MIN_FRAG_SIZE		EXT2_MIN_BLOCK_SIZE
+#define	EXT2_MAX_FRAG_SIZE		EXT2_MAX_BLOCK_SIZE
+#define EXT2_MIN_FRAG_LOG_SIZE		EXT2_MIN_BLOCK_LOG_SIZE
 #ifdef __KERNEL__
 # define EXT2_FRAG_SIZE(s)		((s)->u.ext2_sb.s_frag_size)
 # define EXT2_FRAGS_PER_BLOCK(s)	((s)->u.ext2_sb.s_frags_per_block)
diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
index d8fa228..bf64c68 100644
--- a/lib/ext2fs/initialize.c
+++ b/lib/ext2fs/initialize.c
@@ -166,8 +166,8 @@
 			   EXT2_DESC_PER_BLOCK(super) - 1)
 		/ EXT2_DESC_PER_BLOCK(super);
 
-	/* n.b., fs->blocksize is <= 4096 */
-	set_field(s_inodes_count, super->s_blocks_count/(4096/fs->blocksize));
+	i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;
+	set_field(s_inodes_count, super->s_blocks_count / i);
 
 	/*
 	 * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index cbaffac..89b4f6b 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -44,6 +44,13 @@
 #include <sys/ioctl.h>
 #include <sys/types.h>
 
+#ifdef HAVE_ASM_PAGE_H
+#include <asm/page.h>
+#define SYS_MAX_BLOCKSIZE PAGE_SIZE
+#else
+#define SYS_MAX_BLOCKSIZE 4096
+#endif
+
 #include "ext2fs/ext2_fs.h"
 #include "et/com_err.h"
 #include "uuid/uuid.h"
@@ -137,8 +144,8 @@
 	{ default_str, 3, 1024, 8192 },
 	{ "journal", 0, 4096, 8192 },
 	{ "news", 0, 4096, 4096 },
-	{ "largefile", 0, 4096, 1024 * 1024 },
-	{ "largefile4", 0, 4096, 4096 * 1024 },
+	{ "largefile", 0, SYS_MAX_BLOCKSIZE, 1024 * 1024 },
+	{ "largefile4", 0, SYS_MAX_BLOCKSIZE, 4096 * 1024 },
 	{ 0, 0, 0, 0},
 };
 
@@ -150,8 +157,7 @@
 	int	ratio = 0;
 	struct mke2fs_defaults *p;
 
-	megs = (super->s_blocks_count * (EXT2_BLOCK_SIZE(super) / 1024) /
-		1024);
+	megs = super->s_blocks_count * (EXT2_BLOCK_SIZE(super) / 1024) / 1024;
 	if (inode_ratio)
 		ratio = *inode_ratio;
 	if (!fs_type)
@@ -788,6 +794,7 @@
 	blk_t		group_blk_max = 8192;
 	int		blocksize = 0;
 	int		inode_ratio = 0;
+	int		inode_size = 0;
 	int		reserved_ratio = 5;
 	ext2_ino_t	num_inodes = 0;
 	errcode_t	retval;
@@ -854,11 +861,16 @@
 		switch (c) {
 		case 'b':
 			blocksize = strtoul(optarg, &tmp, 0);
-			if (blocksize < 1024 || blocksize > 4096 || *tmp) {
+			if (blocksize < EXT2_MIN_BLOCK_SIZE ||
+			    blocksize > EXT2_MAX_BLOCK_SIZE || *tmp) {
 				com_err(program_name, 0,
 					_("bad block size - %s"), optarg);
 				exit(1);
 			}
+			if (blocksize > 4096)
+				fprintf(stderr, _("Warning: blocksize %d not "
+						  "usable on most systems.\n"),
+					blocksize);
 			param.s_log_block_size =
 				int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
 			group_blk_max = blocksize * 8;
@@ -869,7 +881,8 @@
 			break;
 		case 'f':
 			size = strtoul(optarg, &tmp, 0);
-			if (size < 1024 || size > 4096 || *tmp) {
+			if (size < EXT2_MIN_BLOCK_SIZE ||
+			    size > EXT2_MAX_BLOCK_SIZE || *tmp) {
 				com_err(program_name, 0,
 					_("bad fragment size - %s"),
 					optarg);
@@ -895,10 +908,13 @@
 			break;
 		case 'i':
 			inode_ratio = strtoul(optarg, &tmp, 0);
-			if (inode_ratio < 1024 || inode_ratio > 4096 * 1024 ||
+			if (inode_ratio < EXT2_MIN_BLOCK_SIZE ||
+			    inode_ratio > EXT2_MAX_BLOCK_SIZE * 1024 ||
 			    *tmp) {
 				com_err(program_name, 0,
-					_("bad inode ratio - %s"), optarg);
+					_("bad inode ratio %s (min %d/max %d"),
+					optarg, EXT2_MIN_BLOCK_SIZE,
+					EXT2_MAX_BLOCK_SIZE);
 				exit(1);
 			}
 			break;
@@ -953,7 +969,12 @@
 			break;
 #ifdef EXT2_DYNAMIC_REV
 		case 'I':
-			param.s_inode_size = atoi(optarg);
+			inode_size = strtoul(optarg, &tmp, 0);
+			if (*tmp) {
+				com_err(program_name, 0,
+					_("bad inode size - %s"), optarg);
+				exit(1);
+			}
 			break;
 #endif
 		case 'N':
@@ -1050,6 +1071,18 @@
 		ext2fs_close(jfs);
 	}
 
+	if (blocksize > SYS_MAX_BLOCKSIZE) {
+		if (!force) {
+			com_err(program_name, 0,
+				_("%d-byte blocks too big for system (max %d)"),
+				blocksize, SYS_MAX_BLOCKSIZE);
+			proceed_question();
+		}
+		fprintf(stderr, _("Warning: %d-byte blocks too big for system "
+				  "(max %d), forced to continue\n"),
+			blocksize, SYS_MAX_BLOCKSIZE);
+	}
+
 	if (param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
 		if (!fs_type)
 			fs_type = "journal";
@@ -1129,6 +1162,23 @@
 		}
 	}
 
+	if (inode_size) {
+		if (inode_size < EXT2_GOOD_OLD_INODE_SIZE ||
+		    inode_size > EXT2_BLOCK_SIZE(&param) ||
+		    inode_size & (inode_size - 1)) {
+			com_err(program_name, 0,
+				_("bad inode size %d (min %d/max %d)"),
+				inode_size, EXT2_GOOD_OLD_INODE_SIZE,
+				EXT2_BLOCK_SIZE(&param));
+			exit(1);
+		}
+		if (inode_size != EXT2_GOOD_OLD_INODE_SIZE)
+			fprintf(stderr, _("Warning: %d-byte inodes not usable "
+				"on most systems\n"),
+				inode_size);
+		param.s_inode_size = inode_size;
+	}
+
 	/*
 	 * Calculate number of inodes based on the inode ratio
 	 */