[LINUX] Talk about paying attention to mke2fs.conf when formatting ext4

To summarize in 3 lines

-** It's hard to understand the default parameters when formatting mke2fs ** -So it is better to explicitly write the parameter in the argument --Don't forget to check with ** dumpe2fs ** after making

Introduction

Suddenly, which of the following determines the default parameters when formatting ext4 with ** mke2fs **?

  1. Volume size
  2. /etc/mke2fs.conf
  3. Environment variables
  4. All of the above
  5. There are many more than all of the above

The correct answer was 5. I think it was easy for everyone who hex dumps ext4 superblock on a regular basis.

That's why I'm writing this ridiculous story, but I think it's useless to say it clearly. I think it's quick and reliable to explicitly format mke2fs with arguments and dumpe2fs to check the resulting image.

Below, the source code looks at e2fsprogs-v1.45.6, showing an example on Ubuntu-18.04.

e2fsprogs mke2fs is a command provided by e2fsprogs. You can think of this as the head family of ext2, ext3, and ext4. There are make_ext4fs and Ext2Fsd, but it is not always possible to follow the original family with detailed options. Therefore, I sometimes step on some bugs.

The behavior of e2fsprogs is not always described in man, so if you want to follow the details, you have to check the source code directly.

mke2fs execution command name

The behavior of mke2fs changes depending on the command name (that is, ** argv [0] **) when it is executed. From parse_fs_type () and PRS () in e2fsprogs / misc / mke2fs.c

e2fsprogs/misc/mke2fs.c


	if (fs_type)
		ext_type = fs_type;
	else if (is_hurd)
		ext_type = "ext2";
	else if (!strcmp(program_name, "mke3fs"))
		ext_type = "ext3";
	else if (!strcmp(program_name, "mke4fs"))
		ext_type = "ext4";
	else if (progname) {
		ext_type = strrchr(progname, '/');
		if (ext_type)
			ext_type++;
		else
			ext_type = progname;

		if (!strncmp(ext_type, "mkfs.", 5)) {
			ext_type += 5;
			if (ext_type[0] == 0)
				ext_type = 0;
		} else
			ext_type = 0;
	}

e2fsprogs/misc/mke2fs.c


	if (argc && *argv) {
		program_name = get_progname(*argv);

		/* If called as mkfs.ext3, create a journal inode */
		if (!strcmp(program_name, "mkfs.ext3") ||
		    !strcmp(program_name, "mke3fs"))
			journal_size = -1;
	}

If ** ext_type ** (**-t ** option) is not specified, ext_type of ext2, ext3, ext4 is determined from the program name. I think many people are usually taken care of by mkfs.ext4.

[[email protected] e2fsprogs]$ ls -l /sbin/mkfs.ext*
lrwxrwxrwx 1 root root 6 Jan 25  2019 /sbin/mkfs.ext2 -> mke2fs
lrwxrwxrwx 1 root root 6 Jan 25  2019 /sbin/mkfs.ext3 -> mke2fs
lrwxrwxrwx 1 root root 6 Jan 25  2019 /sbin/mkfs.ext4 -> mke2fs

This is also described in mke2fs (8).

       If mke2fs is run as mkfs.XXX (i.e., mkfs.ext2, mkfs.ext3, or
       mkfs.ext4) the option -t XXX is implied; so mkfs.ext3 will create a
       file system for use with ext3, mkfs.ext4 will create a file system
       for use with ext4, and so on.

Volume size

mke2fs also behaves differently depending on the size of the volume you are trying to format. From parse_fs_type () in e2fsprogs / misc / mke2fs.c

e2fsprogs/misc/mke2fs.c


	if (fs_blocks_count < 3 * meg)
		size_type = "floppy";
	else if (fs_blocks_count < 512 * meg)
		size_type = "small";
	else if (fs_blocks_count < 4 * 1024 * 1024 * meg)
		size_type = "default";
	else if (fs_blocks_count < 16 * 1024 * 1024 * meg)
		size_type = "big";
	else
		size_type = "huge";

	if (!usage_types)
		usage_types = size_type;

When ** usage_types ** (**-T ** option) is not specified, size_type selection is changed for 3MiB, 512MiB, 4TiB, 16TiB. Although man is mentioned here as well, it does not mention how to specify the size or ** "floppy" **, so I have to look at the source code.

mke2fs.conf As mentioned above, ** ext_type ** and ** usage_types ** are determined, but these are used as values for selecting the section described in mke2fs.conf.

[[email protected] e2fsprogs]$ cat /etc/mke2fs.conf
[defaults]
        base_features = sparse_super,large_file,filetype,resize_inode,dir_index,ext_attr
        default_mntopts = acl,user_xattr
        enable_periodic_fsck = 0
        blocksize = 4096
        inode_size = 256
        inode_ratio = 16384

