debugfs, e2fsck: fix s_desc_size handling

The s_desc_size in the superblock specifies the group descriptor
size in bytes, but in various places the EXT4_FEATURE_INCOMPAT_64BIT
flag implies that the descriptor size is EXT2_MIN_DESC_SIZE_64BIT
(64 bytes) instead of checking the actual size.  In other places,
the s_desc_size field is used without checking for INCOMPAT_64BIT.

In the case of ext2fs_group_desc() the s_desc_size was being ignored,
and assumed to be sizeof(struct ext4_group_desc), which would result
in garbage for any but the first group descriptor.  Similarly, in
ext2fs_group_desc_csum() and print_csum() they assumed that the
maximum group descriptor size was sizeof(struct ext4_group_desc).
Fix these functions to use the actual superblock s_desc_size if
INCOMPAT_64BIT.

Conversely, in ext2fs_swap_group_desc2() s_desc_size was used
without checking for INCOMPAT_64BIT being set.

The e2fsprogs behaviour is different than that of the kernel,
which always checks INCOMPAT_64BIT, and only uses s_desc_size to
determine the offset of group descriptors and what range of bytes
to checksum.

Allow specifying the s_desc_size field at mke2fs time with the
"-E desc_size=NNN" option.  Allow a power-of-two s_desc_size
value up to s_blocksize if INCOMPAT_64BIT is specified.  This
is not expected to be used by regular users at this time, so it
is not currently documented in the mke2fs usage or man page.

Add m_desc_size_128, f_desc_size_128, and f_desc_bad test cases to
verify mke2fs and e2fsck handling of larger group descriptor sizes.

Signed-off-by: Andreas Dilger <adilger@dilger.ca>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index d5541ab..2e8ba60 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -679,7 +679,38 @@
 			*arg = 0;
 			arg++;
 		}
-		if (strcmp(token, "mmp_update_interval") == 0) {
+		if (strcmp(token, "desc-size") == 0 ||
+		    strcmp(token, "desc_size") == 0) {
+			int desc_size;
+
+			if (!(fs_param.s_feature_incompat &
+			      EXT4_FEATURE_INCOMPAT_64BIT)) {
+				fprintf(stderr,
+					_("%s requires '-O 64bit'\n"), token);
+				r_usage++;
+				continue;
+			}
+			if (param->s_reserved_gdt_blocks != 0) {
+				fprintf(stderr,
+					_("'%s' must be before 'resize=%u'\n"),
+					token, param->s_reserved_gdt_blocks);
+				r_usage++;
+				continue;
+			}
+			if (!arg) {
+				r_usage++;
+				badopt = token;
+				continue;
+			}
+			desc_size = strtoul(arg, &p, 0);
+			if (*p || (desc_size & (desc_size - 1))) {
+				fprintf(stderr,
+					_("Invalid desc_size: '%s'\n"), arg);
+				r_usage++;
+				continue;
+			}
+			param->s_desc_size = desc_size;
+		} else if (strcmp(token, "mmp_update_interval") == 0) {
 			if (!arg) {
 				r_usage++;
 				badopt = token;