自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Overlay Fs聯(lián)合文件系統(tǒng)源碼解析系列(一)掛載過程詳解

系統(tǒng) OpenHarmony
Overlay fs是一種虛擬文件系統(tǒng),它的實現(xiàn)是在現(xiàn)有文件系統(tǒng)上又添加了一個抽象層,從而達(dá)到實現(xiàn)聯(lián)合文件系統(tǒng)的目的。而這個抽象層的實現(xiàn)借助了負(fù)責(zé)的結(jié)構(gòu)體類型以及他們之間的關(guān)聯(lián)關(guān)系而實現(xiàn),所以,要理解Overlay fs聯(lián)合文件系統(tǒng)的關(guān)鍵就是理清這些結(jié)構(gòu)體的組織關(guān)系。

??想了解更多關(guān)于開源的內(nèi)容,請訪問:??

??51CTO 開源基礎(chǔ)軟件社區(qū)??

??https://ost.51cto.com??

引言

分析Overlay fs聯(lián)合文件系統(tǒng)源自于培養(yǎng)OpenHarmony高端人才的動機(jī),通過講Overlay fs聯(lián)合文件系統(tǒng)移植到Liteos_A內(nèi)核的項目培養(yǎng)一批精通OpenHarmony內(nèi)核的人才,也通過本文向各位熱愛OpenHarmony內(nèi)核的技術(shù)開發(fā)者和愛好者敘說一個復(fù)雜文件系統(tǒng)的具體實現(xiàn)過程和包含的軟件思想,我們是一群熱愛OpenHarmony,熱愛開源,傳遞技術(shù)正能量的OpenHarmony開發(fā)工程師。

Overlay fs是一種聯(lián)合文件系統(tǒng),它以堆疊的形式將不同的目錄掛載到同一個虛擬文件系統(tǒng)下。Overlayfs文件系統(tǒng)像其他文件系統(tǒng)一樣,先被作為一種文件系統(tǒng)注冊到Linux內(nèi)核,而后用戶通過Mount命令觸發(fā)其掛載,然后才得以被用戶使用。

需要注意的是,Overlay fs在Linux內(nèi)核3.18后就被默認(rèn)加入內(nèi)核模塊了,查看Linux內(nèi)核版本可以使用如下命令:

uname -r

為了更好地幫助我們理解overlay fs的作用,可以在Linux上開啟overlay模塊,并做些簡單的實驗,再去閱讀源碼會有更好的效果。在Linux上開啟overlay fs模塊的方法主要有兩種,具體如下所示:

  1. 使用如下命令進(jìn)行加載overlay模塊。
# 查看是否已加載overlay 模塊
lsmod | grep overlay

# 若沒有加載則可手動加載
modprobe overlay
  1. overlay會在掛載的時候自動加載該文件系統(tǒng),故可以直接使用如下命令進(jìn)行overlay模塊的安裝和掛載。
# 直接繼續(xù)overlay fs的掛載,自動加載overlay模塊
mount -t overlay overlay -o lowerdir=/lower,upperdir=/upper,workdir=/work /merged

加載overlay模塊后,就可以進(jìn)行一些實驗,而本文主要關(guān)注Overlay fs掛載流程,結(jié)合Linux內(nèi)核源碼分析掛載過程的執(zhí)行過程,并通過將該過程中涉及到的主要數(shù)據(jù)結(jié)構(gòu)之間的聯(lián)系繪制成結(jié)構(gòu)圖,來盡可能清晰地為讀者展現(xiàn)一張文件系統(tǒng)核心數(shù)據(jù)結(jié)構(gòu)整體圖。

鑒于作者知識有限,僅以個人視角,一孔窺豹,不成體系,讀者還需實地閱讀代碼才能加深理解。

若發(fā)現(xiàn)文中錯誤,可以聯(lián)系筆者進(jìn)行修改。

1、Overlay fs掛載命令介紹

Overlay fs掛載命令格式如下:

# 該命令指定一個lower層,一個upper層
sudo mount -t overlay overlay -o lowerdir=/lower,upperdir=/upper,workdir=/work /merged

