日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > 嵌入式 > 嵌入式微處理器
[導讀]寫作目的: 學習 Linux 文件模型相關的知識。 正文目錄: 1.?Linux?的兩大抽象 2.?文件類型 3.?文件描述符 4. 通用文件模型:簡介 ????4.1?演示?demo ????4.2?相關要點:?與?VFS?的關系 5. 通用文件模型:文件描述符和打開文件的關系 ????5.1?相關的內(nèi)核數(shù)據(jù)結

寫作目的:

  • 學習 Linux 文件模型相關的知識。

正文目錄:

1. Linux 的兩大抽象

2. 文件類型

3. 文件描述符

4. 通用文件模型:簡介
    4.1 演示 demo
    4.2 相關要點: 與 VFS 的關系

5. 通用文件模型:文件描述符和打開文件的關系
    5.1 相關的內(nèi)核數(shù)據(jù)結構
    5.2 列舉幾種打開文件的情景

1. Linux 的兩大抽象

  • 文件是 Linux 系統(tǒng)中最基礎最重要的抽象。Linux 遵循一切皆文件的理念。很多交互操作是通過讀寫文件來完成,即使所涉及的對象看起來并非普通文件。

  • 另外一大抽象是進程。如果說文件是 Linux 系統(tǒng)最重要的抽象概念,進程則僅次于文件。

  • 進程相關的實現(xiàn)復雜且多變,而文件 IO 的實現(xiàn)則相對穩(wěn)定很多,且更貼近我們的日常操作,所以 以文件作為學習 Linux 內(nèi)核的切入點是個更好的選擇。

2. 文件類型

Linux 系統(tǒng)的大多數(shù)文件是普通文件或目錄,但是也有另外一些文件類型,具體包括如下幾種:

  • 普通文件 ( regular file )。

    • 最常用的文件類型,包含了某種形式的數(shù)據(jù)。至于這種數(shù)據(jù)是文本還是二進制數(shù)據(jù),對于 Linux 內(nèi)核而言并無區(qū)別。

    • 文件中包含的字節(jié)可以是任意值,可以以任意方式進行組織。在系統(tǒng)層,除了字節(jié)流,Linux 對文件結構沒有特定要求。

    • 對普通文件內(nèi)容的解釋由處理該文件的應用程序進行。

    • 文件雖然是通過文件名訪問,但文件本身其實并沒有直接和文件名關聯(lián)。相反地,與文件關聯(lián)的是索引節(jié)點 (inode,是index node 縮寫)。針對駐留于文件系統(tǒng)上的每個文件,文件系統(tǒng)都會為其分配一個 inode。inode 中會保存和文件相關的元數(shù)據(jù),如文件修改時間戳、所有者、類型、長度以及文件數(shù)據(jù)的位置,但不含文件名,文件名由目錄文件負責。

    • inode 由 inode number 來標識,可以通過 “l(fā)s –li” 查看文件的 inode number。

      # ls -li minicom.log
      12582945 -rw-r--r-- 1 root root 665 Jul 10 18:47 minicom.log
  • 目錄文件 ( directory file )。

    • 目錄也是一種文件類型,這種文件包含了其他文件的文件名以及 inode number。文件通常是通過文件名從用戶空間打開,目錄用于提供訪問文件時需要的名稱。

    • 文件名和 inode 之間的配對稱為鏈接 (link)。映射在物理磁盤上的形式,如簡單的表或散列,是通過特定文件系統(tǒng)的內(nèi)核代碼來實現(xiàn)和管理的。

    • 如果用戶空間的應用請求打開指定文件,內(nèi)核會打開包含該文件名的目錄,然后根據(jù)文件名獲取 inode number。通過 inode number 可以找到 inode。inode 包含和文件關聯(lián)的元數(shù)據(jù),其中包括文件數(shù)據(jù)在磁盤上的存儲位置。

  • 硬鏈接 ( hard link )。

    • 不同的文件名可以鏈接到到同一個 inode。當不同名稱的多個鏈接映射到同一個索引節(jié)點時,我們稱該鏈接為硬鏈接。

    • 硬鏈接通常要求鏈接和文件位于同一文件系統(tǒng)中。

    • 在底層文件系統(tǒng)支持的前提下,也只有超級用戶才能創(chuàng)建指向目錄的硬鏈接。

  • 符號鏈接 ( symbolic link )。

    • 符號鏈接是對一個文件的間接指針,它與硬鏈接有所不同,硬鏈接直接指向文件的 inode。引入符號鏈接的原因是為了避開硬鏈接的一些限制。

    • 硬鏈接不能跨越多個文件系統(tǒng),因為 inode number在自己的文件系統(tǒng)之外沒有任何意義。為了跨越文件系統(tǒng)建立鏈接,Linux 系統(tǒng)實現(xiàn)了符號鏈接。

  • 特殊文件 (special file)。

    • 特殊文件是使得某些抽象可以適用于文件系統(tǒng),貫徹一切皆文件的理念。

    • Linux 只支持四種特殊文件:塊設備文件、字符設備文件、命名管道 以及 UNIX域套接字。

    • 塊特殊文件 ( block device file )。提供對設備(如磁盤)帶緩沖的訪問,每次訪問以固定長度為單位進行。

    • 字符特殊文件 ( character device file )。這種類型的文件提供對設備不帶緩沖的訪問,每次訪問長度可變。系統(tǒng)中的所有設備要么是字符特殊文件,要么是塊特殊文件。

    • 命名管道 ( named pipes ),通常稱為 FIFO,是以文件描述符作為通信信道的 IPC 機制,它可以通過特殊文件來訪問。

    • 套接字 ( socket ) 是最后一種特殊文件。socket 是進程間通信的高級形式,支持不同進程間的通信,這兩個進程可以在同一臺機器,也可以在不同機器。socket 是網(wǎng)絡和互聯(lián)網(wǎng)編程的基礎。

