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

Overlay FS聯(lián)合文件系統(tǒng)源碼解析系列—目錄接口詳解

開(kāi)發(fā) 前端
本文重點(diǎn)介紹Overlay FS的目錄相關(guān)的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)和目錄的相關(guān)接口,讓讀者能體會(huì)到所謂的Overlay文件系統(tǒng)的特點(diǎn),很多實(shí)現(xiàn)細(xì)節(jié)是有別于傳統(tǒng)的文件系統(tǒng),均需考慮upper層和lower層不同情況,但是萬(wàn)變不離其宗,我們學(xué)習(xí)文件系統(tǒng)必須抓住文件系統(tǒng)的主要數(shù)據(jù)和接口的實(shí)現(xiàn),這對(duì)C語(yǔ)言實(shí)現(xiàn)其它底層軟件開(kāi)發(fā)也是一種必備技能。

想了解更多關(guān)于開(kāi)源的內(nèi)容,請(qǐng)?jiān)L問(wèn):

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

https://ost.51cto.com

引言

在前篇中介紹了Linux是如何掛載Overlay文件系統(tǒng)的,重點(diǎn)關(guān)注了Overlay的掛載流程的實(shí)現(xiàn)和關(guān)鍵數(shù)據(jù)結(jié)構(gòu)的關(guān)系,而在本文中主要介紹Overlay FS的目錄相關(guān)的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)和目錄的相關(guān)接口,其中比較復(fù)雜的接口將會(huì)在下一篇中展開(kāi)介紹。

一、Overlay 關(guān)鍵數(shù)據(jù)結(jié)構(gòu)

1、目錄文件

struct ovl_dir_file {
    bool is_real;
    bool is_upper;
    struct ovl_dir_cache *cache;
    struct list_head *cursor;
    struct file *realfile;
    struct file *upperfile;
};

2、目錄接口

// fs/overlayfs/readdir.c
const struct file_operations ovl_dir_operations = {
    .read       = generic_read_dir,
    .open       = ovl_dir_open,
    .iterate    = ovl_iterate,
    .llseek     = ovl_dir_llseek,
    .fsync      = ovl_dir_fsync,
    .release    = ovl_dir_release,
};

3、目錄inode操作

// fs/overlayfs/dir.c
const struct inode_operations ovl_dir_inode_operations = {
    .lookup     = ovl_lookup,   // fs/overlayfs/namei.c
    .mkdir      = ovl_mkdir,    // fs/overlayfs/dir.c
    .symlink    = ovl_symlink,
    .unlink     = ovl_unlink,
    .rmdir      = ovl_rmdir,
    .rename     = ovl_rename,
    .link       = ovl_link,
    .setattr    = ovl_setattr,
    .create     = ovl_create,
    .mknod      = ovl_mknod,
    .permission = ovl_permission,
    .getattr    = ovl_getattr,
    .listxattr  = ovl_listxattr,
    .get_acl    = ovl_get_acl,
    .update_time    = ovl_update_time,
};

二、目錄操作

1、創(chuàng)建目錄

(1)創(chuàng)建目錄系統(tǒng)調(diào)用

// ./fs/namei.c
SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
|-> do_mkdirat(AT_FDCWD, pathname, mode);
    |-> struct dentry *dentry;
    |-> struct path path;
    | // (1)創(chuàng)建目錄項(xiàng):創(chuàng)建ovl_dentry,同時(shí)將其加入到其父目錄的子目錄項(xiàng)鏈表中
    |-> dentry = user_path_create(dfd, pathname, &path, lookup_flags); // path保存父目錄路徑;dentry保存新建目錄項(xiàng)內(nèi)存對(duì)象
    |            |-> filename_create(dfd, getname(pathname), path, lookup_flags);
    |                |-> name = filename_parentat(dfd, name, lookup_flags, path, &last, &type);
    |                |-> dentry = __lookup_hash(&last, path->dentry, lookup_flags)
    |                             |-> dentry = d_alloc(base, name);
    |
    | // (2)創(chuàng)建ovl inode:調(diào)用對(duì)應(yīng)文件系統(tǒng)目錄ops中的mkdir創(chuàng)建inode,并關(guān)聯(lián)inode到dentry
    |-> vfs_mkdir(path.dentry->d_inode, dentry, mode);
        |-> dir->i_op->mkdir(dir, dentry, mode) // 參數(shù):父目錄inode、新目錄的目錄項(xiàng)、模式

(2)Overlay FS中ovl_mkdir創(chuàng)建目錄的過(guò)程

在Overlay fs聯(lián)合文件系統(tǒng)下,創(chuàng)建目錄有2種情況:
(1)upper層和lower層均無(wú)同名目錄,則直接在upper層創(chuàng)建。
(2)<u>lower層有同名目錄,但是之后被刪除了</u>,則需要在已經(jīng)存在whiteout文件的情況下創(chuàng)建目錄。