# 若需要指定多個lower層,可以使用如下命令
sudo mount -t overlay overlay -o lowerdir=/lower1:/lower2:/lower3,upperdir=/upper,workdir=/work /merged

其中,overlay文件系統(tǒng)掛載的命令參數(shù)解釋如下:

  • -t overlayfs,指定掛載Overlay fs聯(lián)合文件系統(tǒng)。
  • -o lowerdir=/lower,upperdir=/upper,workdir=/work,即lower層目錄為**/lower**,uppper層目錄為**/upper**,工作目錄為**/work**。
  • /merged為Overlay文件系統(tǒng)的合并層,其為upper和lower兩個目錄的堆疊,具體的堆疊規(guī)則稍后說明。
需要注意的幾點:
  1. workdir=/work<u>不可為空或者省略</u>,否則會導(dǎo)致掛載失敗。
  2. 在創(chuàng)建工作目錄時,系統(tǒng)會默認(rèn)在該目錄下創(chuàng)建一個名稱為WORK的新目錄,<u>用于存放臨時文件或者目錄</u>。例如在刪除由Lower層和Upper層目錄合成的目錄時,既需要刪除Upper層同名的目錄,又要中創(chuàng)建一個同名whiteout類型目錄,要保證這個刪除和創(chuàng)建兩個操作的原子性,就要借助于WORK工作目錄。現(xiàn)在WORK目錄中創(chuàng)建臨時目錄,設(shè)置屬性,然后將臨時目錄與目標(biāo)目錄rename,借助于Upper層文件系統(tǒng)保證rename的原子性,然后在刪除交互到WORK目錄下的目錄,完成整個刪除操作。即使這個過程,中間遇到突然關(guān)機(jī)的情況,在WORK目錄中也是只有剛創(chuàng)建的臨時文件或者交換過去的臨時文件,在下一次系統(tǒng)掛載的過程中自動清空其中的內(nèi)容。這樣,就可以保證整個過程的原子性。

Overlay文件系統(tǒng)的不同層合并規(guī)則以及讀寫規(guī)則有如下幾點:

  1. Overlay 對Upper層目錄或者文件有寫權(quán)限,對Lower層目錄或者文件<u>僅具有讀權(quán)限</u>。
  2. lowerdir和upperdir兩個目錄存在同名文件時,lowerdir的文件將會被隱藏,用戶只能看到upperdir的文件。
  3. lowerdir低優(yōu)先級的同目錄同名文件將會被隱藏。
  4. 用戶修改mergedir中來自upperdir的數(shù)據(jù)時,數(shù)據(jù)將直接寫入upperdir中原來目錄中,刪除文件也同理。
  5. 用戶修改mergedir中來自lowerdir的數(shù)據(jù)時,lowerdir中內(nèi)容均不會發(fā)生任何改變。
  6. 如果某一個目錄單純來自lowerdir或者lowerdir和upperdir合并,默認(rèn)無法進(jìn)行rename系統(tǒng)調(diào)用。

為了簡要形象地說明Overlay文件系統(tǒng)掛載之后的堆疊(合并)規(guī)則,可以參考下圖,圖中含有一個lowedir和upperdir,兩者合并成一個merged層:

Overlay fs聯(lián)合文件系統(tǒng)源碼解析系列(一)掛載過程詳解 -開源基礎(chǔ)軟件社區(qū)

這一小結(jié)中Overlay fs文件系統(tǒng)掛載的的命令行參數(shù),就介紹到這里,下面主要關(guān)注Overlayfs的掛載過程。

2、mount系統(tǒng)調(diào)用過程

使能Linux內(nèi)核Overlay fs文件系統(tǒng)編譯選項CONFIG_OVERLAY_FS,或者以=y靜態(tài)方式編譯進(jìn)內(nèi)核,或者先以=m內(nèi)核模塊方式編譯再加載該內(nèi)核模塊,在Linux內(nèi)核層添加對Overlay fs聯(lián)合文件系統(tǒng)的支持。 然后以mount -t overlay overlayfs,觸發(fā)mount系統(tǒng)調(diào)用,進(jìn)行掛載Overlayfs文件系統(tǒng)的流程。