[fs_types]
        ext3 = {
                features = has_journal
        }
        ext4 = {
                features = has_journal,extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize
                inode_size = 256
        }
        small = {
                blocksize = 1024
                inode_size = 128
                inode_ratio = 4096
        }
        floppy = {
                blocksize = 1024
                inode_size = 128
                inode_ratio = 8192
        }
        big = {
                inode_ratio = 32768
        }
        huge = {
                inode_ratio = 65536
        }
        news = {
                inode_ratio = 4096
        }
        largefile = {
                inode_ratio = 1048576
                blocksize = -1
        }
        largefile4 = {
                inode_ratio = 4194304
                blocksize = -1
        }
        hurd = {
             blocksize = 4096
             inode_size = 128
        }

Like this, mke2fs.conf has options depending on the type. Parameters will be selected from here according to ext_type and usage_types. The template for this file is provided by e2fsprogs, but the actual content may vary from Linux distribution to Linux distribution. As I will mention at the end of the article, ** metadata_csum ** is a habit.

For this mke2fs.conf, ** man mke2fs.conf (5) ** is provided. The options can also be specified in detail.

For this mke2fs.conf file as well, you can customize where to look for the file, and continue to the ↓ chapter.

How to find mke2fs.conf

You can specify the location of the mke2fs.conf file with the environment variable ** MKE2FS_CONFIG **. From PRS () on e2fsprogs / misc / mke2fs.c

e2fsprogs/misc/mke2fs.c


	if ((tmp = getenv("MKE2FS_CONFIG")) != NULL)
		config_fn[0] = tmp;

If the environment variable ** MKE2FS_CONFIG ** is not defined, the compile-time default location (** ROOT_SYSCONFDIR **) is used, which is usually / etc.

Without mke2fs.conf

If mke2fs.conf is not found, the value of ** const char * mke2fs_default_profile ** is used. However, if you look only at the source code, you cannot find the contents of this variable. This variable is actually automatically generated at build time.

e2fsprogs/misc/profile-to-c.awk


#!/bin/awk
BEGIN {
  printf("const char *mke2fs_default_profile = \n");
}

{
  printf("  \"%s\\n\"\n", $0);
}

END {
  printf(";\n", str)
}

And the arguments when executing ** profile-to-c.awk ** are expanded. The argument is

e2fsprogs/misc/Makefile.in


default_profile.c: mke2fs.conf $(srcdir)/profile-to-c.awk
    $(E) "  PROFILE_TO_C mke2fs.conf"
    $(Q) $(AWK) -f $(srcdir)/profile-to-c.awk < mke2fs.conf \
        >  default_profile.c

The file extracted from ** mke2fs.conf.in ** is used at the time of **. / Configure **.

bash:2fsprogs/misc/mke2fs.conf.in


[defaults]
    base_features = sparse_super,large_file,filetype,resize_inode,dir_index,ext_attr
    default_mntopts = acl,user_xattr
    enable_periodic_fsck = 0
    blocksize = 4096
    inode_size = 256
    inode_ratio = 16384

[fs_types]
    ext3 = {
        features = has_journal
    }
    ext4 = {
        features = has_journal,extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize
        inode_size = 256
    }
    small = {
        blocksize = 1024
        inode_size = 128
        inode_ratio = 4096
    }
    floppy = {
        blocksize = 1024
        inode_size = 128
        inode_ratio = 8192
    }
    big = {
        inode_ratio = 32768
    }
    huge = {
        inode_ratio = 65536
    }
    news = {
        inode_ratio = 4096
    }
    largefile = {
        inode_ratio = 1048576
        blocksize = -1
    }
    largefile4 = {
        inode_ratio = 4194304
        blocksize = -1
    }
    hurd = {
         blocksize = 4096
         inode_size = 128
    }

[options]
    fname_encoding = utf8

In other words, the default mke2fs.conf of e2fsprogs is stored in the mke2fs program as it is.

Metadata_csum trap

There was a petite incident in metadata_csum, and there was a problem that e2fsprogs of old Ubuntu (16.04) could not handle ext4 with metadata_csum enabled. -[March 23, 2018 issue: Dealing with ext4's metadata_csum option-Change of initramfs compression method: Ubuntu Weekly Topics | gihyo.jp… Technical Review Company](https://gihyo.jp/admin/clip/01 / ubuntu-topics / 201803/23)

This is because the Linux kernel can understand metadata_csum, but e2fsprogs was still old and couldn't understand metadata_csum. In the case of this Ubuntu-16.04, it is Linux-4.15, but depending on the environment, the kernel version can not be predicted, and there is a possibility that metadata_csum will be enabled in an unexpected environment. If the kernel is too old, it can handle metadata_csum but still has ext4 bugs, so uh, that's very scary, yes.

in conclusion

So, I took a closer look at how mke2fs determines the default parameters. The starting point was the difference in inode size that I wondered casually, but when I looked it up, it was a quagmire to understand properly. Or rather, I thought it was better to stop understanding.

Stop understanding and try to specify it as an argument when running mke2fs as much as possible. Then, make sure that dumpe2fs has the desired parameters for the resulting image.

reference

Recommended Posts

Talk about paying attention to mke2fs.conf when formatting ext4