ovl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) // fs/overlayfs/dir.c
|-> ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL)
    |   // (1)創(chuàng)建ovl_inode節(jié)點(diǎn)
    |-> inode = ovl_new_inode(dentry->d_sb, mode, rdev);
    |-> inode->i_state |= I_CREATING;
    |
    |   // (2)聯(lián)合文件系統(tǒng)調(diào)用(實(shí)際文件系統(tǒng))創(chuàng)建節(jié)點(diǎn),并連接(link)虛擬文件系統(tǒng)inode和實(shí)際文件系統(tǒng)inode
    |   // 實(shí)際文件系統(tǒng)創(chuàng)建新目錄,并將實(shí)際文件系統(tǒng)的inode賦值給虛擬文件系統(tǒng)的目錄項(xiàng)(dentry),同時(shí)虛擬文件系統(tǒng)的目錄項(xiàng)作為虛擬文件系統(tǒng)目錄項(xiàng)的一個(gè)別名
    |-> ovl_create_or_link(dentry, inode, &attr, false) // 參數(shù):虛擬文件系統(tǒng)目錄項(xiàng)、虛擬文件系統(tǒng)inode節(jié)點(diǎn)、屬性、非原始節(jié)點(diǎn)
        | // 父目錄進(jìn)行copyup:將parent的lower目錄內(nèi)容copyup到upper層。若存在upper層,則直接返回。
        |-> ovl_copy_up(parent);// copyup將會(huì)在后續(xù)的文章中詳細(xì)介紹
        |-> if (!ovl_dentry_is_whiteout(dentry))
        |       // 不存在whiteout文件,則直接在upper層創(chuàng)建新目錄
        |->     ovl_create_upper(dentry, inode, attr);
        |-> else
        |       // 存在whiteout文件,則在upper層創(chuàng)建新目錄并..???..
        |->     ovl_create_over_whiteout(dentry, inode, attr);
(3)直接在upper層創(chuàng)建新目錄
參數(shù)inode為ovl_inode,而dentry則是與之對(duì)應(yīng)的overlayfs文件系統(tǒng)目錄節(jié)點(diǎn)的目錄項(xiàng)。
ovl_create_upper(struct dentry *dentry, struct inode *inode, struct ovl_cattr *attr)
| // 將overlayfs目錄轉(zhuǎn)換成源文件路徑
|-> upperdir = ovl_dentry_upper(dentry->d_parent); // 原始實(shí)際文件系統(tǒng)中的父目錄
|-> struct inode *udir = upperdir->d_inode;
|-> struct dentry *newdentry;
| // (1)創(chuàng)建父目錄的upper層創(chuàng)建新目錄
|-> newdentry = ovl_create_real(udir, lookup_one_len(dentry->d_name.name, upperdir, dentry->d_name.len), attr);
|               |-> ovl_mkdir_real(dir, &newdentry, attr->mode);
|                   |-> ovl_do_mkdir(dir, dentry, mode)
|                       |-> vfs_mkdir()
|                           |-> dir->i_op->mkdir(dir, dentry, mode); 
|
| // 實(shí)例化overlayfs目錄項(xiàng)和ovl_inode:
| // (1)ovl_inode的i_private和__upperdentry分別指向upper的inode和目錄項(xiàng);(2)ovl目錄項(xiàng)的d_inode指向ovl_inode
|-> ovl_instantiate(dentry, inode, newdentry, !!attr->hardlink); // ovl: dentry; ovl: inode; realfs: newdentry, ..
    |-> struct ovl_inode_params oip = {
    |      .upperdentry = newdentry, // 實(shí)際文件系統(tǒng)目錄項(xiàng)
    |      .newinode = inode, // ovl_inode
    |   };
    |
    | // 返回ovl_inode的指針:ovl_inode的i_private和__upperdentry分別指向upper的inode和目錄項(xiàng)
    |-> inode = ovl_get_inode(dentry->d_sb, &oip);
    |           | // 返回ovl_inode的指針,并將realinode作為ovl_inode私有數(shù)據(jù)
    |           |-> inode = ovl_iget5(sb, oip->newinode, key);
    |           | // 設(shè)置ovlinode的__upperdentry指向upper的目錄項(xiàng)upperdentry
    |           |-> ovl_inode_init(inode, oip, ino, fsid);
    |               |-> OVL_I(inode)->__upperdentry = oip->upperdentry;
    |
    | // 設(shè)置ovl目錄項(xiàng)的d_inode指向ovl_inode
    |-> d_instantiate(dentry, inode); // overlayfs文件系統(tǒng)目錄項(xiàng)和inode
        |-> __d_instantiate(entry, inode);
            |-> __d_set_inode_and_type(dentry, inode, add_flags);
            |-> dentry->d_inode = inode;

ovl_create_upper()執(zhí)行完后,新創(chuàng)建的overlayfs目錄結(jié)構(gòu),如下圖所示:

overlayfs:                                       struct ovl_inode                       
           struct dentry                         +---------------------------------+    
           +--------------------------------+    |redirect: char*;                 |    
           |d_parent: struct dentry *;      |    |mnt_mountpoint: struct dentry*;  |    
           |d_name: struct qstr;            |    |vfs_inode: struct inode;         |    
           |d_inode: struct inode*;  -------+--->|+-struct inode -----------------+|    
           |d_op: struct dentry_operations*;|    ||i_op: struct inode_operations*;||    
           |d_sb: struct super_block;       |    ||i_sb: struct super_block *;    ||    
           |d_fsdata: void *;               |    || ...                           ||    
           | ...                            |    ||i_private: void *  ------------++---+
           +--------------------------------+    |+-------------------------------+|   |
                                                 |__upperdentry: struct dentry*; --+-+ |
                                                 |lower: struct inode*;            | | |
                                                 |...                              | | |
                                                 +---------------------------------+ | |
                                                                                     | |