在 Linux,可以用 ls/stat 命令 和 stat() 系統(tǒng)調(diào)用確定文件類型。

$ ls -li 
12587634 drwxr-xr-x 26 root root      4096 Mar 16 07:49 1.opensource
27396428 lrwxrwxrwx  1 root root        12 Nov 17  2017 Link to ssd_dvd -> /mnt/ssd_dvd
12582945 -rw-r--r--  1 root root       665 Jul 10 18:47 minicom.log

$ stat minicom.log 
  File: 'minicom.log'
  Size: 665        Blocks: 8          IO Block: 4096   regular file
Device: 822h/2082d Inode: 12582945    Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2020-01-09 09:44:07.101177618 +0800
Modify: 2020-07-10 18:47:20.073532673 +0800
Change: 2020-07-10 18:47:20.073532673 +0800

3. 文件描述符

在 Linux 中,文件必須先打開才能訪問。對于內(nèi)核而言,所有打開的文件都通過文件描述符 ( file descriptor,簡稱fd ) 引用。文件描述符是一個非負整數(shù)。當打開一個現(xiàn)有文件或創(chuàng)建一個新文件時,內(nèi)核向進程返回一個文件描述符。當讀、寫一個文件時,使用 open() 或 creat() 返回的文件描述符標識該文件,將其作為參數(shù)傳送給 read() 或 write()。

  • Linux 系統(tǒng)編程的大部分工作都會涉及打開、操縱、關閉以及其他文件描述符操作;

  • Linux 系統(tǒng)的 Shell 把文件描述符 0 與進程的標準輸入 stdin 關聯(lián),文件描述符 1 與標準輸出 stdout 關聯(lián),文件描述符 2 與標準錯誤 stderr 關聯(lián)。這是各種 Shell 以及很多應用程序使用的慣例,與 Linux 內(nèi)核無關。如果不遵循這種慣例,很多 Linux 系統(tǒng)應用程序就不能正常工作;

  • 用戶可以重定向文件描述符,甚至可以通過管道把一個程序的輸出作為另一個程序的輸入。Shell 就是通過這種方式實現(xiàn)重定向和管道的。

  • 在 POSIX 標準中,幻數(shù) 0、1、2 雖然已被標準化,但應當把它們替換成符號常量 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 以提高可讀性;

  • 文件描述符的范圍是 0 ~ OPEN_MAX-1;

  • 文件描述符并非局限于訪問普通文件。實際上,文件描述符也可以訪問設備文件、管道、FIFO、Socket等。遵循一切皆文件的理念,幾乎任何能夠讀寫的東西都可以通過文件描述符來訪問。

4. 通用文件模型:簡介

