Linux-overlay启动挂载代码分析
背景 Linux-4.1内核使用overlay挂载文件系统后,在写文件遇突然掉电后重启出现修改文件报错问题;问题原因是写文件过程种会在wrok目录下创建Whiteout文件,文件写成功后会删除Whiteout文件,但在异常掉电时Whiteout文件没有被删除,导致系统重启overlay挂载检查work不为空出现异常;下面来分析overlay启动挂载代码流程。代码位置fs/ove...
·
背景
Linux-4.1内核使用overlay挂载文件系统后,在写文件遇突然掉电后重启出现修改文件报错问题;问题原因是写文件过程种会在wrok目录下创建Whiteout文件,文件写成功后会删除Whiteout文件,但在异常掉电时Whiteout文件没有被删除,导致系统重启overlay挂载检查work不为空出现异常;下面来分析overlay启动挂载代码流程。
代码位置
fs/overlayfs/
├── copy_up.c
├── dir.c
├── inode.c
├── Kconfig
├── Makefile
├── overlayfs.h
├── readdir.c
└── super.c
super.c
ovl_init 初始化函数
register_filesystem(&ovl_fs_type); 注册文件系统到系统
static struct file_system_type ovl_fs_type = {
.owner = THIS_MODULE,
.name = "overlay",
.mount = ovl_mount,
.kill_sb = kill_anon_super,
};
MODULE_ALIAS_FS("overlay");
ovl_mount 挂载函数
mount_nodev(fs_type, flags, raw_data, ovl_fill_super); 文件系统挂载类型回调函数ovl_fill_super
ovl_fill_super 回调函数
解析挂载参数
ovl_parse_opt((char *) data, &ufs->config);
static const match_table_t ovl_tokens = {
{OPT_LOWERDIR, "lowerdir=%s"},
{OPT_UPPERDIR, "upperdir=%s"},
{OPT_WORKDIR, "workdir=%s"},
{OPT_ERR, NULL}
};
ovl_mount_dir(ufs->config.upperdir, &upperpath); 挂载upper
ovl_mount_dir(ufs->config.workdir, &workpath); 挂载worker
kstrdup(ufs->config.lowerdir, GFP_KERNEL); 分配内存
ovl_split_lowerdirs(lowertmp); 判断lower层级不大于500
ovl_lower_dir(lower, &stack[numlower], &ufs->lower_namelen, &sb->s_stack_depth); 挂载各lower层级
clone_private_mount(&upperpath);
ovl_workdir_create(ufs->upper_mnt, workpath.dentry); 创建work目录
if (IS_ERR(ufs->workdir)) {
创建失败本该挂载为只读文件系统并打印提示,这里被注释了
//pr_warn("overlayfs: failed to create directory %s/%s (errno: %i); mounting read-only\n",
// ufs->config.workdir, OVL_WORKDIR_NAME, -err);
//sb->s_flags |= MS_RDONLY;
ufs->workdir = NULL; 这里为NULL会导致后面copy-up报空指针错误
clone_private_mount(&stack[i]); 克隆lower私有挂载路径,并设置挂载属性为只读
mnt->mnt_flags |= MNT_READONLY;
d_make_root(ovl_new_inode(sb, S_IFDIR, oe)); 判断是否是根目录挂载
ovl_workdir_create 创建work目录函数
检查work目录是否存在
#define OVL_WORKDIR_NAME "work"
lookup_one_len(OVL_WORKDIR_NAME, dentry, strlen(OVL_WORKDIR_NAME));
目录存在就去清除
ovl_cleanup(dir, work);
ovl_do_rmdir
vfs_rmdir
error = dir->i_op->rmdir(dir, dentry);
fs/ubifs/dir.c +1174
const struct inode_operations ubifs_dir_inode_operations = {
.rmdir = ubifs_rmdir,
err = check_dir_empty(c, d_inode(dentry)); 目录不为空会返回-39,删除失败
walk directory or extended attribute entries. 遍历目录或扩展属性条目。
ubifs_tnc_next_ent(c, &key, &nm);
err = -ENOTEMPTY;
#define ENOTEMPTY 39 /* Directory not empty */
readdir.c
ovl_workdir_cleanup 补丁文件函数:递归清除文件目录
if (!d_is_dir(dentry) || level > 1) {
ovl_cleanup(dir, dentry); 删除文件
return;
}
err = ovl_do_rmdir(dir, dentry); 删除不为空目录失败就删除目录里面的文件
if (err) {
ovl_workdir_cleanup_recurse(&path, level + 1);
ovl_dir_read(path, &rdd); 读出目录信息
list_for_each_entry(p, &list, l_node) {
lookup_one_len(p->name, path->dentry, p->len);
ovl_workdir_cleanup(dir, path->mnt, dentry, level); 目录存在就递归删除
}
}
递归删除work目录下的文件,目录删空后就能删除目录了
扩展
workdir目录下work下创建文件代码:
snprintf(name, sizeof(name), "#%lx", (unsigned long) dentry);
~ # ls /ubifs/work/work/ -l
c--------- 1 root root 0, 0 Mar 7 15:31 #ffffffc03e44b9d8
更多推荐
已为社区贡献4条内容
所有评论(0)