upper:     +-------------------------------------------------------------------------+ |
           |                                     +-------------------------------------+
           |                                     |                                      
           V                                     V                                      
           struct dentry                         struct inode                
           +--------------------------------+ +->+-------------------------------+      
           |d_parent: struct dentry *;      | |  |i_op: struct inode_operations*;|      
           |d_name: struct qstr;            | |  |i_sb: struct super_block *;    |      
           |d_inode: struct inode*; --------+-+  |i_ino: unsigned long;          |      
           |d_op: struct dentry_operations*;|    | ...                           |      
           |d_sb: struct super_block;       |    +-------------------------------+      
           | ...                            |                                           
           +--------------------------------+
(4)創(chuàng)建新目錄,但lower層存在被刪除的同名目錄
參數(shù)ovl_create_upper()一樣:inode為ovl_inode,而dentry則是與之對(duì)應(yīng)的overlayfs文件系統(tǒng)目錄節(jié)點(diǎn)的目錄項(xiàng)。
ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, struct ovl_cattr *attr)
|-> struct dentry *workdir = ovl_workdir(dentry);
|-> struct inode *wdir = workdir->d_inode;
|-> struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);   // upper父目錄項(xiàng)
|-> struct inode *udir = upperdir->d_inode;                         // upper父目錄inode
|-> struct dentry *upper;                                           // ovl目錄項(xiàng)
|-> struct dentry *newdentry;                                       // upper目錄項(xiàng)
|
| // (1)在upper層父目錄中查找目錄項(xiàng)(whiteout)
|-> upper = lookup_one_len(dentry->d_name.name, upperdir, dentry->d_name.len);
| // (2)在workdir目錄下創(chuàng)建臨時(shí)目錄
|-> newdentry = ovl_create_temp(workdir, cattr);
|               |-> ovl_create_real(d_inode(workdir), ovl_lookup_temp(workdir), attr);
| // (3)設(shè)置worddir下新建臨時(shí)目錄屬性為opaque
|-> ovl_set_opaque(dentry, newdentry);
| // (4)workdir新建的臨時(shí)目錄與upper的whiteout目錄做交互rename
|-> ovl_do_rename(wdir, newdentry, udir, upper, RENAME_EXCHANGE);
| // (5)清除rename后workdir下的廢棄文件(whiteout)
|-> ovl_cleanup(wdir, upper);
|
| // 實(shí)例化overlayfs目錄項(xiàng)和ovl_inode:
| // (1)ovl_inode的i_private和__upperdentry分別指向upper的inode和目錄項(xiàng);(2)ovl目錄項(xiàng)的d_inode指向ovl_inode.
|-> ovl_instantiate(dentry, inode, newdentry, !!attr->hardlink);

由上面流程可見(jiàn),與ovl_create_upper()相比,ovl_create_over_whiteout()先在work目錄下創(chuàng)建一個(gè)臨時(shí)目錄,并設(shè)置目錄屬性為opaque,以屏蔽lower層同名目錄。然后將workdir目錄下臨時(shí)目錄與upper層的whiteout文件做重命名互換,并清除互換后的垃圾文件。

2、刪除目錄ovl_rmdir()

將要被刪除的聯(lián)合文件系統(tǒng)目錄主要有3種途徑
(1)目錄只來(lái)自u(píng)pper層,則直接刪除即可;
(2)目錄只來(lái)自lower層,則需要建立對(duì)lower層同名目錄的whiteout文件;
(3)目錄是由uppwer層和lower層目錄合成,則既要?jiǎng)h除upper層目錄,又要建立lower層同名目錄的whiteout文件;

但是上面的情況,經(jīng)過(guò)簡(jiǎn)化合并為兩種情況:

  • 不存在于lower層,則直接刪除即可
  • 存在于lower層,需要生成whiteout文件屏蔽底層目錄。

下面代碼為Overlay fs聯(lián)合文件系統(tǒng)刪除目錄的過(guò)程,留意下列過(guò)程中根據(jù)lower_positive是否為true,即是否存在lower層,分別調(diào)用了函數(shù)ovl_remove_upper()或者ovl_remove_and_whiteout()。

ovl_rmdir(struct inode *dir, struct dentry *dentry)
|-> ovl_do_remove(dentry, true);
    |-> ovl_check_empty_dir(dentry, &list);
    |   | // 獲取目錄下的所有目錄和文件列掛到list鏈表
    |   |-> ovl_dir_read_merged(dentry, list, &root);
    |   |   |-> for (idx = 0; idx != -1; idx = next) {
    |   |   |->     next = ovl_path_next(idx, dentry, &realpath);
    |   |   |->     ovl_dir_read(&realpath, &rdd);
    |   |   |        |-> realfile = ovl_path_open(realpath, O_RDONLY | O_LARGEFILE);
    |   |   |        |-> iterate_dir(realfile, &rdd->ctx);
    |   |   |-> }
    |   |-> 
    |
    | // copyup父目錄:若存在upper層,則ovl_copy_up()直接返回。
    |-> ovl_copy_up(dentry->d_parent);
    |-> if (!lower_positive)
    |->     err = ovl_remove_upper(dentry, is_dir, &list);
    |-> else
    |->     err = ovl_remove_and_whiteout(dentry, &list);
    |
    |-> clear_nlink(dentry->d_inode);
    |
    |-> upperdentry = ovl_dentry_upper(dentry);
    |-> if (upperdentry)
    |->     ovl_copyattr(d_inode(upperdentry), d_inode(dentry));

(1)刪除不存在lower層的目錄

