日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

从open系统调用的源码看文件的打开过程

發(fā)布時間:2024/4/15 windows 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从open系统调用的源码看文件的打开过程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

open系統(tǒng)調(diào)用:創(chuàng)建file結構體,(指針)放入進程打開文件表,返回表下標(文件描述符)

?

?

?

?

?

轉自:http://blog.csdn.net/qiang81020/archive/2010/06/20/5681481.aspx

?

我們常常使用系統(tǒng)調(diào)用open來打開一個文件,例如:

fd = open( "/mnt/data/myfile",O_RDWR|O_CREAT);

下面來看看Linux是如何完成的,首先是系統(tǒng)調(diào)用的代碼:

sys_open的源程序

view plaincopy to clipboardprint?
asmlinkage long sys_open(const char * filename, int flags, int mode)??
{??
??????? char * tmp;??
??????? int fd, error;??
#if BITS_PER_LONG != 32??
??????? flags |= O_LARGEFILE;??
#endif??
??????? tmp = getname(filename);??
??????? fd = PTR_ERR(tmp);??
??????? if (!IS_ERR(tmp)) {??
??????????????? fd = get_unused_fd();/*<-----------------------------------(1) */?
??????????????? if (fd >= 0) {??
??????????????????????? struct file *f = filp_open(tmp, flags, mode);/*<---(2) */?
??????????????????????? error = PTR_ERR(f);??
??????????????????????? if (IS_ERR(f))??
??????????????????????????????? goto out_error;??
??????????????????????? fd_install(fd, f);/*<------------------------------(3) */?
??????????????? }??
out:??
??????????????? putname(tmp);??
??????? }??
??????? return fd;??
out_error:??
??????? put_unused_fd(fd);??
??????? fd = error;??
??????? goto out;??
}?
asmlinkage long sys_open(const char * filename, int flags, int mode)
{
??????? char * tmp;
??????? int fd, error;
#if BITS_PER_LONG != 32
??????? flags |= O_LARGEFILE;
#endif
??????? tmp = getname(filename);
??????? fd = PTR_ERR(tmp);
??????? if (!IS_ERR(tmp)) {
??????????????? fd = get_unused_fd();/*<-----------------------------------(1) */
??????????????? if (fd >= 0) {
??????????????????????? struct file *f = filp_open(tmp, flags, mode);/*<---(2) */
??????????????????????? error = PTR_ERR(f);
??????????????????????? if (IS_ERR(f))
??????????????????????????????? goto out_error;
??????????????????????? fd_install(fd, f);/*<------------------------------(3) */
??????????????? }
out:
??????????????? putname(tmp);
??????? }
??????? return fd;
out_error:
??????? put_unused_fd(fd);
??????? fd = error;
??????? goto out;
}
?


這里面完成的幾個工作

1.注意到返回一個整數(shù)fd,所以在(1)的位置獲得一個整數(shù)fd。
2.根據(jù)路徑/mnt/data/myfile找到(或創(chuàng)建)文件,并且創(chuàng)建一個結構file(見(2))。
3.將整數(shù)fd和file結構指針f聯(lián)系起來(見(3))。

注意:
結構file實際上是系統(tǒng)打開文件表中的表項,目的是實現(xiàn)不同進程共享文件的讀寫指針的情形。(另外一種文件共享是不同的進程有各自的文件讀寫指針的情形)。

文件打開過程的總結:

?


系統(tǒng)在進程打開文件表中找到一個未使用的fd;
根據(jù)open中提供的路徑字符串找到(創(chuàng)建)對應的dentry(從而找到inode);
創(chuàng)建系統(tǒng)打開文件表中的一個打開文件表項(創(chuàng)建一個file結構,使用指針filp指向file結構),并使該表項指向dentry(file的字段之一就是f_dentry,指向被打開文件在其目錄中的表項dentry);
在fd所指示的進程打開文件表表項中設置指向file結構的指針;
系統(tǒng)使用filp->f_dentry->d_inode的方式訪問磁盤inode,將其讀入內(nèi)存中,創(chuàng)建對應的vnode。因此,可以認為系統(tǒng)打開文件表表項有指針指向vnode結構
進一步了解:

Linux 2.6.11內(nèi)核文件IO系統(tǒng)調(diào)用

Linux 2.6.11內(nèi)核文件IO系統(tǒng)調(diào)用
1.??????? 引言
??? 從事Linux環(huán)境工作2年有余,一直懵懵懂懂,1年前拜讀了《萊昂氏UNIX源代碼分析》一書,感覺自己的學習道路漫漫且修遠。最近受chinaunix的精華文帖啟發(fā),擬將近來的部分內(nèi)核調(diào)用分析筆記拿出來與各前輩先進共同探討學習,以壯個人學習之路。
??? 本部分主要講述的是文件I/O操作的2.6.11內(nèi)核版本實現(xiàn),包括了主要的數(shù)據(jù)結構、宏定義和函數(shù)流程。以下分別講述open,create,close,read,write,lseek系統(tǒng)調(diào)用。
2.??????? 主要參考
《萊昂氏UNIX源代碼分析》
《UNIX環(huán)境高級編程》
? www.kernel.org
3.??????? 主要數(shù)據(jù)結構
3.1.??????? FD
????? 對于內(nèi)核而言,所有打開文件都由文件描述符引用。文件描述符是一個非負整數(shù)。當打開一個現(xiàn)存文件或創(chuàng)建一個新文件時,內(nèi)核向進程返回一個文件描述符。
??? 當讀、寫一個文件時,用open或creat返回的文件描述符標識該文件,將其作為參數(shù)傳送給read或write。在POSIX.1應用程序中,文件描述符為常數(shù)0、1和2分別代表STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO,意即標準輸入,標準輸出和標準出錯輸出,這些常數(shù)都定義在頭文件

