自写虚拟文件系统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 也懒惰地解决了这个问题。