ovl_remove_upper(dentry, is_dir, &list)
|-> struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent)
|-> struct inode *dir = upperdir->d_inode
|-> struct dentry *opaquedir = NULL
|-> opaquedir = ovl_clear_empty(dentry, list) // 返回opaque目錄
|-> upper = ovl_lookup_upper(ofs, dentry->d_name.name, upperdir,dentry->d_name.len)// 找到需要?jiǎng)h除的dengtry
|-> err = ovl_do_rmdir(ofs, dir, upper)
| |-> vfs_rmdir(ovl_upper_mnt_userns(ofs), dir, dentry) // 直接調(diào)用vfs_mkdir進(jìn)行刪除
| |...

(2)刪除存在lower層的目錄

ovl_remove_and_whiteout(dentry, &list);
|-> struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
|-> workdir = ovl_workdir(dentry);
| // 返回opaque目錄:已經(jīng)完成了目標(biāo)目錄的刪除
|-> opaquedir = ovl_clear_empty(dentry, list);
|               |-> opaquedir = ovl_create_temp(workdir, OVL_CATTR(stat.mode));
|               |-> ovl_copy_xattr(dentry->d_sb, upper, opaquedir);
|               |-> ovl_set_opaque(dentry, opaquedir);
|               | // rename后opaquedir與upper的inode內(nèi)容互換
|               |-> ovl_do_rename(wdir, opaquedir, udir, upper, RENAME_EXCHANGE);
|               | // 遞歸刪除目標(biāo)目錄下的upper層內(nèi)容
|               |-> ovl_cleanup_whiteouts(upper, list);
|               | // 刪除目標(biāo)目錄
|               |-> ovl_cleanup(wdir, upper);
|                   |-> ovl_do_rmdir(wdir, wdentry);
|                       |-> vfs_rmdir(dir, dentry);
| // 此時(shí),upper即opaquedir
|-> upper = lookup_one_len(dentry->d_name.name, upperdir, dentry->d_name.len);
|-> ovl_cleanup_and_whiteout(ofs, d_inode(upperdir), upper);
    |-> whiteout = ovl_whiteout(ofs);
    |              |-> whiteout = ovl_lookup_temp(workdir);
    |              |              |-> snprintf(name, sizeof(name), "#%x", atomic_inc_return(&temp_id));
    |              |              |-> temp = lookup_one_len(name, workdir, strlen(name));
    |              |-> ovl_do_whiteout(wdir, whiteout);
    |-> ovl_do_rename(wdir, whiteout, dir, dentry, flags);
    |-> ...

如果 要?jiǎng)h除的文件是upper層覆蓋lower層的文件,要?jiǎng)h除的目錄是上下層合并的目錄,其實(shí)是前兩個(gè)場(chǎng)景的合并,Overlay fs即需要?jiǎng)h除upper層對(duì)應(yīng)文件系統(tǒng)中的文件或目錄,也需要在對(duì)應(yīng)位置創(chuàng)建同名whiteout文件,讓upper層的文件被刪除后不至于lower層的文件被暴露出來(lái)。

3、ovl_dir_open打開(kāi)目錄

假設(shè)目錄是merged目錄:

ovl_dir_open(struct inode *inode, struct file *file) // fs/overlayfs/readdir.c
|-> struct ovl_dir_file *od;
|-> od = kzalloc(sizeof(struct ovl_dir_file), GFP_KERNEL);
| // 獲取目錄路徑:若目錄是merged或者upper目錄,則獲得upper路徑;否則,獲得lower路徑。
|-> type = ovl_path_real(file->f_path.dentry, &realpath);
|          |-> type = ovl_path_type(dentry);
|          |          |-> type = __OVL_PATH_UPPER;
|          |          |-> type  |= __OVL_PATH_MERGE;
|          |
|          |-> ovl_path_lower(dentry, path);
|          | // < or >
|          |-> ovl_path_upper(dentry, path);
|              |-> path->mnt = ovl_upper_mnt(ofs);
|              |-> path->dentry = ovl_dentry_upper(dentry);
|
| // 打開(kāi)upper或者lower目錄
|-> realfile = ovl_dir_open_realfile(file, &realpath);
|              |-> struct file *res;
|              |-> res = ovl_path_open(realpath, O_RDONLY | (file->f_flags & O_LARGEFILE));
|                        |-> dentry_open(path, flags, current_cred());
|                            |-> struct file *f;
|                            |-> f = alloc_empty_file(flags, cred);
|                            |-> vfs_open(path, f);
|                                |-> open = f->f_op->open(inode, f);
|
| // realfile作為ovldir_file的實(shí)際文件;ovl_dir_file又作為file的私有數(shù)據(jù)
|-> od->realfile = realfile;
|-> od->is_real = ovl_dir_is_real(file->f_path.dentry);
|-> od->is_upper = OVL_TYPE_UPPER(type);
|-> file->private_data = od;

目錄打開(kāi)后形成如下結(jié)構(gòu):

struct file                      
           +------------------------------+ 
           |f_path: struct path;          | 
           |f_inode: struct inode;        | 
           |f_op: struct file_operations*;| 
           |private_data: void *; --------+-+
           | ...                          | |
           +------------------------------+ |
                                    +-------+
Overlay fs:                          |  struct ovl_dir_file                 
                                    +->+-----------------------------+
                                       |is_real: bool                |
                                       |is_upper: unsigned;          |
                                       |cache: struct ovl_dir_cache*;|
                                       |cursor: struct list_head*;   |
                                       |realfile: struct file*; -----+-+
                                       |upperfile: struct file*;     | |
                                       +-----------------------------+ |
                                                              +--------+
                                                              |                                 
                                                              |  struct file                     