;中。
文件描述符的范圍是0~OPEN_MAX,在目前常用的linux系統(tǒng)中,是32位整形所能表示的整數(shù),即65535,64位機上則更多。
3.2.??????? File
struct file {
?? struct list_head??????? f_list; //文件鏈表指針
? struct dentry??????????????? *f_dentry; // 文件對應的目錄結構
? struct vfsmount???????? *f_vfsmnt; // 虛擬文件系統(tǒng)掛載點
? struct file_operations??????? *f_op; // 文件操作函數(shù)指針
? atomic_t??????????????? f_count;
?? unsigned int???????????????? f_flags;
?? mode_t??????????????????????? f_mode; // 文件模式
? int??????????????????????? f_error;
?? loff_t??????????????????????? f_pos; // 文件offset
?? struct fown_struct??????? f_owner; //文件owner 結構
? unsigned int??????????????? f_uid, f_gid;
?? struct file_ra_state??????? f_ra; // 跟蹤上次文件操作狀態(tài)的結構指針
? size_t??????????????????????? f_maxcount; // 文件大小
? unsigned long??????????????? f_version;
?? void??????????????????????? *f_security; // hook 文件操作的security結構指針
? void??????????????????????? *private_data; // tty 驅動器所需數(shù)據(jù)
#ifdef CONFIG_EPOLL
?? struct list_head??????? f_ep_links; // EPOLL 機制檢測所需鏈表結構
? spinlock_t??????????????? f_ep_lock; // 兼容早期gcc bug 的標志
#endif /* #ifdef CONFIG_EPOLL */
?? struct address_space??????? *f_mapping; // 地址映射表
}
3.3.??????? File_struct
File_struct結構保存了進程打開的所有文件表數(shù)據(jù)。
struct files_struct {
?? atomic_t count; // 自動增量
? spinlock_t file_lock; // 低位成員保護標識
? int max_fds; // 最大文件句柄數(shù)目
? int max_fdset; // 最大的fd集合容量
? int next_fd; // 下一個空閑fd
?? struct file ** fd; // 當前fd對應的文件結構指針列表
? fd_set *close_on_exec; // 可執(zhí)行close的fd集合
? fd_set *open_fds; // 打開的fd集合
? fd_set close_on_exec_init; //
?? fd_set open_fds_init;
?? struct file * fd_array[NR_OPEN_DEFAULT]; // 默認打開的fd隊列
};
4.??????? open 函數(shù)
4.1.??????? 原型與參數(shù)
?? int open(const char * pathname,? int oflag, .../*, mode_t mode * / )? -1代表錯誤。
?? 這里的oflag是一個整形,主要供open 函數(shù)使用,部分fcntl函數(shù)也會使用。詳細的說明請用man 2 open就可以看到了。以下列出了2.6內(nèi)核定義的open和fcntl函數(shù)所使用的flag宏定義,說明的格式如宏定義名稱<實際常數(shù)值>;: 描述。
?? O_ACCMODE??????? <0003>;: 讀寫文件操作時,用于取出flag的低2位。
?? O_RDONLY<00>;: 只讀打開
?? O_WRONLY<01>;: 只寫打開
?? O_RDWR<02>;: 讀寫打開
?? O_CREAT<0100>;: 文件不存在則創(chuàng)建,需要mode_t,not fcntl
??? O_EXCL<0200>;: 如果同時指定了O_CREAT,而文件已經(jīng)存在,則出錯, not fcntl
??? O_NOCTTY<0400>;: 如果pathname指終端設備,則不將此設備分配作為此進程的控制終端。not fcntl O_TRUNC<01000>;: 如果此文件存在,而且為只讀或只寫成功打開,則將其長度截短為0。not fcntl
??? O_APPEND<02000>;: 每次寫時都加到文件的尾端
?? O_NONBLOCK<04000>;: 如果p a t h n a m e指的是一個F I F O、一個塊特殊文件或一個字符特殊文件,則此選擇項為此文件的本次打開操作和后續(xù)的I / O操作設置非阻塞方式。
O_NDELAY;;
?? O_SYNC<010000>;: 使每次write都等到物理I/O操作完成。
?? FASYNC<020000>;: 兼容BSD的fcntl同步操作
?? O_DIRECT<040000>;: 直接磁盤操作標識
?? O_LARGEFILE<0100000>;: 大文件標識
?? O_DIRECTORY<0200000>;:??????? 必須是目錄
?? O_NOFOLLOW<0400000>;: 不獲取連接文件
?? O_NOATIME<01000000>;: 暫無
?? 當新創(chuàng)建一個文件時,需要指定mode 參數(shù),以下說明的格式如宏定義名稱<實際常數(shù)值>;: 描述。
?? S_IRWXU<00700>;:文件擁有者有讀寫執(zhí)行權限
?? S_IRUSR (S_IREAD)<00400>;:文件擁有者僅有讀權限
?? S_IWUSR (S_IWRITE)<00200>;:文件擁有者僅有寫權限
?? S_IXUSR (S_IEXEC)<00100>;:文件擁有者僅有執(zhí)行權限
?? S_IRWXG<00070>;:組用戶有讀寫執(zhí)行權限
?? S_IRGRP<00040>;:組用戶僅有讀權限
?? S_IWGRP<00020>;:組用戶僅有寫權限
?? S_IXGRP<00010>;:組用戶僅有執(zhí)行權限
?? S_IRWXO<00007>;:其他用戶有讀寫執(zhí)行權限
?? S_IROTH<00004>;:其他用戶僅有讀權限
?? S_IWOTH<00002>;:其他用戶僅有寫權限
?? S_IXOTH<00001>;:其他用戶僅有執(zhí)行權限
4.2.??????? 實現(xiàn)分析
4.2.1.??????? 主要函數(shù)調(diào)用關系圖
?? sys_open( 見4.2.2 節(jié))
?? | ----------- getname( 見4.2.3 節(jié) )
?? | ----------- filp_open( 見4.2.4節(jié) )
?? |??????????????????????? | ------------ open_namei( 見4.2.4.1節(jié) )
?? |??????????????????????? |????????????????? | ----------- may_open( 見4.2.4.1.1節(jié) )
?? |??????????????????????? | ------------ dentry_open( 見4.2.4.2節(jié) )
4.2.2.??????? 主調(diào)用函數(shù)sys_open
asmlinkage long sys_open(const char __user * filename, int flags, int mode){
??????? char * tmp;
??????? int fd, error;

// 如果不是32位處理器,則增加大文件標識
#if BITS_PER_LONG != 32
??????? flags |= O_LARGEFILE;
#endif
??????? // 為了提高使用效率,在使用之前先將文件名拷貝到內(nèi)核數(shù)據(jù)區(qū)。見3.2.2說明
??????? tmp = getname(filename);
??????? // 獲取到返回值,如果出錯,則返回,否則執(zhí)行打開操作。
??????? fd = PTR_ERR(tmp);
??????? if (!IS_ERR(tmp)) {
??????????????? // 從進程的文件表中找出一個空閑的文件表指針,如果出錯,則返回
??????????????? fd = get_unused_fd();
??????????????? if (fd >;= 0) {
??????????????????????? // 執(zhí)行打開操作。見3.2.3說明
??????????????????????? struct file *f = filp_open(tmp, flags, mode);
??????????????????????? // 獲取返回結果,如果出錯,則跳轉至out_error,否則執(zhí)行fd_install
??????????????????????? error = PTR_ERR(f);
??????????????????????? if (IS_ERR(f))
??????????????????????????????? goto out_error;
??????????????????????? // 添加打開的文件表 f 到當前進程的文件表隊列中。見3.2.4說明
??????????????????????? fd_install(fd, f);
??????????????? }
out:
??????????????? // 釋放getname分配的內(nèi)存空間
??????????????? putname(tmp);
??????? }
??????? return fd;
out_error:
??????????????? // 將文件表指針返回到進程的文件表中,并返回錯誤代碼。
??????? put_unused_fd(fd);
??????? fd = error;
??????? goto out;
}
4.2.3.??????? sys_open子函數(shù)getname
getname函數(shù)主要功能是在使用文件名之前將其拷貝到內(nèi)核數(shù)據(jù)區(qū),正常結束時返回內(nèi)核分配的空間首地址,出錯時返回錯誤代碼。其調(diào)用了函數(shù)do_getname來實現(xiàn)。
static inline int do_getname(const char __user *filename, char *page){
??????? int retval;
??????? unsigned long len = PATH_MAX; // 內(nèi)核允許的最大路徑長度

??????? // 如果進程的地址限制是否和KERNEL_DS相等,則檢查文件名是否小于用戶進程空間
??????? if (!segment_eq(get_fs(), KERNEL_DS)) {
??????????????? // 文件名地址大于用戶進程空間,則返回錯誤-EFAULT
??????????????? if ((unsigned long) filename >;= TASK_SIZE)
??????????????????????? return -EFAULT;
??????????????? // 獲取較小的地址長度
??????????????? if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
??????????????????????? len = TASK_SIZE - (unsigned long) filename;
??????? }

??????? // 將filename拷貝len長度到page中,返回實際拷貝長度
??????? retval = strncpy_from_user(page, filename, len);
??????? if (retval >; 0) {
??????????????? // 如果retval大于等于len,則返回-ENAMETOOLONG
??????????????? if (retval < len)
??????????????????????? return 0;
??????????????? return -ENAMETOOLONG;
??????? } else if (!retval)
??????????????? // filename 為空,則返回-ENOENT
??????????????? retval = -ENOENT;
??????? return retval;
}

char * getname(const char __user * filename){
??????? char *tmp, *result;

??????? result = ERR_PTR(-ENOMEM);
??????? // 從內(nèi)核緩存中分配空間,如果成功,則執(zhí)行do_getname
??????? tmp = __getname();
??????? if (tmp)? {
??????????????? // 執(zhí)行文件名拷貝操作
??????????????? int retval = do_getname(filename, tmp);

??????????????? result = tmp;
??????????????? if (retval < 0) {
??????????????????????? // do_getname出錯,則釋放空間,并返回錯誤代碼
??????????????????????? __putname(tmp);
??????????????????????? result = ERR_PTR(retval);
??????????????? }
??????? }
??????? // 如果前面操作成功,且audit_context不為空,則將當前文件名添加到audit列表中
??????? if (unlikely(current->;audit_context) && !IS_ERR(result) && result)
??????????????? audit_getname(result);
??????? // 返回處理結果
??????? return result;

??? }

?

總結

以上是生活随笔為你收集整理的从open系统调用的源码看文件的打开过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。