mount系統(tǒng)調(diào)用掛載Overlay fs文件系統(tǒng)的過程如下:

SYSCALL_DEFINE5(mount,,,,,,,) // fs/namespace.c
|-> user_path_at(AT_FDCWD, dir_name, LOOKUP_FOLLOW, &path);
|-> do_mount(kernel_dev, dir_name, kernel_type, flags, options);
|-> path_mount(dev_name, &path, type_page, flags, data_page);
|-> do_new_mount()
| // (1) 找到指定文件系統(tǒng)
|-> type = get_fs_type(fstype);
| |-> find_filesystem(name, len)
| |-> for (p = &file_systems; *p; p = &(*p)->next)
| |-> strncmp((*p)->name, name, len) == 0
| |-> return p;
|
| // (2) 創(chuàng)建fc
|-> fc = fs_context_for_mount(type, sb_flags);
| |-> alloc_fs_context(fs_type, NULL, sb_flags, 0, FS_CONTEXT_FOR_MOUNT);
| |-> fc = kzalloc(sizeof(struct fs_context), GFP_KERNEL);
| |-> fc->fs_type = get_filesystem(fs_type);
| |-> legacy_init_fs_context(fc);
| |-> fc->fs_private = kzalloc(sizeof(struct legacy_fs_context), GFP_KERNEL);
| |-> fc->ops = &legacy_fs_context_ops;
|
| // (3) 將fc的root指針指向overlayfs掛載點根root目錄
|-> vfs_get_tree(fc)
| | // 通過fc的get_tree間接調(diào)用文件系統(tǒng)mount函數(shù),以獲得掛載節(jié)點root目錄項(記錄在fc中)
| | // fc->ops->get_tree(fc); => legacy_get_tree
| |-> legacy_get_tree(fc) // 將掛載點的root目錄項賦值到fc的root
| |-> root = fc->fs_type->mount(fc->fs_type, fc->sb_flags, fc->source, ctx->legacy_data);
| |-> fc->root = root; // struct dentry *
|
| // (4) 創(chuàng)建mount實體,并將其掛載到supper_block的掛載鏈表中
|-> do_new_mount_fc(fc, path, mnt_flags);// path的形參即為mountpoint,是實際文件系統(tǒng)中mount掛載目標(biāo)路徑
|-> mnt = vfs_create_mount(fc);
| |-> mnt = alloc_vfsmnt(fc->source ?: "none");
| |-> mnt->mnt.mnt_sb = fc->root->d_sb;
| |-> mnt->mnt.mnt_root = dget(fc->root);
| |-> mnt->mnt_mountpoint = mnt->mnt.mnt_root;
| |-> mnt->mnt_parent = mnt;
| |-> list_add_tail(&mnt->mnt_instance, &mnt->mnt.mnt_sb->s_mounts);
|
|-> do_add_mount(real_mount(mnt), mp, mountpoint, mnt_flags);

如上系統(tǒng)調(diào)用mount的簡化調(diào)用堆棧中可以看出,整個mount流程可以總結(jié)為4個步驟:
(1)根據(jù)文件系統(tǒng)名稱fstype,在內(nèi)核所支持的文件系統(tǒng)鏈表中,找到對應(yīng)的文件系統(tǒng),若沒有找到則先加載該模塊。
(2)創(chuàng)建文件系統(tǒng)上下文空間,并初步初始化,對Overlay fs聯(lián)合文件系統(tǒng),fc的ops設(shè)置為legacy_fs_context_ops。
(3)由文件系統(tǒng)fc間接調(diào)用文件系統(tǒng)的mount接口,對Overlay fs文件系統(tǒng)來說,該指針指向ovl_mount(),由該函數(shù)完成Overlay fs文件系統(tǒng)的掛載。
(4)在Overlay fs文件系統(tǒng)掛載完成后,創(chuàng)建一個mount節(jié)點,并將其掛載到Overlayfs文件系統(tǒng)supper_block的掛載鏈表內(nèi)。

