国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

Linux 字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)(三)—— file、inode結(jié)構(gòu)體及chardevs數(shù)組等相關(guān)知識解析

2019-11-10 18:52:26
字體:
供稿:網(wǎng)友
 前面我們學(xué)習(xí)了字符設(shè)備結(jié)構(gòu)體cdev linux 字符設(shè)備驅(qū)動(dòng)開發(fā) (一)—— 字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)(上)  下面繼續(xù)學(xué)習(xí)字符設(shè)備另外幾個(gè)重要的數(shù)據(jù)結(jié)構(gòu)。

       先看下面這張圖,這是Linux 中虛擬文件系統(tǒng)、一般的設(shè)備文件與設(shè)備驅(qū)動(dòng)程序值間的函數(shù)調(diào)用關(guān)系;

        上面這張圖展現(xiàn)了一個(gè)應(yīng)用程序調(diào)用字符設(shè)備驅(qū)動(dòng)的過程, 在設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)中,一般而言,會(huì)關(guān)心 file 和 inode 這兩個(gè)結(jié)構(gòu)體

        用戶空間使用 open() 函數(shù)打開一個(gè)字符設(shè)備 fd = open("/dev/hello",O_RDWR) , 這一函數(shù)會(huì)調(diào)用兩個(gè)數(shù)據(jù)結(jié)構(gòu) struct inode{...}struct file{...} ,二者均在虛擬文件系統(tǒng)VFS處,下面對兩個(gè)數(shù)據(jù)結(jié)構(gòu)進(jìn)行解析:

一、file 文件結(jié)構(gòu)體

       在設(shè)備驅(qū)動(dòng)中,這也是個(gè)非常重要的數(shù)據(jù)結(jié)構(gòu),必須要注意一點(diǎn),這里的file與用戶空間程序中的FILE指針是不同的,用戶空間FILE是定義在C庫中,從來不會(huì)出現(xiàn)在內(nèi)核中。而struct file,卻是內(nèi)核當(dāng)中的數(shù)據(jù)結(jié)構(gòu),因此,它也不會(huì)出現(xiàn)在用戶層程序中。

       file結(jié)構(gòu)體指示一個(gè)已經(jīng)打開的文件(設(shè)備對應(yīng)于設(shè)備文件),其實(shí)系統(tǒng)中的每個(gè)打開的文件在內(nèi)核空間都有一個(gè)相應(yīng)的struct file結(jié)構(gòu)體,它由內(nèi)核在打開文件時(shí)創(chuàng)建,并傳遞給在文件上進(jìn)行操作的任何函數(shù),直至文件被關(guān)閉。如果文件被關(guān)閉,內(nèi)核就會(huì)釋放相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。

     在內(nèi)核源碼中,struct file要么表示為file,或者為filp(意指“file pointer”), 注意區(qū)分一點(diǎn),file指的是struct file本身,而filp是指向這個(gè)結(jié)構(gòu)體的指針。

下面是幾個(gè)重要成員:

a -- fmode_t f_mode;

      此文件模式通過FMODE_READ, FMODE_WRITE識別了文件為可讀的,可寫的,或者是二者。在open或ioctl函數(shù)中可能需要檢查此域以確認(rèn)文件的讀/寫權(quán)限,你不必直接去檢測讀或?qū)憴?quán)限,因?yàn)樵谶M(jìn)行octl等操作時(shí)內(nèi)核本身就需要對其權(quán)限進(jìn)行檢測。

 b -- loff_t f_pos;

     當(dāng)前讀寫文件的位置。為64位。如果想知道當(dāng)前文件當(dāng)前位置在哪,驅(qū)動(dòng)可以讀取這個(gè)值而不會(huì)改變其位置。對read,write來說,當(dāng)其接收到一個(gè)loff_t型指針作為其最后一個(gè)參數(shù)時(shí),他們的讀寫操作便作更新文件的位置,而不需要直接執(zhí)行filp ->f_pos操作。而llseek方法的目的就是用于改變文件的位置。

c -- unsigned int f_flags;

     文件標(biāo)志,如O_RDONLY, O_NONBLOCK以及O_SYNC。在驅(qū)動(dòng)中還可以檢查O_NONBLOCK標(biāo)志查看是否有非阻塞請求。其它的標(biāo)志較少使用。特別地注意的是,讀寫權(quán)限的檢查是使用f_mode而不是f_flog。所有的標(biāo)量定義在頭文件中

d -- struct file_Operations *f_op;

    與文件相關(guān)的各種操作。當(dāng)文件需要迅速進(jìn)行各種操作時(shí),內(nèi)核分配這個(gè)指針作為它實(shí)現(xiàn)文件打開,讀,寫等功能的一部分。filp->f_op 其值從未被內(nèi)核保存作為下次的引用,即你可以改變與文件相關(guān)的各種操作,這種方式效率非常高。

    file_operation 結(jié)構(gòu)體解析如下:Linux 字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)(四)—— file_operations 結(jié)構(gòu)體知識解析

