自写虚拟文件系统umount后忙inodes/dentries
Busy inodes/dentries after umount in self-written virtual fs
我写了一个简单的 FS,它应该只静态包含一个名为 hello
的文件。该文件应包含字符串 Hello, world!
。我这样做是出于教育目的。当安装 fs 时,它实际上表现得像预期的那样。我可以很好地阅读文件。
然而在卸载后我总是得到
VFS: Busy inodes after unmount of dummyfs. Self-destruct in 5 seconds. Have a nice day...
如果我在挂载 fs 时在 rootdir 上调用 ls,我得到
BUG: Dentry (ptrval){i=2,n=hello} still in use (-1) [unmount of dummyfs dummyfs]
除此之外。
这详细是什么意思,我该如何解决?
mount 和 kill_sb 例程调用 mount_nodev 并为包含此 FS 使用的 2 个 inode 的结构分配 space。
static struct dentry *dummyfs_mount(struct file_system_type* fs_type,
int flags, const char* dev_name, void* data)
{
struct dentry *ret;
ret = mount_nodev(fs_type, flags, data, dummyfs_fill_super);
if (IS_ERR(ret)) {
printk(KERN_ERR "dummyfs_mount failed");
}
return ret;
}
static void dummyfs_kill_sb(struct super_block *sb) {
kfree(sb->s_fs_info);
kill_litter_super(sb);
}
填充超级块方法创建2个inode并将它们保存在mount分配的结构中:
static int dummyfs_fill_super(struct super_block *sb, void *data, int flags)
{
struct dummyfs_info *fsi;
sb->s_magic = DUMMYFS_MAGIC;
sb->s_op = &dummyfs_sops;
fsi = kzalloc(sizeof(struct dummyfs_info), GFP_KERNEL);
sb->s_fs_info = fsi;
fsi->root = new_inode(sb);
fsi->root->i_ino = 1;
fsi->root->i_sb = sb;
fsi->root->i_op = &dummyfs_iops;
fsi->root->i_fop = &dummyfs_dops;
fsi->root->i_atime = fsi->root->i_mtime = fsi->root->i_ctime = current_time(fsi->root);
inode_init_owner(fsi->root, NULL, S_IFDIR);
fsi->file = new_inode(sb);
fsi->file->i_ino = 2;
fsi->file->i_sb = sb;
fsi->file->i_op = &dummyfs_iops;
fsi->file->i_fop = &dummyfs_fops;
fsi->file->i_atime = fsi->file->i_mtime = fsi->file->i_ctime = current_time(fsi->file);
inode_init_owner(fsi->file, fsi->root, S_IFREG);
sb->s_root = d_make_root(fsi->root);
return 0;
}
如果父目录是根目录,查找方法只是将 fsi->file_inode
添加到目录中:
if (parent_inode->i_ino == fsi->root->i_ino) {
d_add(child_dentry, fsi->file);
}
迭代方法在调用时仅发出点文件和 hello
文件:
if (ctx->pos == 0) {
dir_emit_dots(file, ctx);
ret = 0;
}
if (ctx->pos == 2) {
dir_emit(ctx, "hello", 5, file->f_inode->i_ino, DT_UNKNOWN);
++ctx->pos;
ret = 0;
}
读取方法仅使用 copy_to_user
写入静态字符串。偏移量计算正确,在 EOF 上,方法只是 returns 0。但是,由于即使未调用读取方法也会出现问题,我认为这已经超出了这个已经太长的问题的范围。
实际上 运行 我使用来自 git master(4.15+x commit d48fcbd864a008802a90c58a9ceddd9436d11a49
)的用户模式 linux。 userland 是从头开始编译的,init 进程是 Rich Felker 的最小 init 的派生物,我在其中添加了 mount
调用 /proc
、/sys
和 /
(重新挂载)。
我的命令行是./linux ubda=../uml/image root=/dev/ubda
也欢迎任何指向更详尽文档的指针。
使用 gdb 观察 dentry->d_lockref.count
我意识到 umount 中的 kill_litter_super
调用实际上是导致 dentry 问题的原因。用 kill_anon_super
替换它解决了这个问题。
忙碌的 inode 问题几乎消失了,除非我在挂载后立即卸载。分配第二个 inode 也懒惰地解决了这个问题。
我写了一个简单的 FS,它应该只静态包含一个名为 hello
的文件。该文件应包含字符串 Hello, world!
。我这样做是出于教育目的。当安装 fs 时,它实际上表现得像预期的那样。我可以很好地阅读文件。
然而在卸载后我总是得到
VFS: Busy inodes after unmount of dummyfs. Self-destruct in 5 seconds. Have a nice day...
如果我在挂载 fs 时在 rootdir 上调用 ls,我得到
BUG: Dentry (ptrval){i=2,n=hello} still in use (-1) [unmount of dummyfs dummyfs]
除此之外。
这详细是什么意思,我该如何解决?
mount 和 kill_sb 例程调用 mount_nodev 并为包含此 FS 使用的 2 个 inode 的结构分配 space。
static struct dentry *dummyfs_mount(struct file_system_type* fs_type,
int flags, const char* dev_name, void* data)
{
struct dentry *ret;
ret = mount_nodev(fs_type, flags, data, dummyfs_fill_super);
if (IS_ERR(ret)) {
printk(KERN_ERR "dummyfs_mount failed");
}
return ret;
}
static void dummyfs_kill_sb(struct super_block *sb) {
kfree(sb->s_fs_info);
kill_litter_super(sb);
}
填充超级块方法创建2个inode并将它们保存在mount分配的结构中:
static int dummyfs_fill_super(struct super_block *sb, void *data, int flags)
{
struct dummyfs_info *fsi;
sb->s_magic = DUMMYFS_MAGIC;
sb->s_op = &dummyfs_sops;
fsi = kzalloc(sizeof(struct dummyfs_info), GFP_KERNEL);
sb->s_fs_info = fsi;
fsi->root = new_inode(sb);
fsi->root->i_ino = 1;
fsi->root->i_sb = sb;
fsi->root->i_op = &dummyfs_iops;
fsi->root->i_fop = &dummyfs_dops;
fsi->root->i_atime = fsi->root->i_mtime = fsi->root->i_ctime = current_time(fsi->root);
inode_init_owner(fsi->root, NULL, S_IFDIR);
fsi->file = new_inode(sb);
fsi->file->i_ino = 2;
fsi->file->i_sb = sb;
fsi->file->i_op = &dummyfs_iops;
fsi->file->i_fop = &dummyfs_fops;
fsi->file->i_atime = fsi->file->i_mtime = fsi->file->i_ctime = current_time(fsi->file);
inode_init_owner(fsi->file, fsi->root, S_IFREG);
sb->s_root = d_make_root(fsi->root);
return 0;
}
如果父目录是根目录,查找方法只是将 fsi->file_inode
添加到目录中:
if (parent_inode->i_ino == fsi->root->i_ino) {
d_add(child_dentry, fsi->file);
}
迭代方法在调用时仅发出点文件和 hello
文件:
if (ctx->pos == 0) {
dir_emit_dots(file, ctx);
ret = 0;
}
if (ctx->pos == 2) {
dir_emit(ctx, "hello", 5, file->f_inode->i_ino, DT_UNKNOWN);
++ctx->pos;
ret = 0;
}
读取方法仅使用 copy_to_user
写入静态字符串。偏移量计算正确,在 EOF 上,方法只是 returns 0。但是,由于即使未调用读取方法也会出现问题,我认为这已经超出了这个已经太长的问题的范围。
实际上 运行 我使用来自 git master(4.15+x commit d48fcbd864a008802a90c58a9ceddd9436d11a49
)的用户模式 linux。 userland 是从头开始编译的,init 进程是 Rich Felker 的最小 init 的派生物,我在其中添加了 mount
调用 /proc
、/sys
和 /
(重新挂载)。
我的命令行是./linux ubda=../uml/image root=/dev/ubda
也欢迎任何指向更详尽文档的指针。
使用 gdb 观察 dentry->d_lockref.count
我意识到 umount 中的 kill_litter_super
调用实际上是导致 dentry 问题的原因。用 kill_anon_super
替换它解决了这个问题。
忙碌的 inode 问题几乎消失了,除非我在挂载后立即卸载。分配第二个 inode 也懒惰地解决了这个问题。