Reliable way to detect ext2 or ext3 or ext4

ext2ext3ext4filesystems

I need to detect a filesystem type from a C/C++ program using the filesystem superblock. However, I don't see much differences between superblocks for ext2 and ext4. The s_rev_level field is the same (=1), the s_minor_rev_level is the same (=0).

I could check some features from s_feature_compat (and other feature fields) and try to locate features, which aren't supported by ext2. But – the person, formatting a partition, could disable some features on purpose. So, this method can detect the ext4, but it can't distinguish between the ext2 and the ext4 with disabled ext4-specific features.

So, how to do that?

Best Answer

After looking at the code for various utilities and the kernel code for some time, it does seem that what @Hauke suggested is true - whether a filesystem is ext2/ext3/ext4 is purely defined by the options that are enabled.

From the Wikipedia page on ext4:

Backward compatibility

ext4 is backward compatible with ext3 and ext2, making it possible to mount ext3 and ext2 as ext4. This will slightly improve performance, because certain new features of ext4 can also be used with ext3 and ext2, such as the new block allocation algorithm.

ext3 is partially forward compatible with ext4. That is, ext4 can be mounted as ext3 (using "ext3" as the filesystem type when mounting). However, if the ext4 partition uses extents (a major new feature of ext4), then the ability to mount as ext3 is lost.

As most probably already know, there is similar compatibility between ext2 and ext3.

After looking at the code which blkid uses to distinguish different ext filesystems, I was able to turn an ext4 filesystem into something recognised as ext3 (and from there to ext2). You should be able to repeat this with:

truncate -s 100M testfs
mkfs.ext4 -O ^64bit,^extent,^flex_bg testfs <<<y
blkid testfs
tune2fs -O ^huge_file,^dir_nlink,^extra_isize,^mmp testfs
e2fsck testfs
tune2fs -O metadata_csum testfs
tune2fs -O ^metadata_csum testfs
blkid testfs
./e2fsprogs/misc/tune2fs -O ^has_journal testfs
blkid testfs

First blkid output is:

testfs: UUID="78f4475b-060a-445c-a5d2-0f45688cc954" SEC_TYPE="ext2" TYPE="ext4"

Second is:

testfs: UUID="78f4475b-060a-445c-a5d2-0f45688cc954" SEC_TYPE="ext2" TYPE="ext3"

And the final one:

testfs: UUID="78f4475b-060a-445c-a5d2-0f45688cc954" TYPE="ext2"

Note that I had to use a new version of e2fsprogs than was available in my distro to get the metadata_csum flag. The reason for setting, then clearing this was because I found no other way to affect the underlying EXT4_FEATURE_RO_COMPAT_GDT_CSUM flag. The underlying flag for metadata_csum (EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) and EXT4_FEATURE_RO_COMPAT_GDT_CSUM are mutually exclusive. Setting metadata_csum disables EXT4_FEATURE_RO_COMPAT_GDT_CSUM, but un-setting metadata_csum does not re-enable the latter.

Conclusions

Lacking a deep knowledge of the filesystem internals, it seems either:

  1. Journal checksumming is meant to be a defining feature of a filesystem created as ext4 that you are really not supposed to disable and that fact that I have managed this is really a bug in e2fsprogs. Or,

  2. All ext4 features were always designed to be disabled and disabling them does make the filesystem to all intents an purposes an ext3 filesystem.

Either way a high level of compatibility between the filesystems is clearly a design goal, compare this to ReiserFS and Reiser4 where Reiser4 is a complete redesign. What really matters is whether the features present are supported by the driver that is used to mount the system. As the Wikipedia article notes the ext4 driver can be used with ext3 and ext2 as well (in fact there is a kernel option to always use the ext4 driver and ditch the others). Disabling features just means that the earlier drivers will have no problems with the filesystem and so there are no reasons to stop them from mounting the filesystem.

Recommendations

To distinguish between the different ext filesystems in a C program, libblkid seems to be the best thing to use. It is part of util-linux and this is what the mount command uses to try to determine the filesystem type. API documentation is here.

If you have to do your own implementation of the check, then testing the same flags as libblkid seems to be the right way to go. Although notably the file linked has no mention of the EXT4_FEATURE_RO_COMPAT_METADATA_CSUM flag which appears to be tested in practice.

If you really wanted to go the whole hog, then looking at for journal checksums might be a surefire way of finding if a filesystem without these flags is (or perhaps was) ext4.

Update

It is actually somewhat easier to go in the opposite direction and promote an ext2 filesystem to ext4:

truncate -s 100M test
mkfs.ext2 test
blkid test
tune2fs -O has_journal test
blkid test
tune2fs -O huge_file test
blkid test

The three blkid ouputs:

test: UUID="59dce6f5-96ed-4307-9b39-6da2ff73cb04" TYPE="ext2"

test: UUID="59dce6f5-96ed-4307-9b39-6da2ff73cb04" SEC_TYPE="ext2" TYPE="ext3"

test: UUID="59dce6f5-96ed-4307-9b39-6da2ff73cb04" SEC_TYPE="ext2" TYPE="ext4"

The fact that ext3/ext4 features can so easily by enabled on a filesystem that started out as ext2 is probably the best demonstration that the filesystem type really is defined by the features.

Related Question