e -- void *PRivate_data;

      在驅(qū)動(dòng)調(diào)用open方法之前,open系統(tǒng)調(diào)用設(shè)置此指針為NULL值。你可以很自由的將其做為你自己需要的一些數(shù)據(jù)域或者不管它,如,你可以將其指向一個(gè)分配好的數(shù)據(jù),但是你必須記得在file struct被內(nèi)核銷毀之前在release方法中釋放這些數(shù)據(jù)的內(nèi)存空間。private_data用于在系統(tǒng)調(diào)用期間保存各種狀態(tài)信息是非常有用的。

二、 inode結(jié)構(gòu)體

         VFS inode 包含文件訪問權(quán)限、屬主、組、大小、生成時(shí)間、訪問時(shí)間、最后修改時(shí)間等信息。它是Linux 管理文件系統(tǒng)的最基本單位,也是文件系統(tǒng)連接任何子目錄、文件的橋梁。

        內(nèi)核使用inode結(jié)構(gòu)體在內(nèi)核內(nèi)部表示一個(gè)文件。因此,它與表示一個(gè)已經(jīng)打開的文件描述符的結(jié)構(gòu)體(即file 文件結(jié)構(gòu))是不同的,我們可以使用多個(gè)file 文件結(jié)構(gòu)表示同一個(gè)文件的多個(gè)文件描述符,但此時(shí),所有的這些file文件結(jié)構(gòu)全部都必須只能指向一個(gè)inode結(jié)構(gòu)體

      inode結(jié)構(gòu)體包含了一大堆文件相關(guān)的信息,但是就針對驅(qū)動(dòng)代碼來說,我們只要關(guān)心其中的兩個(gè)域即可:

(1) dev_t i_rdev;

      表示設(shè)備文件的結(jié)點(diǎn),這個(gè)域?qū)嶋H上包含了設(shè)備號。

(2) struct cdev *i_cdev;

      struct cdev是內(nèi)核的一個(gè)內(nèi)部結(jié)構(gòu),它是用來表示字符設(shè)備的,當(dāng)inode結(jié)點(diǎn)指向一個(gè)字符設(shè)備文件時(shí),此域?yàn)橐粋€(gè)指向inode結(jié)構(gòu)的指針。

下面是源代碼:

[cpp] view plain copy 在CODE上查看代碼片struct inode {   struct hlist_node i_hash;   struct list_head i_list;   struct list_head i_sb_list;   struct list_head i_dentry;   unsigned long  i_ino;   atomic_t  i_count;   unsigned int  i_nlink;   uid_t   i_uid;//inode擁有者id   gid_t   i_gid;//inode所屬群組id   dev_t   i_rdev;//若是設(shè)備文件,表示記錄設(shè)備的設(shè)備號   u64   i_version;   loff_t   i_size;//inode所代表大少  #ifdef __NEED_I_SIZE_ORDERED   seqcount_t  i_size_seqcount;  #endif   struct timespec  i_atime;//inode最近一次的存取時(shí)間   struct timespec  i_mtime;//inode最近一次修改時(shí)間   struct timespec  i_ctime;//inode的生成時(shí)間   unsigned int  i_blkbits;   blkcnt_t  i_blocks;   unsigned short          i_bytes;   umode_t   i_mode;   spinlock_t  i_lock;    struct mutex  i_mutex;   struct rw_semaphore i_alloc_sem;   const struct inode_operations *i_op;   const struct file_operations *i_fop;    struct super_block *i_sb;   struct file_lock *i_flock;   struct address_space *i_mapping;   struct address_space i_data;  #ifdef CONFIG_QUOTA   struct dquot  *i_dquot[MAXQUOTAS];  #endif   struct list_head i_devices;   union {    struct p#define CHRDEV_MAJOR_HASH_SIZE 255  static DEFINE_MUTEX(chrdevs_lock);    static struct char_device_struct {      struct char_device_struct *next; // 結(jié)構(gòu)體指針      unsigned int major;              // 主設(shè)備號      unsigned int baseminor;          // 次設(shè)備起始號      int minorct;                     // 次備號個(gè)數(shù)      char name[64];      struct cdev *cdev; /* will die */  } *chrdevs[CHRDEV_MAJOR_HASH_SIZE];      // 只能掛255個(gè)字符主設(shè)備<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">  </span>  

 %20 %20 %20 可以看到全局?jǐn)?shù)組%20chrdevs%20包含了255(CHRDEV_MAJOR_HASH_SIZE%20的值)個(gè)%20struct%20char_device_struct的元素,每一個(gè)對應(yīng)一個(gè)相應(yīng)的主設(shè)備號。

 %20 %20 %20 如果分配了一個(gè)設(shè)備號,就會(huì)創(chuàng)建一個(gè)%20struct%20char_device_struct%20的對象,并將其添加到%20chrdevs%20中;這樣,通過chrdevs數(shù)組,我們就可以知道分配了哪些設(shè)備號。