上述幾個步驟中**,關(guān)鍵結(jié)構(gòu)體的鏈接情況**可以參考下圖:

Overlay fs聯(lián)合文件系統(tǒng)源碼解析系列(一)掛載過程詳解 -開源基礎(chǔ)軟件社區(qū)

如上圖,為了便于理解和記憶,可以將mount過程中的關(guān)鍵結(jié)構(gòu)體抽象成4個層次,即mount層,fs_context層,fs文件系統(tǒng)層,以及目錄項節(jié)點層。首先,從系統(tǒng)支持的文件系統(tǒng)鏈表中獲得Overlayfs文件系統(tǒng),然后創(chuàng)建fs_context對象,并以此間接地調(diào)用Overlay fs文件系統(tǒng)的mount接口函數(shù)。由ovl_mount()掛載函數(shù)完成Overlayfs文件系統(tǒng)所特有的掛載過程,有上圖Overlayfs有一個獨有的表示其文件系統(tǒng)結(jié)構(gòu)的結(jié)構(gòu)體類型struct ovl_fs,作為其super_block的私有數(shù)據(jù),以有別與其他的文件系統(tǒng)。

在第3小結(jié)中,我們將詳細(xì)地解析Overlay fs文件系統(tǒng)的掛載過程。

3、Overlay fs文件系掛載過程詳解

如前文所述,真正實現(xiàn)Overlay fs聯(lián)合文件系統(tǒng)掛載過程的函數(shù)是由fc_context間接調(diào)用的ovl_mount()過程,過程也比較簡單,就是申請一個supper_block,
然后使用Overlayfs文件系系統(tǒng)的信息將其填充。 具體過程如下:

ovl_mount() // fs/overlayfs/super.c
|-> mount_nodev(fs_type, flags, raw_data, ovl_fill_super); // return "dentry* s_root"
| // (1) 為新掛載點創(chuàng)建superblock
|-> s = sget() // struct super_block *
| |-> s = alloc_super(type, (flags & ~SB_SUBMOUNT), user_ns);
| |-> list_add_tail(&s->s_list, &super_blocks);
|
| // fill_super()
|-> ovl_fill_super(s, data, flags & SB_SILENT ? 1 : 0)
|-> struct ovl_fs *ofs; // private information held for overlayfs's superblock
|-> struct ovl_layer *layers;
|
|-> ofs = kzalloc(sizeof(struct ovl_fs), GFP_KERNEL);
|-> sb->s_d_op = &ovl_dentry_operations;
|-> ovl_parse_opt((char *) data, &ofs->config);
|-> numlower = ovl_split_lowerdirs(splitlower);
|
| // 創(chuàng)建聯(lián)合文件系統(tǒng)層級數(shù)組
|-> layers = kcalloc(numlower + 1, sizeof(struct ovl_layer), GFP_KERNEL);
|-> ofs->layers = layers;
|
|-> sb->s_op = &ovl_super_operations;
|
| // 設(shè)置upperlayer:設(shè)置layer的trap執(zhí)行upperpath目錄的inode;依據(jù)upperpath在實際文件系統(tǒng)中的掛載點填充layer的掛載點(ovl掛載的root為實際文件系統(tǒng)中一指定目錄);
|-> ovl_get_upper(sb, ofs, &layers[0], &upperpath);
| | // 獲得upperlayer目錄在實際文件系統(tǒng)上路徑:若路徑未打開過,則創(chuàng)建路徑上的所有節(jié)點的dentry與inode
| |-> ovl_mount_dir(ofs->config.upperdir, upperpath);
| | // 為掛載點創(chuàng)建一個inode,保存在trap中:新inode的private數(shù)據(jù)指向?qū)嶋H文件系統(tǒng)中掛載點目錄的inode
| |-> ovl_setup_trap(sb, upperpath->dentry, &upper_layer->trap, "upperdir");
| | // 拷貝upper層實際文件系統(tǒng)路徑的掛載點為虛擬堆疊文件系統(tǒng)一個層次的新mount節(jié)點,且新的mount節(jié)點的root目錄為uppper目錄;
| |-> upper_mnt = clone_private_mount(upperpath);
| |-> upper_layer->mnt = upper_mnt;
|
| // 創(chuàng)建workdir: workbasedir為指定的實際文件系統(tǒng)內(nèi)的目錄,workbasedir_trap對workbasedir的inode的trap;workdir為workbasedir下創(chuàng)建的默認(rèn)名稱為“work”的目錄
|-> ovl_get_workdir(sb, ofs, &upperpath);
| |-> ofs->workbasedir = dget(workpath.dentry);
| | // 申請一個ovl_inode,使其private指向?qū)嶋H文件系統(tǒng)inode,新對象地址保存在ofs->workbasedir_trap內(nèi)
| |-> ovl_setup_trap(sb, ofs->workbasedir, &ofs->workbasedir_trap, "workdir");
| |
| |-> ovl_make_workdir(sb, ofs, &workpath);
|
| // 逐個獲取lower層,檢查是否已經(jīng)有打上“trap”標(biāo)記的inode,同時為每個lower層的root inode打上“trap”標(biāo)記
|-> oe = ovl_get_lowerstack(sb, splitlower, numlower, ofs, layers);
|
| // 對每個層對應(yīng)root inode的parent遞歸檢查是否已經(jīng)打上“trap”標(biāo)記,重疊層可能是互為祖先關(guān)系
|-> ovl_check_overlapping_layers(sb, ofs);
|
|-> sb->s_fs_info = ofs;
|
|-> root_dentry = ovl_get_root(sb, upperpath.dentry, oe);
|
|-> sb->s_root = root_dentry;

