Fri 30 May 2014 01:24:13 PM UTC, original submission:
We have a setup where the kernel to be loaded is accessed through a path containing a symbolic link. The config is something like this:
- 8< -
search --set=root --label boot
linux '/boot/active/kernel'
initrd '/boot/active/initrd'
- 8< -
If '/boot/active' is a symbolic link to a directory whose name is exactly 60 characters long, loading the kernel fails and GRUB cannot boot. Directories whose name is less than 60 or more than 60 work perfectly.
It seems to be that there is a difference in how the Linux ext4 implementation handles in-inode symbolic links and what the GRUB implementation expects.
In the Linux implementation of ext4, symbolic links whose target is shorter than 60 bytes are stored directly in the inode. (See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/ext4/namei.c?id=455c6fdbd219161bd09b1165f11699d6d73de11c#n2831)
It's worth noting that the code performs the comparison '(l > 60)', where l equals strlen(symname)+1. That means in practice that if the lenth of the symlink target is 60, the comparison is true, meaning that it is stored as a non-fast symlink in a separate block.
In the GRUB implementation, however, the following comparison is made to check if the symlink target is stored in the inode structure: diro->inode.size <= 60. (sizeof(diro->inode.symlink) == 60) Unfortunately, if size is 60, this leads to GRUB looking for the symlink target in the inode, but the ext4 implementation has not stored that info there.
I've attached a patch that seems to fix the issue by making sure that GRUB handles symlink targets of length 60 as non-fast.
|