持续创作,加速成长!这是我参与「日新计划 6 月更文挑战」的第23天。
Docker
底层有三驾马车,Namespace
、CGroup
和UnionFS(联合文件系统)
,UnionFS
是Docker
镜像的基础。
UnionFS(联合文件系统)
是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修数据结构题库改作为枸杞一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。
UnionFS
是Docke数据结构c语言版严蔚敏第二版答案r
镜像的基础,镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可数据结构c语言版第二版课后答案以制作各种具体的应用镜像。由于 Linuxdockerhub 下有多种的UnionFS
(如AUFS
、Overlay缓存英文FS
和Btrfs
等),所以我们以实现相对简单的OverlayFS
作为分析对象。
OverlayFS
使用
我们先来看看OverlayFS
基本原理(图片来源于网络):
overlayfs-map
从上图可知,OverlayFS
文件系统主要有三个角色,lowerdir
、upperdir
和merged
。lowerdir
是只读层,用户不能修改这个层的文件;upperdir
是可读写缓存是什么意思层,用户能够修改工资超过5000怎么扣税这个层的文件;而merged
是合并层,把lowerdir
层和upperdir
层的文件合并展示。
使用OverlayFS
前需要进行挂载操作,挂载OverlayFS
文件系统的基本命令如下:
$mount-toverlayoverlay-olowerdir=lower1:lower2,upperdir=upper,workdir=workmerged
参数-t
表示挂载的文件系接口卡统类型,这里设置为overlay
表示文件系统类型为Overl缓存视频变成本地视频ayFS
,而参数-o
指定的是lowe公司让员工下班发手机电量截图rdir
、upperdocker安装dir
和workdir
,最后的merged
目录工商银行就是最终的挂载点目录。下面说明一下-o
参数几个目录的作用:
-
lowerdir
:指定用户需要挂载的l龚俊ower层目录,指定多个目录可以使用:
来分隔(最大支持5数据结构题库00层)。 -
upperdir
:指定用数据结构户需要挂载的upper层目录。 -
workdir
:指定文件系统的工作基础目录,挂载后内容会被清空,且在使用过程中其内容用户不可见。
OverlayFS
实现原理
下面我们开始分析OverlayFS
的实现原理。
OverlayFS
文件系统的作用是合并upper
目录和low工龄差一年工资差多少er
目录的中的内容,如果upp工龄越长退休金越多吗er
目录与lower
目录接口是什么同时存在同一文件或目录,那么Overdocker菜鸟教程layFS
文件系统怎么处理呢?
-
如果
upper
和lower
目录下同时数据结构有哪些存在同一文件,那么按upper
目录的文件为准。比如upper
与lower
目录下同时存在文件a.txt
,那么按upper
目录工商银行的a.txt
文件为Docker准。 -
如果
upper
和lowe工资超过5000怎么扣税r
目录下同时存在同一目录,那么把upper
目录与lower
目录的内容合并起来。比如upper
与lower
目录下同时存在目录test
,那么把upper
目缓存是什么意思录下的test
目录中的内容与lower
目录下的test
目录中的内容合并起来。
为了简单起见,本文使用的是Linux 3.18.3
版本,此版本的OverlayFS
文件系统只支持一层的lower
目录,所以简化了多层lower
合并的逻辑。
OverlayFS
文件系统挂载
前面介绍过挂载OverlayFS
文件系统的命令,挂载OverlayFS
文件系统会触发系统调用接口卡sys_mount()
,而sys_mount()
会执行虚拟文件系统
的通用挂载过程,如申请缓存是什么意思和初始化超级块对象(super block)
(接口英文可参考:虚拟文件系统)。然后调用具体文件系统的fill_super()
接口来填充超级块对象
,对于OverlayFS
文件系统而言,最公积金终会调缓存视频在手机哪里找用ovl_fill_super()
函数来填充超级块对象
。
我们来分析一下ovl_fill_super()缓存视频怎样转入相册
函数的主要部分:
staticintovl_fill_super(structsuper_block*sb,void*data,intsilent){structpathlowerpath;structpathupperpath;structpathworkpath;structinode*root_inode;structdentry*root_dentry;structovl_entry*oe;...oe=ovl_alloc_entry();//新建一个ovl_entry对象...//新建一个inode对象root_inode=ovl_new_inode(sb,S_IFDIR,oe);//新建一个dentry对象,并且指向新建的inode对象root_inoderoot_dentry=d_make_root(root_inode);...oe->__upperdentry=upperpath.dentry;//指向upper目录的dentry对象oe->lowerdentry=lowerpath.dentry;//指向lower目录的dentry对象root_dentry->d_fsdata=oe;//保存ovl_entry对象到新建dentry对象的d_fsdata字段中...sb->s_root=root_dentry;//保存新建的dentry对象到超级块的s_root字段中...return0;}
ovl_fill_super()
函数主要完成以下几个步骤:
-
调用
ovl_alloc_entry()
创建一个ovl_e数据结构c语言版ntry
对象oe
。 -
调用
ovl_new_inode()
创建一个inode
对象root_inod数据结构教程第5版李春葆答案e
。 -
调用
d_make接口和抽象类的区别_root()
创建一个数据结构dentry
对象root_dentry
,并且将其指向root_inode
。 -
将
oe
的__upperdentry
字段指向upper
目录的dentry
,而将lo工龄越长退休金越多吗werdentry
字段指向lower
目录的dentry
。 -
将
root_dentry
的d_fsdata
字段指向oe
。 -
将
超级块对象
的s_root
字段指向root_dentry
。
最后,其各个数据结构的关系如下图:
overlay接口和抽象类的区别fs-relation
在上面的代码中出现的ovl_entry
结构用于记录OverlayFS
文件系统中某个文件或者目录所在的真实位置,由于OverlayFS
文件系统是一个联合文件系统,并不是真正存数据结构c语言版在于磁盘的文件系统,所以在OverlayFS
文件系统中的文件都要指向真实文件系统中的位置。
而ovl_entry
结数据结构与算法构就是用来指向真实文件系统的位置,其定义如下:
structovl_entry{structdentry*__upperdentry;structdentry*lowerdentry;structovl_dir_cache*cache;union{struct{u64version;boolopaque;};structrcu_headrcu;};};
下面解宫颈癌析一下ovl_entry
结构各个字段的作用:
-
__upperdentry
:如果文件存在于upper
目录中,那么指向此文件公积金的dentry对象。 -
lowerdentry
:如果文件存在于lower
目录中,那接口和抽象类的区别么指向此文件的dentry对象。 -
cache
:如果指向的目录,那么数据结构实验报告缓存此目录的文件接口卡列表。 -
version
:用于记录此ovl_entry
结构的版本。 -
opaque
:此文件或目录是否被隐藏。
__upperdentry
和lowe数据结构知识点总结rdentr接口y
是ovl_edocker常用命令ntry
结构比较重要的两个字段,一个指向文件所在upper
目录中的dentry对象,另外一个指向文件所在lower
目录中的dentry对象,如下图:
overlayfs-mount
在OverlayFS
文件系统中,每个文件或目录都由一个ovl_entry
结构管理。如果我们把dentry
结构当成是文件或目录的接口crc错误计数实体,那么__uppe接口测试rdentry
指向的就是文件或目录所在upper
目录中的实体,而lowerdentry
指向的就是文件或目录所在lower
目录的实体docker菜鸟教程。
读取OverlayFS
文件数据结构系统的目录
一般来说,我们调用ls
命令读取目录的列表时,会触发内存以下过程:
-
调用
openat()
系统调用打开目录。 -
调用
getdents()
系统调用读取目录的列表。
打开目录
o工龄差一年工资差多少pen(接口文档)
系统调用最终会调用具体文件系统的open(接口文档)
方法来打开文件接口卡,对于OverlayFS
文件系统调用的是ovl_di缓存的视频在哪r_open()
函数,其实现如下:
staticintovl_dir_open(structinode*inode,structfile*file){structpathrealpath;structfile*realfile;structovl_dir_file*od;enumovl_path_typetype;//申请一个ovl_dir_file对象od=kzalloc(sizeof(structovl_dir_file),GFP_KERNEL);if(!od)return-ENOMEM;type=ovl_path_real(file->f_path.dentry,&realpath);realfile=ovl_path_open(&realpath,file->f_flags);if(IS_ERR(realfile)){kfree(od);returnPTR_ERR(realfile);}//初始化ovl_dir_file对象INIT_LIST_HEAD(&od->cursor.l_node);od->realfile=realfile;od->is_real=(type!=OVL_PATH_MERGE);od->is_upper=(type!=OVL_PATH_LOWER);od->cursor.is_cursor=true;file->private_data=od;//保存到file对象的private_data字段中return0;}
ovl_dir_open()
函数主要完成的工作包括:
-
创建一个缓存文件夹名称
ovl_dir_file
对象od
。 -
调用
ovl_path_real()
函数分析当前文件接口类型或目录所属的类型: -
如果是一个目录,并且
upper
目录和lower宫颈癌
目录同时存在,那么返回OVL_数据结构教程第5版李春葆答案PATH_MERGE
,表示需要接口类型对目录进行合并。 -
如果是一个目录,并且只存在于
upper
目录中。或者是一个文件,并且存docker容器在于upper
目录中docker常用命令,那么返回OVL_PATH_UPPER
,表接口自动化示从upper
目录中读取。 -
否则返回
OVL_PATH_LOWER
,表示从lower
目录中读取。 -
把
ovl_dir_file
对象保存到 file 对象的private_data
字段中。
ovldocker命令_dir_fi数据结构知识点总结le
对象用于描述缓存OverlayFS
文件系统的目工商银行录或文件的信息,其定义如下:
structovl_dir_file{boolis_real;boolis_upper;structovl_dir_cache*cache;structovl_cache_entrycursor;structfile*realfile;structfile*upperfile;};structovl_dir_cache{longrefcount;u64version;structlist_headentries;};
ovl_dir_file
对象各个字段的含义如下:
-
is_r接口卡eal
:如不需要合并,设置为true。 -
is_upper
:是否需要从upper
目录中读取。 -
c缓存视频合并appa工龄差一年工资差多少che
:用于缓存目录的文件列表。 -
cursor
:用dockerhub于迭代目录列表时的游标。 -
rea缓存英文l接口类型file
:真实文件或目录的dentr接口英文y
对象。 -
upperfile
:指向文件或目录所在upper
目录中的dentry
对象。
读取目录列表
读取目录中的文件列表是通过getdents()
系统调用,而getdents()
系统调用最终会调用具体文件系统的iterate(数据结构有哪些)
接口,对于OverlayFS
文google件系统而言,调用的就是ovl_iterate()
函数。其实现如下:
staticintovl_iterate(structfile*file,structdir_context*ctx){structovl_dir_file*od=file->private_data;structdentry*dentry=file->f_path.dentry;if(!ctx->pos)ovl_dir_reset(file);if(od->is_real)//如果不需要合并,直接调用iterate_dir()函数读取真实的目录列表即可returniterate_dir(od->realfile,ctx);if(!od->cache){//如果还没有创建缓存对象structovl_dir_cache*cache;cache=ovl_cache_get(dentry);//读取合并后目录的文件列表,并且缓存起来if(IS_ERR(cache))returnPTR_ERR(cache);od->cache=cache;//保持缓存对象ovl_seek_cursor(od,ctx->pos);//移动游标}while(od->cursor.l_node.next!=&od->cache->entries){//遍历合并后的目录中的文件列表structovl_cache_entry*p;p=list_entry(od->cursor.l_node.next,structovl_cache_entry,l_node);if(!p->is_cursor){if(!p->is_whiteout){if(!dir_emit(ctx,p->name,p->len,p->ino,p->type))//写到用户空间的缓冲区中break;}ctx->pos++;}list_move(&od->cursor.l_node,&p->l_node);//移动到下一个文件}return0;}
ovl_iterate()
函数的主要工作有以下几个步骤:
-
如果不需要合并目录(就是
i缓存是什么意思s_real
为true),那么直接调用iterate_dir()
函数读取真实的目录列表。 -
如果
ovl_dir_file
对象的缓存没有被创建,那么调用ovl_cache_get()
创建缓存对象,ovl_cache_get()
除了创建缓存对象外,还会读取合并后的目录中的文件列表,并保存到缓存对象的entries
链表中。 -
遍历合并后的目录中的文件列表,并把文件列表写到用户空间的缓存中,这docker是干什么的样用户就可以获取合并后的文件列表。
我们主要来分析一下怎么通过ovl_cach工龄越长退休金越多吗e_get()
函数来读取合并后的目录中的接口文档文件列表:
staticstructovl_dir_cache*ovl_cache_get(structdentry*dentry){intres;structovl_dir_cache*cache;...cache=kzalloc(sizeof(structovl_dir_cache),GFP_KERNEL);if(!cache)returnERR_PTR(-ENOMEM);cache->refcount=1;INIT_LIST_HEAD(&cache->entries);res=ovl_dir_read_merged(dentry,&cache->entries);...cache->version=ovl_dentry_version_get(dentry);ovl_set_dir_cache(dentry,cache);returncache;}
ovl_cache_get()
函缓存英文数首先创建一个ovl_dir_cac接口和抽象类的区别he
缓存对象,并且调用ovl_dir_read_merged()
函数读取合并目录的文件列表,ovl_di接口和抽象类的区别r_read_merged()
函数实现如下:
staticintovl_dir_read_merged(structdentry*dentry,structlist_head*list){interr;structpathlowerpath;structpathupperpath;structovl_readdir_datardd={.ctx.actor=ovl_fill_merge,.list=list,.root=RB_ROOT,.is_merge=false,};ovl_path_lower(dentry,&lowerpath);//获取lower目录ovl_path_upper(dentry,&upperpath);//获取upper目录if(upperpath.dentry){//如果upper目录存在,读取upper目录中的文件列表err=ovl_dir_read(&upperpath,&rdd);if(err)gotoout;if(lowerpath.dentry){err=ovl_dir_mark_whiteouts(upperpath.dentry,&rdd);if(err)gotoout;}}if(lowerpath.dentry){//如果lower目录存在,读取lower目录中的文件列表list_add(&rdd.middle,rdd.list);rdd.is_merge=true;err=ovl_dir_read(&lowerpath,&rdd);list_del(&rdd.middle);}out:returnerr;}
ovl_dir_read_merged()
函数的实现比较简单,调用了ovl_dir_read()
函数读取lower
和upper
目录中的文件列表,并保存到list
参数中。
这里有个问题,就是如果lower
目录和u接口卡pper
目录同时存在相同的文件怎办?
在调用ovl_dir_read()
函数读取lower
和upper
目录中的文件列表时会缓存视频在手机哪里找调用ovl_fill_merge()
函数过滤相同的文件。过滤操作通过红黑树来实现,过滤过程如下:
-
读取
upper
目录中的文件列表,保存到list
列表中,并且保存到红黑树中接口crc错误计数。 -
读取
lower
目录中的文google件列表,查询红黑树中是否已经存在此文件,如果存在,那么跳过此文件,否则添加到list
列表中