自制虚拟文件系统卸载后Busy inodes/dentries问题排查求助
咱们先把这个报错的意思说清楚:
一、"Busy inodes/dentries"到底啥意思?
这个报错说白了就是内核觉得你的文件系统里还有inode(索引节点)或者目录项(dentry)还在被用着,没法安全卸载。可能是用户空间还有进程拿着文件句柄没放,也可能是内核内部缓存的dentry/inode没被正确释放——比如你静态创建的那个hello文件,或者根目录的目录项,还有残留的引用没清理干净。
尤其是你说挂载后ls根目录会触发额外报错,这大概率是根目录的dentry或者inode的引用没处理好,ls遍历目录后留下了没释放的引用,进一步加剧了卸载时的Busy问题。
接下来给你拆解具体的修复步骤:
二、一步步修复问题
1. 把静态资源的引用给清干净
你这个虚拟文件系统是静态包含hello文件的,那挂载时创建的这个文件的inode,还有根目录的dentry,卸载时必须手动释放:
- 在
kill_sb函数里,先对根目录的dentry调用d_drop或者d_delete,把它从内核的dentry缓存里踢出去,减少引用计数。 - 对
hello文件的inode,一定要调用iput()来释放它——内核里inode的引用计数(i_count)如果不为0,就会被判定为“busy”。
2. 把superblock的销毁逻辑补全
你用了mount_nodev,那你的struct super_operations结构体里的方法是不是没写全?
put_super方法要负责清理superblock关联的所有资源,比如你自定义的superblock私有数据,还有静态创建的inode。如果有inode链表,要逐个调用iput释放。kill_sb里别自己直接free superblock的内存,交给deactivate_locked_super或者kill_litter_super来处理,确保所有引用都清完了再释放内存。
3. 搞定ls触发的额外报错
ls根目录的时候会遍历目录项,如果你的根目录inode的操作方法有问题,就会报错:
- 确保根目录inode的
i_op指向正确的struct inode_operations,尤其是lookup方法——如果是静态目录,要能正确返回已有的目录项,或者处理不存在的项。 - 给dentry设置正确的
d_op(dentry操作结构体),这样内核在ls结束后才能正确释放目录项的引用,不会留下尾巴。
4. 调试小技巧:找引用残留的地方
如果不确定哪里有残留,可以先用lsof看看用户空间有没有进程占着挂载点:
lsof /你的挂载路径
如果没有用户进程,那问题肯定在内核里。你可以在代码里加打印,跟踪inode->i_count和dentry->d_count的变化,看看哪个地方引用没减下去。
给你举个kill_sb的示例代码参考:
static void myfs_kill_sb(struct super_block *sb) { struct myfs_sb_info *sbi = MYFS_SB(sb); // 先释放静态创建的hello文件inode if (sbi->hello_inode) { iput(sbi->hello_inode); sbi->hello_inode = NULL; } // 清理根目录的dentry引用 d_drop(sb->s_root); // 让内核处理superblock的销毁 kill_litter_super(sb); // 释放自定义的superblock私有数据 kfree(sbi); }
三、最后总结一下
核心问题就是卸载时还有没释放的inode/dentry引用,要么是静态资源没清理,要么是superblock的操作方法没写全,或者目录项管理有问题。按照上面的步骤逐一排查,把该释放的引用都清掉,应该就能解决这个Busy报错和ls的额外问题了。
内容的提问来源于stack exchange,提问作者Richard

