前一篇,分析了overlayfs的初始化过程。本篇对overlayfs的具体运行进行分析。
overlayfs的super operations,定义在fs/overlay/super.c
static const struct super_operations ovl_super_operations = { .alloc_inode = ovl_alloc_inode, .free_inode = ovl_free_inode, .destroy_inode = ovl_destroy_inode, .drop_inode = generic_delete_inode, .put_super = ovl_put_super, .sync_fs = ovl_sync_fs, .statfs = ovl_statfs, .show_options = ovl_show_options, };
实现了几类接口:
1 inode分配、释放、摧毁等接口。
2 super block释放接口
3 文件系统统计接口
4 sync接口
5 显示参数接口
alloc inode
static struct inode *ovl_alloc_inode(struct super_block *sb) { struct ovl_inode *oi = alloc_inode_sb(sb, ovl_inode_cachep, GFP_KERNEL); if (!oi) return NULL; oi->cache = NULL; oi->redirect = NULL; oi->version = 0; oi->flags = 0; oi->__upperdentry = NULL; oi->lowerdata_redirect = NULL; oi->oe = NULL; mutex_init(&oi->lock); return &oi->vfs_inode; }
相当简单,就是从kmem_cache分配内存,然后初始化私有成员,最后返回内嵌的inode指针。
free inode
static void ovl_free_inode(struct inode *inode) { struct ovl_inode *oi = OVL_I(inode); kfree(oi->redirect); kfree(oi->oe); mutex_destroy(&oi->lock); kmem_cache_free(ovl_inode_cachep, oi); }
释放也相当简单,释放私有数据,然后将内存返还给kmem_cache
destroy inode
根据参考手册,是这个操作是释放alloc inode接口中分配的东西,overlay fs用来释放底层的一些东西
static void ovl_destroy_inode(struct inode *inode) { struct ovl_inode *oi = OVL_I(inode); dput(oi->__upperdentry); ovl_stack_put(ovl_lowerstack(oi->oe), ovl_numlower(oi->oe)); if (S_ISDIR(inode->i_mode)) ovl_dir_cache_free(inode); else kfree(oi->lowerdata_redirect); }
drop inode
这个接口在inode的引用计数为0的时候调用。它只能有2个接口,要么是NULL,要么是generic_delete_inode,它表示删除inode。
在卸载文件系统的时候调用,用来释放所有的资源。
inode、dentry已经提前释放?不走这个接口,这个接口只是释放文件系统私有的数据。
static void ovl_put_super(struct super_block *sb) { struct ovl_fs *ofs = OVL_FS(sb); if (ofs) ovl_free_fs(ofs); }
可以看到,它获得ovl_fs结构体,然后释放它。
将dirty inode保存到disk。分为两种情况:
1 sync
2 syncfs
sync会同步所有的文件系统。所以这里就没有必要同步了。
syncfs就需要同步upper fs。
统计文件系统信息。它调用vfs_statfs来统计。
dentry operations保存在super block
sb->s_d_op = &ovl_dentry_operations
dentry有很多operation,overlayfs只实现了3个,其它都使用默认的。
union fs用这个接口返回底层的dentry。
每当lookup找到一个dentry,就调用这个接口来验证dentry是否仍然有效。对于大多数文件系统,这个接口设置为NULL。
对于网络文件系统和union文件系统。dentry可能在别的地方被修改,所以需要实现这个接口。
返回正数表示dentry仍然有效,否则dentry无效。
d_revalidate可能在rcu-walk环境被调用,此时inode可能为空,此时应该返回-ECHILD
weak版本,表示只要检测inode是否有效即可。
参考
https://docs.kernel.org/6.12/filesystems/vfs.html