由于Overlay fs文件系統(tǒng)疊層聯(lián)合文件系統(tǒng),那么在執(zhí)行mount命令時指定upper目錄、lower目錄及work目錄,是如何在Overlayfs內(nèi)被組織利用,進(jìn)而實現(xiàn)層疊聯(lián)合文件系統(tǒng)的呢?該過程為Overlayfs文件掛載的核心過程,主要在ovl_fill_super()函數(shù)內(nèi)完成。

在ovl_fill_super()的主要過程為:
(1)從overlayfs掛載命令中獲取Lower層的個數(shù),并以此分配layers空間。
(2)解析Upper層,包括掛載路徑,原系統(tǒng)的掛載節(jié)點、掛載目錄等。
(3)解析Work工作目錄,并做必要合法性檢測。
(4)解析lower層,可能包含多個疊層,需要對每一層都進(jìn)行解析,并將解析結(jié)果保存layers中。
(5)設(shè)置overlayfs系統(tǒng)根目錄。

其中,比較復(fù)雜而且關(guān)系到Overlayfs整個實現(xiàn)機(jī)制的步驟為(2)、(4)和(5),在下面的內(nèi)容中將著重介紹這些內(nèi)容,之后便可以對整個Overlay fs聯(lián)合文件系統(tǒng)的掛載過程形成一個整體藍(lán)圖。

(1)Upper層過程解析

Overlay fs對upper層目錄的解析過程在ovl_get_upper()函數(shù)中完成,主要分為3個步驟:

(1)查找upper層目標(biāo)目錄的路徑,是根據(jù)掛載Overlayfs提供的upperdir路徑,層層查找得到。
(2)設(shè)置upper_layer的trap,trap即為Overlayfs文件系統(tǒng)中的一個inode,其私有數(shù)據(jù)指向upper目錄在實際文件系統(tǒng)中的inode。
(3)創(chuàng)建一個upper層目錄掛載節(jié)點的克隆體,并設(shè)置為upper_layer的mnt成員。

如下為ovl_get_upper()函數(shù)的調(diào)用堆棧:

