九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項超值服

開通VIP
fd 與file的關(guān)系

Linux支持各種各樣的文件系統(tǒng)格式,如ext2、ext3、reiserfs、FAT、NTFS、iso9660等等,不同的磁盤分區(qū)、光盤或其它存儲設(shè)備都有不同的文件系統(tǒng)格式,然而這些文件系統(tǒng)都可以mount到某個目錄下,使我們看到一個統(tǒng)一的目錄樹,各種文件系統(tǒng)上的目錄和文件我們用ls命令看起來是一樣的,讀寫操作用起來也都是一樣的,這是怎么做到的呢?Linux內(nèi)核在各種不同的文件系統(tǒng)格式之上做了一個抽象層,使得文件、目錄、讀寫訪問等概念成為抽象層的概念,因此各種文件系統(tǒng)看起來用起來都一樣,這個抽象層稱為虛擬文件系統(tǒng)(VFS,Virtual Filesystem)。上一節(jié)我們介紹了一種典型的文件系統(tǒng)在磁盤上的存儲布局,這一節(jié)我們介紹運(yùn)行時文件系統(tǒng)在內(nèi)核中的表示。

3.1. 內(nèi)核數(shù)據(jù)結(jié)構(gòu) 請點(diǎn)評

Linux內(nèi)核的VFS子系統(tǒng)可以圖示如下:

圖 29.8. VFS


第 28 章 文件與I/O中講過,每個進(jìn)程在PCB(Process Control Block)中都保存著一份文件描述符表,文件描述符就是這個表的索引,每個表項都有一個指向已打開文件的指針,現(xiàn)在我們明確一下:已打開的文件在內(nèi)核中用file結(jié)構(gòu)體表示,文件描述符表中的指針指向file結(jié)構(gòu)體。

file結(jié)構(gòu)體中維護(hù)File Status Flag(file結(jié)構(gòu)體的成員f_flags)和當(dāng)前讀寫位置(file結(jié)構(gòu)體的成員f_pos)。在上圖中,進(jìn)程1和進(jìn)程2都打開同一文件,但是對應(yīng)不同的file結(jié)構(gòu)體,因此可以有不同的File Status Flag和讀寫位置。file結(jié)構(gòu)體中比較重要的成員還有f_count,表示引用計數(shù)(Reference Count),后面我們會講到,dupfork等系統(tǒng)調(diào)用會導(dǎo)致多個文件描述符指向同一個file結(jié)構(gòu)體,例如有fd1fd2都引用同一個file結(jié)構(gòu)體,那么它的引用計數(shù)就是2,當(dāng)close(fd1)時并不會釋放file結(jié)構(gòu)體,而只是把引用計數(shù)減到1,如果再close(fd2),引用計數(shù)就會減到0同時釋放file結(jié)構(gòu)體,這才真的關(guān)閉了文件。

每個file結(jié)構(gòu)體都指向一個file_operations結(jié)構(gòu)體,這個結(jié)構(gòu)體的成員都是函數(shù)指針,指向?qū)崿F(xiàn)各種文件操作的內(nèi)核函數(shù)。比如在用戶程序中read一個文件描述符,read通過系統(tǒng)調(diào)用進(jìn)入內(nèi)核,然后找到這個文件描述符所指向的file結(jié)構(gòu)體,找到file結(jié)構(gòu)體所指向的file_operations結(jié)構(gòu)體,調(diào)用它的read成員所指向的內(nèi)核函數(shù)以完成用戶請求。在用戶程序中調(diào)用lseek、read、write、ioctl、open等函數(shù),最終都由內(nèi)核調(diào)用file_operations的各成員所指向的內(nèi)核函數(shù)完成用戶請求。file_operations結(jié)構(gòu)體中的release成員用于完成用戶程序的close請求,之所以叫release而不叫close是因?yàn)樗灰欢ㄕ娴年P(guān)閉文件,而是減少引用計數(shù),只有引用計數(shù)減到0才關(guān)閉文件。對于同一個文件系統(tǒng)上打開的常規(guī)文件來說,read、write等文件操作的步驟和方法應(yīng)該是一樣的,調(diào)用的函數(shù)應(yīng)該是相同的,所以圖中的三個打開文件的file結(jié)構(gòu)體指向同一個file_operations結(jié)構(gòu)體。如果打開一個字符設(shè)備文件,那么它的read、write操作肯定和常規(guī)文件不一樣,不是讀寫磁盤的數(shù)據(jù)塊而是讀寫硬件設(shè)備,所以file結(jié)構(gòu)體應(yīng)該指向不同的file_operations結(jié)構(gòu)體,其中的各種文件操作函數(shù)由該設(shè)備的驅(qū)動程序?qū)崿F(xiàn)。

每個file結(jié)構(gòu)體都有一個指向dentry結(jié)構(gòu)體的指針,“dentry”是directory entry(目錄項)的縮寫。我們傳給open、stat等函數(shù)的參數(shù)的是一個路徑,例如/home/akaedu/a,需要根據(jù)路徑找到文件的inode。為了減少讀盤次數(shù),內(nèi)核緩存了目錄的樹狀結(jié)構(gòu),稱為dentry cache,其中每個節(jié)點(diǎn)是一個dentry結(jié)構(gòu)體,只要沿著路徑各部分的dentry搜索即可,從根目錄/找到home目錄,然后找到akaedu目錄,然后找到文件a。dentry cache只保存最近訪問過的目錄項,如果要找的目錄項在cache中沒有,就要從磁盤讀到內(nèi)存中。