upper:                                                        +->+------------------------------+
                                                                 |f_path: struct path;          |
                                                                 |f_inode: struct inode;        |
                                                                 |f_op: struct file_operations*;|
                                                                 |private_data: void *;         |
                                                                 | ...                          |
                                                                 +------------------------------+

(1)OVL目錄內(nèi)查找目標(biāo)目錄或者文件

每當(dāng)在這樣一個(gè)合并的目錄中請(qǐng)求查找時(shí),就會(huì)在每個(gè)實(shí)際的目錄中進(jìn)行查找,而合并的結(jié)果則緩存在屬于覆蓋文件系統(tǒng)的目錄中。結(jié)果被緩存在屬于疊加文件系統(tǒng)的目錄中。如果兩個(gè)實(shí)際的查詢都能找到目錄,那么這兩個(gè)查詢都會(huì)被存儲(chǔ)起來(lái),并且創(chuàng)建一個(gè)合并的目錄。創(chuàng)建一個(gè)合并的目錄,否則只存儲(chǔ)一個(gè):如果上層目錄存在,則存儲(chǔ)下層目錄。只有來(lái)自目錄的名稱列表被合并。其他內(nèi)容,如元數(shù)據(jù)和擴(kuò)展屬性,只報(bào)告給上層目錄,下層目錄的這些屬性被隱藏。

/* 
  DESCRIPTION: 在特定文件系統(tǒng)中,在目錄dir下查找dentry中包含
  PARAMS:
    @dir: 父目錄,在該目錄下查找目標(biāo)目錄或者文件,但是函數(shù)內(nèi)未使用,父目錄由dentry的d_parent獲得。
    @dentry: 目標(biāo)目錄或者文件的目錄項(xiàng),包含name,但是缺少inode
    @flags*/
ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) // fs/overlayfs/dir.c
| // (1)在upper層父目錄中查找目標(biāo)文件或者目錄:
| // (1.1)從ovl目錄項(xiàng)的ovl_inode反向索引到實(shí)際文件系統(tǒng)的dentry
|-> upperdir = ovl_dentry_upper(dentry->d_parent);
| // (1.2)在upper層目錄下搜索目標(biāo)文件或者目錄,若存在則使用局部目錄項(xiàng)指針upperdentry指向目標(biāo)目錄項(xiàng)
|-> ovl_lookup_layer(upperdir, &d, &upperdentry, true); // 參數(shù):實(shí)際文件系統(tǒng)中的父目錄項(xiàng)、...、目標(biāo)實(shí)際文件系統(tǒng)中目錄項(xiàng)返回值、...
|   |-> ovl_lookup_single(base, d, d->name.name, d->name.len,0, "", ret, drop_negative) // ret,即&upperdentry
|       |-> this = ovl_lookup_positive_unlocked(name, base, namelen, drop_negative);
|       |          |-> lookup_one_len_unlocked(name, base, len);
|       |              |-> lookup_slow(&this, base, 0); 
|       |                   |-> __lookup_slow(name, dir, flags);
|       |                       |-> dentry = d_alloc_parallel(dir, name, &wq);
|       |                       |-> old = inode->i_op->lookup(inode, dentry, flags);
|       |                       |-> dentry = old;
|       |-> *ret = this;
|
| // (2)在所有l(wèi)ower層父目錄中查找目標(biāo)文件或者目錄
|-> for (i = 0; !d.stop && i < poe->numlower; i++) {
|->     struct ovl_path lower = poe->lowerstack[i];
|->     d.last = i == poe->numlower - 1;
|->     ovl_lookup_layer(lower.dentry, &d, &this, false);
|->     ...
|->     stack[ctr].dentry = this;
|->     stack[ctr].layer = lower.layer;
|->     ctr++;
|-> }
|
|   // (3)分配ovl_entry,其中包括根據(jù)堆疊層次確定的ovl_path層次數(shù)
|-> oe = ovl_alloc_entry(ctr);
|-> memcpy(oe->lowerstack, stack, sizeof(struct ovl_path) * ctr);
|-> dentry->d_fsdata = oe;
|
|   // 關(guān)聯(lián)實(shí)際文件系統(tǒng)denty和inode到虛擬文件系統(tǒng)inode
|-> inode = ovl_get_inode(dentry->d_sb, &oip);

根據(jù)上面的流程,在overlayfs文件系統(tǒng)的一個(gè)目錄下查詢一個(gè)目錄或者文件的流程為,通過(guò)ovl系統(tǒng)中父目錄dentry找到實(shí)際文件系統(tǒng)的目錄項(xiàng)和inode,找到目標(biāo)目錄或者文件對(duì)應(yīng)的dentry和inode。