ovl_get_upper(sb, ofs, &layers[0], &upperpath);
|-> struct vfsmount *upper_mnt;
| // (1)解析upper目錄:沿著用戶指定的upper目錄路徑解析,直至找到目錄的目錄項
|-> ovl_mount_dir(ofs->config.upperdir, upperpath);
| |-> tmp = kstrdup(name, GFP_KERNEL);
| |-> ovl_mount_dir_noesc(tmp, path);
| |-> kern_path(name, LOOKUP_FOLLOW, path);
| |-> filename_lookup(AT_FDCWD, getname_kernel(name), flags, path, NULL);
|
| // (2)設(shè)置upper_layer的trap:即從Overlayfs超級塊新申請一個inode,并將upper目錄的inode設(shè)置為其私有數(shù)據(jù)
|-> ovl_setup_trap(sb, upperpath->dentry, &upper_layer->trap, "upperdir");
| |-> trap = ovl_get_trap_inode(sb, dir);
| | |-> struct inode *key = d_inode(dir);
| | |-> struct inode *trap;
| | |-> trap = iget5_locked(sb, (unsigned long) key, ovl_inode_test, ovl_inode_set, key);
| | |-> return trap;
| |-> *ptrap = trap;
|
| // (3)創(chuàng)建一個upper層目錄掛載節(jié)點clone體,并賦值給upper_layer的mnt成員
|-> upper_mnt = clone_private_mount(upperpath);
| |-> struct mount *old_mnt = real_mount(path->mnt);
| |-> struct mount *new_mnt;
| | // 創(chuàng)建一個upper層的mount節(jié)點的clone體,并且將其掛載到upper層超級塊的掛載點鏈表上
| |-> new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE);
| | |-> struct super_block *sb = old->mnt.mnt_sb;
| | |-> struct mount *mnt;
| | |
| | |-> mnt = alloc_vfsmnt(old->mnt_devname);
| | |-> mnt->mnt.mnt_sb = sb;
| | |-> mnt->mnt.mnt_root = dget(root);
| | |-> list_add_tail(&mnt->mnt_instance, &sb->s_mounts);
| |
| |-> return &new_mnt->mnt;
|-> upper_layer->mnt = upper_mnt;

為方便理解,將ovl_get_upper()中涉及的結(jié)構(gòu)類型ovl_layer、mount、dentry和inode等的關(guān)聯(lián)關(guān)系繪制成如下圖形:

Overlay fs聯(lián)合文件系統(tǒng)源碼解析系列(一)掛載過程詳解 -開源基礎(chǔ)軟件社區(qū)

(2)lower層過程解析

Overlayfs對upper層目錄的解析過程在ovl_get_lowerstack()函數(shù)中完成,lower層與upper層不同是lower層可能有多個目錄疊加在一起,需要對lower層。
目錄做批量處理,過程有些類似于ovl_get_upper()對upper層的解析過程:

static struct ovl_entry *
ovl_get_lowerstack(struct super_block *sb, const char *lower, unsigned int numlower, struct ovl_fs *ofs, struct ovl_layer *layers)
|-> struct path *stack = NULL;
|-> struct ovl_entry *oe;
|
| // (1)分配并初始化深度與lower層目錄樹對應(yīng)的path數(shù)組
|-> stack = kcalloc(numlower, sizeof(struct path), GFP_KERNEL);
|-> for (i = 0; i < numlower; i++) {
| // 依次解析所有l(wèi)ower層目錄
|-> err = ovl_lower_dir(lower, &stack[i], ofs, &sb->s_stack_depth);
|-> }
|
| // 根據(jù)lower層目錄數(shù)組設(shè)置Overlayfs文件系統(tǒng)及其layers
|-> ovl_get_layers(sb, ofs, stack, numlower, layers);
| |-> ofs->fs = kcalloc(numlower + 1, sizeof(struct ovl_sb), GFP_KERNEL);
| |
| |-> ofs->fs[0].sb = ovl_upper_mnt(ofs)->mnt_sb;
| |-> ofs->fs[0].is_lower = false;
| |
| |-> for (i = 0; i < numlower; i++) {
| |-> ovl_setup_trap(sb, stack[i].dentry, &trap, "lowerdir");
| |-> mnt = clone_private_mount(&stack[i]);
| |-> layers[ofs->numlayer].trap = trap;
| |-> layers[ofs->numlayer].mnt = mnt;
| |-> ofs->fs[fsid].is_lower = true;
| |-> }
|
| // 設(shè)置overlayfs文件系統(tǒng)的根目錄ovl_entry
|-> oe = ovl_alloc_entry(numlower);
|-> for (i = 0; i < numlower; i++) {
|-> oe->lowerstack[i].dentry = dget(stack[i].dentry);
|-> oe->lowerstack[i].layer = &ofs->layers[i+1];
|-> }
|
| // 釋放臨時存放lower層路徑的path數(shù)組
|-> kfree(stack);
|-> return oe;