每個dentry結(jié)構(gòu)體都有一個指針指向inode結(jié)構(gòu)體。inode結(jié)構(gòu)體保存著從磁盤inode讀上來的信息。在上圖的例子中,有兩個dentry,分別表示/home/akaedu/a/home/akaedu/b,它們都指向同一個inode,說明這兩個文件互為硬鏈接。inode結(jié)構(gòu)體中保存著從磁盤分區(qū)的inode讀上來信息,例如所有者、文件大小、文件類型和權(quán)限位等。每個inode結(jié)構(gòu)體都有一個指向inode_operations結(jié)構(gòu)體的指針,后者也是一組函數(shù)指針指向一些完成文件目錄操作的內(nèi)核函數(shù)。和file_operations不同,inode_operations所指向的不是針對某一個文件進(jìn)行操作的函數(shù),而是影響文件和目錄布局的函數(shù),例如添加刪除文件和目錄、跟蹤符號鏈接等等,屬于同一文件系統(tǒng)的各inode結(jié)構(gòu)體可以指向同一個inode_operations結(jié)構(gòu)體。

inode結(jié)構(gòu)體有一個指向super_block結(jié)構(gòu)體的指針。super_block結(jié)構(gòu)體保存著從磁盤分區(qū)的超級塊讀上來的信息,例如文件系統(tǒng)類型、塊大小等。super_block結(jié)構(gòu)體的s_root成員是一個指向dentry的指針,表示這個文件系統(tǒng)的根目錄被mount到哪里,在上圖的例子中這個分區(qū)被mount/home目錄下。

file、dentry、inode、super_block這幾個結(jié)構(gòu)體組成了VFS的核心概念。對于ext2文件系統(tǒng)來說,在磁盤存儲布局上也有inode和超級塊的概念,所以很容易和VFS中的概念建立對應(yīng)關(guān)系。而另外一些文件系統(tǒng)格式來自非UNIX系統(tǒng)(例如Windows的FAT32、NTFS),可能沒有inode或超級塊這樣的概念,但為了能mount到Linux系統(tǒng),也只好在驅(qū)動程序中硬湊一下,在Linux下看FAT32和NTFS分區(qū)會發(fā)現(xiàn)權(quán)限位是錯的,所有文件都是rwxrwxrwx,因?yàn)樗鼈儽緛砭蜎]有inode和權(quán)限位的概念,這是硬湊出來的。

3.2. dup和dup2函數(shù) 請點(diǎn)評

dupdup2都可用來復(fù)制一個現(xiàn)存的文件描述符,使兩個文件描述符指向同一個file結(jié)構(gòu)體。如果兩個文件描述符指向同一個file結(jié)構(gòu)體,F(xiàn)ile Status Flag和讀寫位置只保存一份在file結(jié)構(gòu)體中,并且file結(jié)構(gòu)體的引用計數(shù)是2。如果兩次open同一文件得到兩個文件描述符,則每個描述符對應(yīng)一個不同的file結(jié)構(gòu)體,可以有不同的File Status Flag和讀寫位置。請注意區(qū)分這兩種情況。

#include <unistd.h>int dup(int oldfd);int dup2(int oldfd, int newfd);

如果調(diào)用成功,這兩個函數(shù)都返回新分配或指定的文件描述符,如果出錯則返回-1。dup返回的新文件描述符一定是該進(jìn)程未使用的最小文件描述符,這一點(diǎn)和open類似。dup2可以用newfd參數(shù)指定新描述符的數(shù)值。如果newfd當(dāng)前已經(jīng)打開,則先將其關(guān)閉再做dup2操作,如果oldfd等于newfd,則dup2直接返回newfd而不用先關(guān)閉newfd再復(fù)制。

下面這個例子演示了dupdup2函數(shù)的用法,請結(jié)合后面的連環(huán)畫理解程序的執(zhí)行過程。

例 29.2. dup和dup2示例程序

#include <unistd.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>int main(void){	int fd, save_fd;	char msg[] = "This is a test\n";	fd = open("somefile", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);	if(fd<0) {		perror("open");		exit(1);	}	save_fd = dup(STDOUT_FILENO);	dup2(fd, STDOUT_FILENO);	close(fd);	write(STDOUT_FILENO, msg, strlen(msg));	dup2(save_fd, STDOUT_FILENO);	write(STDOUT_FILENO, msg, strlen(msg));	close(save_fd);	return 0;}

圖 29.9. dup/dup2示例程序


重點(diǎn)解釋兩個地方:

  • 第3幅圖,要執(zhí)行dup2(fd, 1);,文件描述符1原本指向tty,現(xiàn)在要指向新的文件somefile,就把原來的關(guān)閉了,但是tty這個文件原本有兩個引用計數(shù),還有文件描述符save_fd也指向它,所以只是將引用計數(shù)減1,并不真的關(guān)閉文件。

  • 第5幅圖,要執(zhí)行dup2(save_fd, 1);,文件描述符1原本指向somefile,現(xiàn)在要指向新的文件tty,就把原來的關(guān)閉了,somefile原本只有一個引用計數(shù),所以這次減到0,是真的關(guān)閉了。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
linux 2.6.X 文件相關(guān)結(jié)構(gòu)體總結(jié)(轉(zhuǎn)載)
Linux 文件系統(tǒng)(二)
8.2.4 與進(jìn)程相關(guān)的文件結(jié)構(gòu)
linux內(nèi)核中的文件描述符(一)--基礎(chǔ)知識簡介
文件IO-文件描述符與lseek
[apue] 一圖讀懂 unix 文件句柄及文件共享過程
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服