Linux 通用文件模型最為顯著的特性之一就是 I/O 通用性。也就是說,同一套系統(tǒng)調(diào)用 open()、read()、write()、close() 等所執(zhí)行的 I/O 操作,可施之于所有文件類型,包括設備文件在內(nèi)。應用程序發(fā)起的I/O請求,內(nèi)核會將其轉化為相應的文件系統(tǒng)操作,或者設備驅動程序操作,以此來執(zhí)行針對目標文件或設備的I/O操作。因此,采用這些系統(tǒng)調(diào)用的程序能夠處理任何類型的文件。

演示 demo (copy.c):

int main(int argc, char *argv[])
{
    int inputFd, outputFd, openFlags;
    mode_t filePerms;
    ssize_t numRead;
    char buf[BUF_SIZE];

    if (argc != 3 || strcmp(argv[1], "--help") == 0)
        usageErr("%s old-file new-file\n", argv[0]);

    /* Open input and output files */

    inputFd = open(argv[1], O_RDONLY);
    if (inputFd == -1)
        errExit("opening file %s", argv[1]);

    openFlags = O_CREAT | O_WRONLY | O_TRUNC;
    filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
                S_IROTH | S_IWOTH;      /* rw-rw-rw- */
    outputFd = open(argv[2], openFlags, filePerms);
    if (outputFd == -1)
        errExit("opening file %s", argv[2]);

    /* Transfer data until we encounter end of input or an error */

    while ((numRead = read(inputFd, buf, BUF_SIZE)) > 0)
        if (write(outputFd, buf, numRead) != numRead)
            fatal("write() returned error or partial write occurred");
    if (numRead == -1)
        errExit("read");

    if (close(inputFd) == -1)
        errExit("close input");
    if (close(outputFd) == -1)
        errExit("close output");

    exit(EXIT_SUCCESS);
}

運行效果:

$ ./copy test test.old
$ ./copy test /dev/tty
$ ./copy /dev/tty abc.txt

相關要點:

  • 要實現(xiàn)通用 I/O,就必須確保每一種文件系統(tǒng)和每一種文件類型(包括設備文件)都實現(xiàn)了相同的 I/O 系統(tǒng)調(diào)用集。由于文件系統(tǒng)或設備文件所特有的操作細節(jié)在內(nèi)核中處理,在編程時通常可以忽略設備專有的因素。一旦應用程序需要訪問文件系統(tǒng)或設備的專有功能時,可以選擇瑞士軍刀般的 ioctl() 系統(tǒng)調(diào)用,該調(diào)用為通用 I/O 模型之外的專有特性提供了訪問接口。

  • 提到通用 I/O,就必須提起虛擬文件系統(tǒng) (VFS)。為支持各種本機文件系統(tǒng),且在同時允許訪問其他操作系統(tǒng)的文件,Linux 內(nèi)核在用戶進程和文件系統(tǒng)實現(xiàn)之間引入了一個抽象層 VFS。虛擬文件系統(tǒng)基于文件通用模型(common file model,簡稱CFM)實現(xiàn)這種抽象,它是 Linux 上所有文件系統(tǒng)的基礎。

  • 一方面,VFS 提供了一種操作文件、目錄及其他對象的統(tǒng)一方法。另一方面,它與各種具體的文件系統(tǒng)的實現(xiàn)達成妥協(xié)。我們可以認為,是虛擬文件系統(tǒng) (VFS) 和通用文件模型 (CFM) 的共同作用為 Linux 提供了訪問不同文件系統(tǒng)以及不同類型的文件的 統(tǒng)一API (open()、read()、write()、close())。在本文中,我們將重點放在文件上,忽略文件系統(tǒng)相關的東西。

  • 在 VFS 中,并非所有文件系統(tǒng)都支持同樣的功能,有些操作對普通文件是不可缺少的,對某些對象則完全沒有意義。即并非每一種文件系統(tǒng)都支持 VFS 中的所有抽象

  • Linux VFS 的實現(xiàn): 參考 ext2 文件系統(tǒng),提供一種結構模型,該文件系統(tǒng)模型包含了一個強大文件系統(tǒng)所應具備的所有組件。但該模型是虛擬的,它適應于各種真實的文件系統(tǒng)。所有實現(xiàn)都必須提供可以適應 VFS 定義的結構體的 routines,因此可以充當兩個視圖之間的過渡。

  • 在 VFS 中,每個文件都關聯(lián)到一個 inode,我們可以 以 inode 和 inode->file_operations 作為學習通用文件模型和虛擬文件系統(tǒng)的切入點。

