Running genext2fs to build a filesystem that contains symlinks that are exactly 60 characters long result in those symlinks getting created (incorrectly) as "fast" symlinks where the data is stored within the inode.
Running e2fsck on the generated filesystem reports invalid symlinks, and from there things only get worse.
I noticed that all of the invalid symlinks were 60 bytes long and then ran across the following ext2 documentation:
Symbolic links are also filesystem objects with inodes. They deserve
special mention because the data for them is stored within the inode
itself if the symlink is less than 60 bytes long. It uses the fields
which would normally be used to store the pointers to data blocks.
This is a worthwhile optimisation as it we avoid allocating a full
block for the symlink, and most symlinks are less than 60 characters long.
Upon looking at the genext2fs v1.4.1 source, I found the following test in mklink_fs():
if(size <= 4 * (EXT2_TIND_BLOCK+1))
Elsewhere in the source, I found that EXT2_TIND_BLOCK is 14, hence the test is for <= 60.
Changing this to instead test for "size < 4 * ...", re-building, re-generating my filesystem image, and re-running e2fsck now reports no corruption.