struct ovl_entry                 
                                     +==>+-------------------------------+
                                     H   |lowerstack: struct ovl_path[]; |
                                     H   |numlower: unsigned;            |
                                     H   | ...                           |
                                     H   +-------------------------------+
                                     H
                                     H   struct ovl_inode                   
   struct dentry(d_parent)           H   +---------------------------------+       
   +--------------------------------+H   |redirect: char*;                 |           
   |d_parent: struct dentry *;      |H   |mnt_mountpoint: struct dentry*;  |                  
   |d_name: struct qstr;            |H   |vfs_inode: struct inode;         |               
   |d_inode: struct inode*;==========H==>|+-struct inode -----------------+|                    
   |d_op: struct dentry_operations*;|H   ||i_op: struct inode_operations*;||                    
   |d_sb: struct super_block;       |H   ||i_sb: struct super_block *;    ||                
   |d_fsdata: void *;  ==========(2)=H   ||i_ino: unsigned long;          ||
   | ...                            |    || ...                           ||
   +--------------------------------+    |+-------------------------------+|      struct dentry(base dir in realfs)      
                                         |__upperdentry: struct dentry*; ==(1)===>+--------------------------------+      
                                         |lower: struct inode*;            |      |d_parent: struct dentry *;      |     
                                         |...                              |      |d_name: struct qstr;            |                                    
                                         +---------------------------------+      |d_inode: struct inode*; ============H                                  
                                                                                  |d_op: struct dentry_operations*;|   H                                            
                                                                                  |d_sb: struct super_block;       |   H
                                                                                  | ...                            |   H
                                                                                  +--------------------------------+   H
                                                                                       struct inode(lowerendtry->inode)V
                                                                                        +-------------------------------+
                                                                                        |i_op: struct inode_operations*;| ==> 實(shí)際文件系統(tǒng)的lookup()
                                                                                        |i_sb: struct super_block *;    |
                                                                                        |i_ino: unsigned long;          |
                                                                                        | ...                           |
                                                                                        +-------------------------------+

查找到的目錄或者文件,在ovl文件系統(tǒng)中表示如下:

struct ovl_entry                 
                                     +->+------------------------------+
                                     |  | ...                          |
                                     |  |numlower: unsigned;           |
                                     |  |lowerstack: struct ovl_path[];|
                                     |  +==============================+
                                     |  |struct ovl_path {             |
                                     |  |  layer: struct ovl_layer*;   |
                                     |  |  dentry: struct dentry*;     |
                                     |  |};                            |
                                     |  +------------------------------+
                                     |  |struct ovl_path {             |
                                     |  |  layer: struct ovl_layer*;   |
                                     |  |  dentry: struct dentry*;     |
                                     |  |};                            |
                                     |  +------------------------------+
                                     |  |                              |
                                     |  |                              |
                                     |
                                     |  struct ovl_inode                   
   struct dentry                     |  +---------------------------------+       
   +--------------------------------+|  |redirect: char*;                 |           
   |d_parent: struct dentry *;      ||  |mnt_mountpoint: struct dentry*;  |                  
   |d_name: struct qstr;            ||  |vfs_inode: struct inode;         |               
   |d_inode: struct inode*;----------+->|+-struct inode -----------------+|                    
   |d_op: struct dentry_operations*;||  ||i_op: struct inode_operations*;||                    
   |d_sb: struct super_block;       ||  ||i_sb: struct super_block *;    ||                
   |d_fsdata: void *;  -(3)----------+  ||i_ino: unsigned long;          ||
   | ...                            |   || ...                           ||
   +--------------------------------+   |+-------------------------------+|
                                        |__upperdentry: struct dentry*;   |
                                        |lower: struct inode*;            |
                                        |...                              |                              
                                        +---------------------------------+

(2)打開(kāi)目錄

被打開(kāi)的目錄可能只來(lái)自于upper層或lower層,由或者是upper和lower目錄merged而成,打開(kāi)過(guò)程如下:

ovl_dir_open(struct inode *inode, struct file *file) // fs/overlayfs/readdir.c
|-> struct ovl_dir_file *od;
|-> od = kzalloc(sizeof(struct ovl_dir_file), GFP_KERNEL);
| // (1)獲取目錄路徑:若目錄是merged或者upper目錄,則獲得upper路徑;否則,獲得lower路徑。
|-> type = ovl_path_real(file->f_path.dentry, &realpath);
|          |-> type = ovl_path_type(dentry);
|          |          |-> type = __OVL_PATH_UPPER;
|          |          |-> type  |= __OVL_PATH_MERGE;
|          |
|          |-> ovl_path_lower(dentry, path);
|          | // < or >
|          |-> ovl_path_upper(dentry, path);
|              |-> path->mnt = ovl_upper_mnt(ofs);
|              |-> path->dentry = ovl_dentry_upper(dentry);
|
| // (2)打開(kāi)實(shí)際文件系統(tǒng)目錄文件:upper或者lower目錄
|-> realfile = ovl_dir_open_realfile(file, &realpath);
|              |-> struct file *res;
|              |-> res = ovl_path_open(realpath, O_RDONLY | (file->f_flags & O_LARGEFILE));
|                        |-> dentry_open(path, flags, current_cred());
|                            |-> struct file *f;
|                            |-> f = alloc_empty_file(flags, cred);
|                            |-> vfs_open(path, f);
|                                |-> open = f->f_op->open(inode, f);
|
| // (3)將overlayfs目錄文件和實(shí)際文件系統(tǒng)目錄文件關(guān)聯(lián):realfile作為ovldir_file的實(shí)際文件;ovl_dir_file又作為file的私有數(shù)據(jù)
|-> od->realfile = realfile;
|-> od->is_real = ovl_dir_is_real(file->f_path.dentry);
|-> od->is_upper = OVL_TYPE_UPPER(type);
|-> file->private_data = od;

由上過(guò)程可知,Overlay fs目錄文件被打開(kāi)后,同時(shí)存在Overlay fs目錄文件和實(shí)際文件系統(tǒng)目錄文件,中間通過(guò)ovl_dir_file鏈接(ovl_dir_file作為Overlay fs目錄文件的私有數(shù)據(jù)),他們直接的關(guān)系示意如下:

struct ovl_dir_file                 
                            +->+-----------------------------+
                            |  |is_real: bool                |
                            |  |is_upper: unsigned;          |
                            |  |cache: struct ovl_dir_cache*;|
                            |  |cursor: struct list_head*;   |
                            |  |realfile: struct file*; -----+-+
                            |  |upperfile: struct file*;     | |
                            |  +-----------------------------+ |
                            +-------+                  +-------+
   struct file                      |                  |  struct file                     
   +------------------------------+ |                  +->+------------------------------+  
   |f_path: struct path;          | |                     |f_path: struct path;          |         
   |f_inode: struct inode;        | |                     |f_inode: struct inode;        |     
   |f_op: struct file_operations*;| |                     |f_op: struct file_operations*;|
   |private_data: void *; --------+-+                     |private_data: void *;         |
   | ...                          |                       | ...                          |
   +------------------------------+                       +------------------------------+
   overlayfs目錄文件                                      實(shí)際文件系統(tǒng)目錄文件

(3)遍歷目錄

遍歷目錄,即是所有各疊層相同目錄下的所有文件列表。

(4)系統(tǒng)調(diào)用-遍歷目錄
YSCALL_DEFINE3(getdents, unsigned int, fd,,,,,) // fs/readdir.c
|-> struct fd f;
|-> struct getdents_callback buf = {
|->     .ctx.actor = filldir,
|->     .count = count,
|->     .current_dir = dirent
|-> };
|
|-> iterate_dir(f.file, &buf.ctx);
    |-> file->f_op->iterate(file, ctx);
(5)OVL函數(shù)iterate實(shí)現(xiàn)

假設(shè)目錄是merged的目錄:

struct ovl_dir_file                 
                                    +=>+-----------------------------+
                                    H  |is_real: bool                |
                                    H  |is_upper: unsigned;          |
                                    H  |cache: struct ovl_dir_cache*;|
                                    H  |cursor: struct list_head*;   |
                                    H  |realfile: struct file*; -----+-+
                                    H  +-----------------------------+ |
                                    H                                  | 
   struct file                      H    struct file                   V  
   +------------------------------+ H    +------------------------------+  
   |f_path: struct path;  ==========+=+  |f_path: struct path;          |         
   |f_inode: struct inode;        | H H  |f_inode: struct inode;        |     
   |f_op: struct file_operations*;| H H  |f_op: struct file_operations*;|
   |private_data: void *; ========+=+ H  |private_data: void *;         |
   | ...                          |   H  | ...                          |
   +------------------------------+   H  +------------------------------+
     +================================+
     V
    struct path                     
    +-----------------------+
    |mnt: struct vfsmount*; |
    |dentry: struct dentry*;|==+
    +-----------------------+  H
     +=========================+
     V
     struct dentry                        struct ovl_inode                   
     +--------------------------------+   +---------------------------------+
     |d_parent: struct dentry *;      |   |cache: struct ovl_dir_cache*;    |
     |d_name: struct qstr;            |   |flags: unsigned long;            |
     |d_inode: struct inode*;=========+==>|vfs_inode: struct inode;         |
     |d_op: struct dentry_operations*;|   |+-struct inode -----------------+|
     |d_sb: struct super_block;       |   ||i_op: struct inode_operations*;||
     |d_fsdata: void *;  =============++  ||i_sb: struct super_block *;    ||
     | ...                            |H  ||i_ino: unsigned long;          ||
     +--------------------------------+H  || ...                           ||
                                       H  |+-------------------------------+|
                                       H  |__upperdentry: struct dentry*;   |
                                       H  |...                              |
                                       H  +---------------------------------+
                                       H                  
                                       H  struct ovl_entry                
                                       +=>+------------------------------+
                                          | ...                          |
                                          |numlower: unsigned;           |
                                          |lowerstack: struct ovl_path[];|
                                          +==============================+
                                          |struct ovl_path {             |
                                          |  layer: struct ovl_layer*;   |
                                          |  dentry: struct dentry*;     |
                                          |};                            |
                                          +------------------------------+
                                          |                              |
                                          |                              |
ovl_iterate(struct file *file, struct dir_context *ctx)
|-> struct ovl_dir_file *od = file->private_data;
|-> struct ovl_dir_cache *cache;
|
|-> cache = ovl_cache_get(dentry);
|           |-> ovl_set_dir_cache(d_inode(dentry), NULL);
|           |-> cache = kzalloc(sizeof(struct ovl_dir_cache), GFP_KERNEL);
|           |-> cache->refcount = 1;
|           |-> INIT_LIST_HEAD(&cache->entries);
|           |-> cache->root = RB_ROOT;
|           |  // 遍歷同名目錄所在所有層次的文件列表,掛載文件列表到cache的紅黑樹(shù)節(jié)點(diǎn)
|           |-> ovl_dir_read_merged(dentry, &cache->entries, &cache->root);
|           |   |-> for (idx = 0; idx != -1; idx = next) {
|           |   |       next = ovl_path_next(idx, dentry, &realpath);
|           |   |              |-> struct ovl_entry *oe = dentry->d_fsdata;
|           |   |              |-> if (idx == 0) ovl_path_upper(dentry, path);
|           |   |              |        <or>
|           |   |              |-> path->dentry = oe->lowerstack[idx - 1].dentry;
|           |   |       if (next != -1) {
|           |   |           // 遍歷某一層中目錄下文件列表,結(jié)果存放在ctx中
|           |   |           err = ovl_dir_read(&realpath, &rdd);
|           |   |                 |-> realfile = ovl_path_open(realpath, O_RDONLY | O_LARGEFILE);
|           |   |                 |-> iterate_dir(realfile, &rdd->ctx);
|           |   |       } else {
|           |   |           err = ovl_dir_read(&realpath, &rdd);
|           |   |       }
|           |   |-> }
|           |-> cache->root = RB_ROOT;
|           |-> ovl_set_dir_cache(d_inode(dentry), cache);
|
|-> od->cache = cache;
|-> ovl_seek_cursor(od, ctx->pos);
|   |-> od->cursor = p;

