问题:
内核打印 VFS: Can't find ext4 filesystem 只有第一次启动才会出问题
定位思路: 1,由于刚升级了内核,很有可能是内核导致的 查看内核代码,定位到打印出错信息的位置为函数ext4_fill_super,该函数是一个回调函数,由函数mount_bdev 调用 加入printk打印详细信息,看为什么会出现这种错误,定位到问题代码在 if (sb->s_magic != EXT4_SUPER_MAGIC) { printk(KERN_ERR, "invalid magic number:0x%x", sb->s_magic); goto cantfind_ext4; } 直接原因是magic number不对 于是打印super_block结构,发现全是0,于是想到,设备第一次启动,对于新加入的硬盘,这个盘应该还没有分区,还没有文件系统,所以mount当然失败 问题又出现了,为什么这块盘还没有初始化就被使用了呢? 在内核打印调用栈 dump_stack+0x66/0x90 ext4_fill_super.cold+0x135/0x33fd ? vsnprintf+0x239/0x5b0 ? snprintf+0x49/0x60 mount_bdev+0x171/0x1a0 ? ext4_calculate_overhead+0x470/0x470 legacy_get_tree+0x22/0x40 vfs_get_tree+0x1b/0x80 ? ns_capable_common+0x29/0x50 do_mount+0x72a/0x920 ? memdup_user+0x33/0x70 ksys_mount+0x79/0xc0 __x64_sys_mount+0x1c/0x20 do_syscall_64+0x52/0x2f0 entry_SYSCALL_64_after_hwframe+0x44/0xa9
do_syscall_64调过去,也就是从用户态调过去的 也就是说虽然是升级了内核,但是跟内核没关系,这个是用户态bug
2,用户态代码很多 怎么定位 首先缩小范围,在启动的时候加打印,
查看代码,认真阅读代码,发现是对于/home 目录的挂载出现的问题, 出问题的原因是因为硬盘挂载之前没有对硬盘进行格式化(或者说是使用mkfs工具创建文件系统)
我们知道对于一块新安装的硬盘,如果要mount到本地的目录进行读写,一般要进行如下步骤: 1) 使用fdisk 工具给硬盘进行分区 2) 使用mkfs 工具创建文件系统 3) 新硬盘mount到本地目录
这次问题的根本原因是在没有创建文件系统的情况下就去mount,导致内核中sb(super_block)结构体中字段为空,打印出错信息。
这个函数的名字是 ***_check,思考这个地方错误可能是有意为之,只是用来做测试的,如果能mount上就不用mkfs了,如果mount失败再mkfs。 本着最小改动解决bug的思想,觉得在mount的接口上加上了 MS_SILENT 的flag。 后来跟相关同事讨论验证了这种改法的正确性,硬件盒子在bootloader阶段会对新挂载的硬盘进行mkfs,如果把mkfs和mount调换顺序,硬件盒子会打印remoung的错误。
疑问,既然这个问题由来已久,为什么之前的版本没有发现,仔细比对了新内核代码与旧内核代码之后发现,新内核代码中ext3,ext4代码合并到一起了,原有的出错打印是info级别的,只能在dmesg中看到,新内核的代码打印的是error级别的,所以显示到了串口。
验证: 修改之后编译版本,升级测试,不在打印错误信息,查看dmesg信息没有发现异常,df -h,fdisk 命令检查磁盘状态也都没有问题,mount命令检查挂载状态,正常,测试/home 目录,可以正常读写。验证通过,问题解决。