struct inode {
    umode_t   i_mode;
    ...
    const struct file_operations *i_fop;
    ...
}
struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_tint);
    ssize_t (*read) (struct file *, char __user *, size_tloff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_tloff_t *);
    ...
    long (*unlocked_ioctl) (struct file *, unsigned intunsigned long);
    long (*compat_ioctl) (struct file *, unsigned intunsigned long);
    int (*mmap) (struct file *, struct vm_area_struct *);
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *, fl_owner_t id);
...
} __randomize_layout;

5. 通用文件模型:文件描述符和打開文件的關系

5.1 相關的內(nèi)核數(shù)據(jù)結構

內(nèi)核使用 3 種數(shù)據(jù)結構來表示一個被打開的文件:

  • 進程級的文件描述符表 ( file descriptor table )。

  • 系統(tǒng)級的打開文件表 ( open file table ) 。

  • 文件系統(tǒng)的 i-node 表 ( i-node table )。

1) 進程級的文件描述符表 ( file descriptor table )

每個進程在進程表 (process table) 中都有一個記錄項 (process table entry),即 struct task_struct,內(nèi)核用它來描述一個進程。在 struct task_struct 中包含了一張打開文件描述符表 (open file descriptors table),由 struct files_struct 里的 struct fdtable 來表示 (Linux-4.14):

struct task_struct {
    ...
    /* Filesystem information: */
 struct fs_struct  *fs;

 /* Open file information: */
 struct files_struct  *files;
        -> struct fdtable *fdt;
    ...
}

每個文件描述符包含:

  • 1> 文件描述符標志 ( file descriptor flags,目前只有一個:close_on_exec,暫不關心 );
  • 2> 指向一個打開文件表項 ( open file table entry) 的指針。
struct fdtable {
    ...
 struct file **fd;      /* current fd array */
 unsigned long *close_on_exec;
 ...
};

2) 系統(tǒng)級的打開文件表 ( open file table )

內(nèi)核為所有打開文件維持一張打開文件表。每個打開文件表項包含:

  • 1> 文件狀態(tài)標志 ( file status flags,即 open() 的 flags 參數(shù));

  • 2> 當前文件偏移量 ( current file offset );

  • 3> 指向該文件 inode 表項的指針 (在某些 UNIX 系統(tǒng)中是 vnode pointer,在 Linux 中是 inode pointer)。

inode 結構體和 vnode 結構體名稱雖然不同,但是 2 者其實是同一個概念,它們都用于描述存儲在硬盤中的文件系統(tǒng)的 inode 數(shù)據(jù)。注意區(qū)別內(nèi)存里的 inode 結構體對象和硬盤中的 inode 數(shù)據(jù)。

3) 文件系統(tǒng)的 i-node 表 ( i-node table )

每個打開文件都有一個 inode 對象。inode 對象包含了:

  • 文件類型和對此文件進行各種操作函數(shù)的指針。

  • 對于大多數(shù)文件,inode 對象還包含了指向該文件系統(tǒng) inode 數(shù)據(jù)的指針。

struct inode {
    ...
    /* Stat data, not accessed from path walking */
    unsigned long  i_ino;

    ...
    /* former ->i_op->default_file_ops */
    const struct file_operations *i_fop; 
}

這些信息是在打開文件時從硬盤上讀入內(nèi)存的,所以,文件的所有相關信息都是隨時可用的。即 inode 對象包含了文件的所有者、文件長度、指向文件實際數(shù)據(jù)塊在磁盤上所在位置的指針等。

上述三張表的完整關系如下:

5.2 列舉幾種打開文件的情景

1) 兩個獨立進程各自打開同一個文件

兩個獨立進程各自打開了同一文件,則有如下關系:

第一個進程在文件描述符 3 上打開該文件,而另一個進程在文件描述符 4 上打開該文件。打開該文件的每個進程都獲得各自的一個打開文件表項,但對一個給定的文件只有一個 inode 節(jié)點表項。

之所以每個進程都獲得自己的打開文件表項,是因為這可以使每個進程都有它自己的對該文件的當前偏移量。

