在自行编写的虚拟fs中卸载后出现繁忙的inode / dentries

时间:2018-02-11 12:19:50

标签: linux-kernel vfs

我写了一个简单的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的结构分配空间。

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);
}

fill superblock方法创建2个inode并将它们保存在mount:

分配的struct中
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添加到dentry:

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;
}

read方法只使用copy_to_user编写静态字符串。正确计算偏移量,并且在EOF上,方法只返回0.但是,即使没有调用read方法也会出现问题,我认为这已经超出了这个已经太长的问题了。

对于实际运行它,我使用git master中的用户模式linux(4.15 + x commit d48fcbd864a008802a90c58a9ceddd9436d11a49)。 userland是从头开始编译的,init进程是Rich Felker的最小init的派生,我为mount/proc/sys(remount)添加了/个调用。

我的命令行是./linux ubda=../uml/image root=/dev/ubda

对于更全面的文档的任何指示也表示赞赏。

1 个答案:

答案 0 :(得分:1)

使用gdb观看dentry->d_lockref.count我意识到umount中的kill_litter_super调用实际上是导致dentry问题的原因。用kill_anon_super替换它解决了这个问题。

繁忙的inode问题消失得太多了,除非我在安装后立即卸载。分配第二个inode懒惰地解决了这个问题。