由上面的流程可以看出,若是目錄是合成的,在遍歷目錄下文件列表時(shí),是將各疊層目錄下的所有文件列表保存在文件所有的紅黑數(shù)上,結(jié)構(gòu)如下:

struct ovl_dir_file                                
                                    +=>+-----------------------------+               
                                    H  |is_real: bool                |               
                                    H  |is_upper: unsigned;          |               
                                    H  |cache: struct ovl_dir_cache*;+--------+      
                                    H  |cursor: struct list_head*;   |        |      
                                    H  |realfile: struct file*; -----+-+      |        
                                    H  +-----------------------------+ |      |        
                                    H                                  |      |         
   struct file                      H    struct file                   V      |          
   +------------------------------+ H    +------------------------------+     |           
   |f_path: struct path;  ==========+=+  |f_path: struct path;          |     |                  
   |f_inode: struct inode;        | H H  |f_inode: struct inode;        |     |              
   |f_op: struct file_operations*;| H H  |f_op: struct file_operations*;|     |         
   |private_data: void *; ========+=+ H  |private_data: void *;         |     |                         保存所有不同層次相同目錄下的文件列表(紅黑樹(shù))
   | ...                          |   H  | ...                          |     |                        /
   +------------------------------+   H  +------------------------------+     |                       V
     +================================+                                       |  struct ovl_dir_cache                                    
     V                                                                        +->+------------------------+               
    struct path                                                               |  |refcount: long;         |               
    +-----------------------+                                                 |  |version: u64;           |               
    |mnt: struct vfsmount*; |                                                 |  |entries: struct entries;|               
    |dentry: struct dentry*;|==+                                              |  |root: struct rb_root;   |               
    +-----------------------+  H                                              |  +------------------------+               
     +=========================+                                              |                
     V                                                                        |                
     struct dentry                        struct ovl_inode                    |                
     +--------------------------------+   +---------------------------------+ |             
     |d_parent: struct dentry *;      |   |cache: struct ovl_dir_cache*; ---+-+              
     |d_name: struct qstr;            |   |flags: unsigned long;            |
     |d_inode: struct inode*;=========+==>|vfs_inode: struct inode;         |
     |d_op: struct dentry_operations*;|   |+-struct inode -----------------+|
     |d_sb: struct super_block;       |   ||i_op: struct inode_operations*;||
     |d_fsdata: void *;               |   ||i_sb: struct super_block *;    ||
     | ...                            |   ||i_ino: unsigned long;          ||
     +--------------------------------+   || ...                           ||
                                          |+-------------------------------+|
                                          |__upperdentry: struct dentry*;   |
                                          |...                              |
                                          +---------------------------------+

總結(jié)

本文重點(diǎn)介紹Overlay FS的目錄相關(guān)的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)和目錄的相關(guān)接口,讓讀者能體會(huì)到所謂的Overlay文件系統(tǒng)的特點(diǎn),很多實(shí)現(xiàn)細(xì)節(jié)是有別于傳統(tǒng)的文件系統(tǒng),均需考慮upper層和lower層不同情況,但是萬(wàn)變不離其宗,我們學(xué)習(xí)文件系統(tǒng)必須抓住文件系統(tǒng)的主要數(shù)據(jù)和接口的實(shí)現(xiàn),這對(duì)C語(yǔ)言實(shí)現(xiàn)其它底層軟件開(kāi)發(fā)也是一種必備技能。

想了解更多關(guān)于開(kāi)源的內(nèi)容,請(qǐng)?jiān)L問(wèn):

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

https://ost.51cto.com

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

2023-04-12 15:09:25

Overlay fs鴻蒙

2014-12-22 11:30:54

DockerAUFS云計(jì)算

2021-06-06 16:55:22

Linux文件系統(tǒng)

2010-04-13 13:31:31

Unix文件

2010-11-15 16:41:29

Oracle文件

2018-01-18 17:14:58

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

2010-07-27 10:15:38

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

2009-12-10 14:27:07

Linux操作系統(tǒng)

2010-06-04 18:45:43

Hadoop分布式文件

2010-02-25 14:50:59

Linux文件系統(tǒng)

2022-01-14 08:39:47

鴻蒙HarmonyOS應(yīng)用

2010-08-05 11:03:55

創(chuàng)建分區(qū)文件系統(tǒng)

2023-05-05 08:16:56

SeaweedFS分布式文件

2009-09-22 11:59:19

2009-11-25 17:48:18

PHP文件系統(tǒng)相關(guān)函數(shù)

2019-05-29 16:33:32

Linux虛擬系統(tǒng)

2011-03-16 14:23:38

分布式文件

2020-11-11 07:48:21

Node

2019-05-22 09:00:16

Linux虛擬文件系統(tǒng)

2023-08-05 12:58:51

RPC協(xié)議服務(wù)端
點(diǎn)贊
收藏

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