前言
Linux中對一個檔案進行操作的時候,一件很重要的事情是對檔案名稱進行解析處理,並且找到對應檔案的inode對象,然後建立表示檔案的file對象。在此,對檔案名稱解析過程,並且如何找到對應inode的過程進行源碼分析。分析代碼基於Linux-3.2版本。
關鍵函數分析
不管是通過應用程式層的API函數還是在核心中開啟一個檔案,最終都需要調用filp_open函數,該函數的主要職責就是解析檔案名稱,找到檔案對應的inode對象,然後分配記憶體建立file對象,最後執行該檔案對應的file->open函數。
filp_open的核心處理函數是path_openat,該函數分析如下:
static struct file *path_openat(int dfd, const char *pathname, struct nameidata *nd, const struct open_flags *op, int flags) { struct file *base = NULL; struct file *filp; struct path path; int error; /* 建立一個file對象 */ filp = get_empty_filp(); if (!filp) return ERR_PTR(-ENFILE); filp->f_flags = op->open_flag; nd->intent.open.file = filp; nd->intent.open.flags = open_to_namei_flags(op->open_flag); nd->intent.open.create_mode = op->mode; /* 初始化檢索的起始目錄,判斷起始目錄是根目錄還是目前的目錄,並且初始化nd->inode對象,為link_path_walk函數的解析處理做準備。 */ error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base); if (unlikely(error)) goto out_filp; current->total_link_count = 0; /* 關鍵的字串解析處理函數,其核心思想是分級解析字串,通過字串對應的目錄項找到下一級目錄的inode節點。該函數的具體分析如下。 */ error = link_path_walk(pathname, nd); if (unlikely(error)) goto out_filp; /* do_last函數建立或者擷取檔案對應的inode對象,並且初始化file對象,至此一個表示開啟檔案的記憶體對象filp誕生 */ filp = do_last(nd, &path, op, pathname); while (unlikely(!filp)) { /* trailing symlink */ struct path link = path; void *cookie; if (!(nd->flags & LOOKUP_FOLLOW)) { path_put_conditional(&path, nd); path_put(&nd->path); filp = ERR_PTR(-ELOOP); break; } nd->flags |= LOOKUP_PARENT; nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); error = follow_link(&link, nd, &cookie); if (unlikely(error)) filp = ERR_PTR(error); else filp = do_last(nd, &path, op, pathname); put_link(nd, &link, cookie); } out: if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) path_put(&nd->root); if (base) fput(base); release_open_intent(nd); return filp; out_filp: filp = ERR_PTR(error); goto out; }