2) dup(1) 復制文件描述符

dup() 用來復制一個現(xiàn)有的文件描述符。

$ man 2 dup
       #include <unistd.h>
       int dup(int oldfd);

dup(1)后的內(nèi)核數(shù)據(jù)結構:

dup() 返回的新文件描述符與參數(shù) oldfd 共享同一個打開文件表項。

3) fork 之后父進程和子進程之間對打開文件的共享



假定所用的描述符是在fork之前打開的,如果父進程和子進程寫同一描述符指向的文件,但又沒有任何形式的同步,如使父進程等待子進程,那么它們的輸出就會相互混合。


三、總結

不好意思,這周身體不太舒服,文章拖更了,各位見諒。

鑒于大多數(shù)人的注意力無法在一篇文章里上集中太久,更多的內(nèi)容請大家先自行去閱讀吧,不是自己理解到的東西是消化不了的。有機會的話我會把更多的讀書心得放在后面的文章。

更多值得學習的知識點

  • stat() 的使用方法;
  • 復制文件描述符的方法 (dup, fcntl) 與使用場景;
  • 目錄相關的操作;
  • 高級文件 io 接口;
  • 文件 io 與標準 io 的對比;
  • VFS 的具體實現(xiàn);
  • ext2 文件系統(tǒng)的實現(xiàn);
  • ...

四、相關參考

1. 參考書籍

  • 《Linux 程序設計》(BLP)

    • 3 - 文件操作
  • 《Linux 系統(tǒng)編程》(LSP)

    • 1.4.1 - 文件和文件系統(tǒng)
  • 《UNIX 環(huán)境高級編程》(APUE)

    • 3.10 - 文件共享
    • 3.12 - dup
    • 4.3 - 文件類型
    • 8.3 - fork 文件共享
  • 《Linux/UNIX 系統(tǒng)編程手冊》(TLPI)

    • 2.5 - 文件I/O模型
    • 4 - 文件I/O:通用的I/O模型
    • 5.4 - 文件描述符和打開文件之間的關系
  • 《linux內(nèi)核設計與實現(xiàn)》(LKD)

    • 13 - 虛擬文件系統(tǒng)
  • 《深入理解LINUX內(nèi)核》(ULK)

    • 3.2 - 進程描述符
    • 12 - 虛擬文件系統(tǒng)
  • 《深入Linux內(nèi)核架構》(PLKA)

    • 6.3 - 與文件系統(tǒng)關聯(lián)
    • 8.2 - 通用文件模型
  • 《UNIX 操作系統(tǒng)設計》

    • 4 - 文件的內(nèi)部表示



免責聲明:本文內(nèi)容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

嵌入式ARM

掃描二維碼,關注更多精彩內(nèi)容

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: 驅動電源

在工業(yè)自動化蓬勃發(fā)展的當下,工業(yè)電機作為核心動力設備,其驅動電源的性能直接關系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅動電源設計中至關重要的兩個環(huán)節(jié),集成化方案的設計成為提升電機驅動性能的關鍵。

關鍵字: 工業(yè)電機 驅動電源

LED 驅動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設備的使用壽命。然而,在實際應用中,LED 驅動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設計、生...

關鍵字: 驅動電源 照明系統(tǒng) 散熱

根據(jù)LED驅動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關鍵字: LED 設計 驅動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術之一是電機驅動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機驅動系統(tǒng)中的關鍵元件,其性能直接影響到電動汽車的動力性能和...

關鍵字: 電動汽車 新能源 驅動電源

在現(xiàn)代城市建設中,街道及停車場照明作為基礎設施的重要組成部分,其質(zhì)量和效率直接關系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關鍵字: 發(fā)光二極管 驅動電源 LED

LED通用照明設計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關鍵字: LED 驅動電源 功率因數(shù)校正

在LED照明技術日益普及的今天,LED驅動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關鍵字: LED照明技術 電磁干擾 驅動電源

開關電源具有效率高的特性,而且開關電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現(xiàn)在的LED驅動電源

關鍵字: LED 驅動電源 開關電源

LED驅動電源是把電源供應轉換為特定的電壓電流以驅動LED發(fā)光的電壓轉換器,通常情況下:LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: LED 隧道燈 驅動電源
關閉