在這個場景中我們希望創建一個新文件(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->mode = (mode & S_IALLUGO) | S_IFREG;
...
- 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);
...
接着就是 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 讀物。