Linux 系統呼叫 open 七日遊(七)
阿新 • • 發佈:2018-11-08
【場景三】open(pathname, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)
在這個場景中我們希望建立一個新檔案(O_CREAT),並賦予該檔案使用者可讀(S_IRUSR)和使用者可寫(S_IWUSR)的許可權,然後以只寫(O_WRONLY)的方式開啟這個檔案。O_EXCL 在這裡保證該檔案必須被建立,如果該檔案已經存在則失敗返回。
這些標誌位的作用已經解釋得很清楚了,現在來看看 build_open_flags:
【fs/open.c】 sys_open > do_sys_open > build_open_flags
)摺疊或開啟
【fs/namei.c】 sys_open > do_sys_open > do_filp_open > path_openat > do_last
接著就是 lookup_open,我們進去看看:
【fs/namei.c】 sys_open > do_sys_open > do_filp_open > path_openat > do_last > lookup_open
好了,回到 do_last:
【fs/namei.c】 sys_open > do_sys_open > do_filp_open > path_openat > do_last
最後 may_open 檢查相應的許可權,然後 finish_open 完成開啟操作,這兩個函式我們已經看過了,這裡就不深入了。
現在,我們終於到了說再見的時候了,希望這七天的旅行能讓你有所收穫。
本來只是在看完程式碼後想給自己留下點什麼,要不然以後忘了就白看了,但是等寫的時候才發現要想寫得明白光馬馬虎虎看完遠遠不夠,於是就越寫越多。大家可以發現在這幾篇部落格中有好多自問自答,這都是我在看程式碼時的疑問,有些回答可能並不是那麼準確,還請海涵。最後推薦兩本參考書籍:
《Linux 核心原始碼情景分析》,可以說這本書寫得相當精彩,雖然它核心版本是 2.4.0 相對來說有點老了,但是並不影響我們探索核心腳步,萬變不離其宗,有很多東西並沒有本質上的變化。
《深度探索 Linux 作業系統》,這本書將從另一個角度帶我們領略 Linux 的美麗和神祕,在一步一步建立並編譯自己的核心的同時,也深刻的揭示了編譯、連結、載入的原理,同樣是一本精彩的 Linux 讀物。
轉自:http://blog.chinaunix.net/uid-20522771-id-4426883.html
在這個場景中我們希望建立一個新檔案(O_CREAT),並賦予該檔案使用者可讀(S_IRUSR)和使用者可寫(S_IWUSR)的許可權,然後以只寫(O_WRONLY)的方式開啟這個檔案。O_EXCL 在這裡保證該檔案必須被建立,如果該檔案已經存在則失敗返回。
這些標誌位的作用已經解釋得很清楚了,現在來看看 build_open_flags:
【fs/open.c】 sys_open > do_sys_open > build_open_flags
點選(此處
- static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op)
- {
...
- if (flags & (O_CREAT | __O_TMPFILE))
- op-
...
- acc_mode = MAY_OPEN | ACC_MODE(flags);
...
- if (flags & O_CREAT)
- op->intent |= LOOKUP_CREATE;
- if (flags & O_EXCL)
- op->intent |= LOOKUP_EXCL;
- }
...
- }
【fs/namei.c】 sys_open > do_sys_open > do_filp_open > path_openat > do_last
點選(此處)摺疊或開啟
- static int do_last(struct nameidata *nd, struct path *path,
- struct file *file, const struct open_flags *op,
- int *opened, struct filename *name)
- {
...
- if (!(open_flag & O_CREAT)) {
...
- } else {
...
- error = complete_walk(nd);
- if (error)
- return error;
- audit_inode(name, dir, LOOKUP_PARENT);
- error = -EISDIR;
- /* trailing slashes? */
- if (nd->last.name[nd->last.len])
- goto out;
- }
- retry_lookup:
- if (op->open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) {
- error = mnt_want_write(nd->path.mnt);
- if (!error)
- got_write = true;
- /*
- * do _not_ fail yet - we might not need that or fail with
- * a different error; let lookup_open() decide; we'll be
- * dropping this one anyway.
- */
- }
- mutex_lock(&dir->d_inode->i_mutex);
- error = lookup_open(nd, path, file, op, got_write, opened);
- mutex_unlock(&dir->d_inode->i_mutex);
...
首先會呼叫 complete_walk 告別 rcu-walk 模式,然後會判斷這個最終目標是不是以“/”結尾,如果是的話就表示最終目標是一個目錄那就返回並報錯“Is a directory”(2926)。隨後,如果本次操作是有可能“寫入”的(2931),那就需要取得當前檔案系統的寫許可權,但是註釋上寫的很明白,就算現在獲取寫許可權失敗也不要急著返回,因為首先現在只是“有可能”會“寫入”,其次我們可能會因為別的原因失敗,所以現在先不理會這次的 fail,讓 lookup_open 來決定這一切吧。接著就是 lookup_open,我們進去看看:
【fs/namei.c】 sys_open > do_sys_open > do_filp_open > path_openat > do_last > lookup_open
點選(此處)摺疊或開啟
- static int lookup_open(struct nameidata *nd, struct path *path,
- struct file *file,
- const struct open_flags *op,
- bool got_write, int *opened)
- {
...
- *opened &= ~FILE_CREATED;
- dentry = lookup_dcache(&nd->last, dir, nd->flags, &need_lookup);
...
- dentry = lookup_real(dir_inode, dentry, nd->flags);
...
- if (!dentry->d_inode && (op->open_flag & O_CREAT)) {
...
- if (!got_write) {
- error = -EROFS;
- goto out_dput;
- }
- *opened |= FILE_CREATED;
...
- error = vfs_create(dir->d_inode, dentry, mode,
- nd->flags & LOOKUP_EXCL);
- if (error)
- goto out_dput;
- }
...
- }
好了,回到 do_last:
【fs/namei.c】 sys_open > do_sys_open > do_filp_open > path_openat > do_last
點選(此處)摺疊或開啟
...
- if (*opened & FILE_CREATED) {
- /* Don't check for write permission, don't truncate */
- open_flag &= ~O_TRUNC;
- will_truncate = false;
- acc_mode = MAY_OPEN;
- path_to_nameidata(path, nd);
- goto finish_open_created;
- }
...
- error = -EEXIST;
- if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))
- goto exit_dput;
...
- finish_open_created:
- error = may_open(&nd->path, acc_mode, open_flag);
- if (error)
- goto out;
- file->f_path.mnt = nd->path.mnt;
- error = finish_open(file, nd->path.dentry, NULL, opened);
...
- }
最後 may_open 檢查相應的許可權,然後 finish_open 完成開啟操作,這兩個函式我們已經看過了,這裡就不深入了。
現在,我們終於到了說再見的時候了,希望這七天的旅行能讓你有所收穫。
本來只是在看完程式碼後想給自己留下點什麼,要不然以後忘了就白看了,但是等寫的時候才發現要想寫得明白光馬馬虎虎看完遠遠不夠,於是就越寫越多。大家可以發現在這幾篇部落格中有好多自問自答,這都是我在看程式碼時的疑問,有些回答可能並不是那麼準確,還請海涵。最後推薦兩本參考書籍:
《Linux 核心原始碼情景分析》,可以說這本書寫得相當精彩,雖然它核心版本是 2.4.0 相對來說有點老了,但是並不影響我們探索核心腳步,萬變不離其宗,有很多東西並沒有本質上的變化。
《深度探索 Linux 作業系統》,這本書將從另一個角度帶我們領略 Linux 的美麗和神祕,在一步一步建立並編譯自己的核心的同時,也深刻的揭示了編譯、連結、載入的原理,同樣是一本精彩的 Linux 讀物。
轉自:http://blog.chinaunix.net/uid-20522771-id-4426883.html