相關(guān)函數(shù),(這些函數(shù)在上篇已經(jīng)介紹過,現(xiàn)在回顧一下:

  register_chrdev_region( ) 分配指定的設(shè)備號范圍

  alloc_chrdev_region( ) 動(dòng)態(tài)分配設(shè)備范圍

他們都主要是通過調(diào)用函數(shù) __register_chrdev_region() 來實(shí)現(xiàn)的;要注意,這兩個(gè)函數(shù)僅僅是注冊設(shè)備號!如果要和cdev關(guān)聯(lián)起來,還要調(diào)用cdev_add()。

  register_chrdev( )申請指定的設(shè)備號,并且將其注冊到字符設(shè)備驅(qū)動(dòng)模型中.

  它所做的事情為:

a -- 注冊設(shè)備號, 通過調(diào)用 __register_chrdev_region() 來實(shí)現(xiàn)

b -- 分配一個(gè)cdev, 通過調(diào)用 cdev_alloc() 來實(shí)現(xiàn)

c -- 將cdev添加到驅(qū)動(dòng)模型中, 這一步將設(shè)備號和驅(qū)動(dòng)關(guān)聯(lián)了起來. 通過調(diào)用 cdev_add() 來實(shí)現(xiàn)

d -- 將第一步中創(chuàng)建的 struct char_device_struct 對象的 cdev 指向第二步中分配的cdev. 由于register_chrdev()是老的接口,這一步在新的接口中并不需要。

四、cdev 結(jié)構(gòu)體

        在 Linux 字符設(shè)備驅(qū)動(dòng)開發(fā) (一)—— 字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)(上) 有解析。

五、文件系統(tǒng)中對字符設(shè)備文件的訪問

        下面看一下上層應(yīng)用open() 調(diào)用系統(tǒng)調(diào)用函數(shù)的過程

        對于一個(gè)字符設(shè)備文件, 其inode->i_cdev 指向字符驅(qū)動(dòng)對象cdev, 如果i_cdev為 NULL ,則說明該設(shè)備文件沒有被打開.

  由于多個(gè)設(shè)備可以共用同一個(gè)驅(qū)動(dòng)程序.所以,通過字符設(shè)備的inode 中的i_devices 和 cdev中的list組成一個(gè)鏈表

        首先,系統(tǒng)調(diào)用open打開一個(gè)字符設(shè)備的時(shí)候, 通過一系列調(diào)用,最終會(huì)執(zhí)行到 chrdev_open

  (最終是通過調(diào)用到def_chr_fops中的.open, 而def_chr_fops.open = chrdev_open. 這一系列的調(diào)用過程,本文暫不討論)

  int chrdev_open(struct inode * inode, struct file * filp)

chrdev_open()所做的事情可以概括如下:

  1. 根據(jù)設(shè)備號(inode->i_rdev), 在字符設(shè)備驅(qū)動(dòng)模型中查找對應(yīng)的驅(qū)動(dòng)程序, 這通過kobj_lookup() 來實(shí)現(xiàn), kobj_lookup()會(huì)返回對應(yīng)驅(qū)動(dòng)程序cdev的kobject.

  2. 設(shè)置inode->i_cdev , 指向找到的cdev.

  3. 將inode添加到cdev->list 的鏈表中.

  4. 使用cdev的ops 設(shè)置file對象的f_op

  5. 如果ops中定義了open方法,則調(diào)用該open方法

  6. 返回

執(zhí)行完 chrdev_open()之后,file對象的f_op指向cdev的ops,因而之后對設(shè)備進(jìn)行的read, write等操作,就會(huì)執(zhí)行cdev的相應(yīng)操作。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 克拉玛依市| 崇阳县| 东台市| 镶黄旗| 米泉市| 木里| 木兰县| 太仆寺旗| 卫辉市| 上林县| 随州市| 文登市| 高清| 偃师市| 大港区| 东阿县| 思南县| 团风县| 密山市| 远安县| 西安市| 股票| 兴城市| 苍南县| 通化县| 永年县| 申扎县| 师宗县| 都江堰市| 芦山县| 神农架林区| 万源市| 安乡县| 普洱| 瑞昌市| 嘉黎县| 宜君县| 广元市| 邵阳市| 嫩江县| 乌兰浩特市|