仔細(xì)閱讀如上代碼,我們會發(fā)現(xiàn)除了批量執(zhí)行類似于ovl_get_upper()中解析目錄操作外,還增加了分配并初始化一個ovl_entry類型結(jié)構(gòu)實例的過程。

該ovl_entry的在Overlayfs虛擬文件系統(tǒng)中的功能主要為Overlayfs文件系統(tǒng)中的目錄提供額外的聯(lián)合文件系統(tǒng)的Lower層目錄信息,其作用我們將在root根目錄初始化的過程中見到。

將ovl_get_lowerstack()內(nèi)創(chuàng)建的數(shù)組和相關(guān)結(jié)構(gòu)體類型的關(guān)系繪制成如下圖形:

Overlay fs聯(lián)合文件系統(tǒng)源碼解析系列(一)掛載過程詳解 -開源基礎(chǔ)軟件社區(qū)

從上圖可知,ovl_get_lowerstack()的功能相對于ovl_get_upper()揉進(jìn)了額外的功能,除了構(gòu)建ovl_fs的layers數(shù)組外,還構(gòu)建了fs數(shù)組,另外還構(gòu)建Overlayfs目錄的ovl_entry結(jié)構(gòu)體對象??梢悦黠@的感覺到,這部分代碼不像Linux內(nèi)核一貫嚴(yán)謹(jǐn)?shù)拇a風(fēng)格,在一個函數(shù)混合了多個功能。 其中的lowerstack關(guān)系圖可以參考下圖,分別用圖表和代碼的形式繪制。

Overlay fs聯(lián)合文件系統(tǒng)源碼解析系列(一)掛載過程詳解 -開源基礎(chǔ)軟件社區(qū)

(2)root根目錄構(gòu)建過程解析

文件系統(tǒng)的目錄和文件操作是以root根目錄為起點,而對于Overlayfs聯(lián)合文件系統(tǒng),知道root根目錄的構(gòu)建過程,是理解該聯(lián)合文件系統(tǒng)操作目錄的關(guān)鍵。Overlayfs文件系統(tǒng)依靠ovl_get_root()完成根目錄的構(gòu)建,具體調(diào)用堆棧如下:

static struct dentry *
ovl_get_root(struct super_block *sb, struct dentry *upperdentry, struct ovl_entry *oe)
|-> struct dentry *root;
|-> struct ovl_path *lowerpath = &oe->lowerstack[0];
|-> struct ovl_inode_params oip = {
|-> .upperdentry = upperdentry,
|-> .lowerpath = lowerpath,
|-> };
|
|-> root = d_make_root(ovl_new_inode(sb, S_IFDIR, 0));
|-> root->d_fsdata = oe;
|
|-> ovl_inode_init(d_inode(root), &oip, ino, fsid);
| |-> OVL_I(inode)->__upperdentry = oip->upperdentry;
| |-> OVL_I(inode)->lower = igrab(d_inode(oip->lowerpath->dentry));
|
|-> ovl_dentry_update_reval(root, upperdentry, DCACHE_OP_WEAK_REVALIDATE);
|-> return root;

為便于理解其中繁雜的結(jié)構(gòu)體之間的組合關(guān)心,還是將他們直接的關(guān)系繪制成如下圖形:

Overlay fs聯(lián)合文件系統(tǒng)源碼解析系列(一)掛載過程詳解 -開源基礎(chǔ)軟件社區(qū)

在構(gòu)建root根目錄的過程中,ovl_get_root()首先調(diào)用d_make_root(ovl_new_inode(sb, S_IFDIR, 0))創(chuàng)建一個ovl_inode類型的Overlay fs系統(tǒng)的inode節(jié)點,該節(jié)點中包含一個VFS系統(tǒng)的inode結(jié)構(gòu)體;再創(chuàng)建一個跟目錄價的dentry目錄項,并將ovl_inode包含的inode成員的地址賦值給dentry目錄項的d_inode指針。然后,ovl_get_root()將ovl_get_lowerstack()解析lower層目錄時創(chuàng)建的ovl_entry結(jié)構(gòu)體對象作為root根目錄dentry的私有數(shù)據(jù)。最后,ovl_get_root()借助upper和lower目錄在ovl_inode_init()函數(shù)內(nèi)初始化了root根目錄在VFS中的inode節(jié)點,借此間接設(shè)置了ovl_inode對象的上層目錄的dentry和第一個lower層的inode節(jié)點地址。

至此,我們完成了掛載Overlayfs文件系統(tǒng)的整個過程。

總結(jié)

Overlay fs是一種虛擬文件系統(tǒng),它的實現(xiàn)是在現(xiàn)有文件系統(tǒng)上又添加了一個抽象層,從而達(dá)到實現(xiàn)聯(lián)合文件系統(tǒng)的目的。而這個抽象層的實現(xiàn)借助了負(fù)責(zé)的結(jié)構(gòu)體類型以及他們之間的關(guān)聯(lián)關(guān)系而實現(xiàn),所以,要理解Overlay fs聯(lián)合文件系統(tǒng)的關(guān)鍵就是理清這些結(jié)構(gòu)體的組織關(guān)系。

為了能明白地解析Overlayfs文件系統(tǒng)掛載過程,本文只盡可能詳細(xì)跟蹤了代碼執(zhí)行過程,同時也省略了“自以為”不影響描述整個過程的代碼,主要目的也是為了是讀者更加關(guān)注在掛載流程。至于其他機(jī)制,例如目錄的合并、目錄或者文件的刪除、目錄的遍歷等,這里不做涉及,將在后續(xù)的博客中介紹。

??想了解更多關(guān)于開源的內(nèi)容,請訪問:??

??51CTO 開源基礎(chǔ)軟件社區(qū)??

??https://ost.51cto.com??

責(zé)任編輯:jianghua 來源: 51CTO 開源基礎(chǔ)軟件社區(qū)
相關(guān)推薦

2023-07-19 14:00:50

OverlayC語言

2021-05-31 07:50:59

Linux文件系統(tǒng)

2014-12-22 11:30:54

DockerAUFS云計算

2021-06-06 16:55:22

Linux文件系統(tǒng)

2023-09-27 23:19:04

Linuxmount

2010-01-08 18:01:03

Ubuntu硬盤操作

2010-11-15 16:41:29

Oracle文件

2010-04-13 13:31:31

Unix文件

2018-01-18 17:14:58

分布式文件系統(tǒng)FastDFS

2021-08-25 10:10:52

findmnt命令Linux

2021-03-10 08:02:58

Findmnt命令系統(tǒng)

2022-04-15 08:00:00

FUSE開發(fā)Android

2010-07-27 10:15:38

NFS網(wǎng)絡(luò)文件系統(tǒng)

2010-03-02 15:09:26

Linux mount

2009-12-10 14:27:07

Linux操作系統(tǒng)

2010-06-04 18:45:43

Hadoop分布式文件

2009-12-02 15:46:36

Linux系統(tǒng)掛接

2022-08-09 15:30:41

Linux

2021-06-21 14:52:45

磁盤機(jī)械磁盤固態(tài)磁盤

2009-10-28 14:29:40

linux文件系統(tǒng)
點贊
收藏

51CTO技術(shù)棧公眾號