linux驅動 cdev,inode結構體

前面我們學習了字符設備結構體cdev? Linux 字符設備驅動開發 (一)—— 字符設備驅動結構(上)? 下面繼續學習字符設備另外幾個重要的 數據結構。

? ? ? ?先看下面這張圖,這是Linux 中虛擬文件系統、一般的設備文件與設備驅動程序值間的函數調用關系;



? ? ? ? 上面這張圖展現了一個應用程序調用字符設備驅動的過程, 在設備驅動程序的設計中,一般而言,會關心 file 和 inode 這兩個結構體

? ? ? ? 用戶空間使用 open() 函數打開一個字符設備 fd = open("/dev/hello",O_RDWR) , 這一函數會調用兩個數據結構 struct inode{...}struct file{...} ,二者均在虛擬文件系統VFS處,下面對兩個數據結構進行解析:


一、file 文件結構體

? ? ? ?在設備驅動中,這也是個非常重要的數據結構,必須要注意一點,這里的file與用戶空間程序中的FILE指針是不同的,用戶空間FILE是定義在C庫中,從來不會出現在內核中。而struct file,卻是內核當中的數據結構,因此,它也不會出現在用戶層程序中。

? ? ? ?file結構體指示一個已經打開的文件(設備對應于設備文件),其實系統中的每個打開的文件在內核空間都有一個相應的struct file結構體,它由內核在打開文件時創建,并傳遞給在文件上進行操作的任何函數,直至文件被關閉。如果文件被關閉,內核就會釋放相應的數據結構。

? ? ?在內核源碼中,struct file要么表示為file,或者為filp(意指“file pointer”), 注意區分一點,file指的是struct file本身,而filp是指向這個結構體的指針。

下面是幾個重要成員:

a -- fmode_t f_mode;

? ? ? 此文件模式通過FMODE_READ, FMODE_WRITE識別了文件為可讀的,可寫的,或者是二者。在open或ioctl函數中可能需要檢查此域以確認文件的讀/寫權限,你不必直接去檢測讀或寫權限,因為在進行octl等操作時內核本身就需要對其權限進行檢測。

?b -- loff_t f_pos;

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

c -- unsigned int f_flags;

? ? ?文件標志,如O_RDONLY, O_NONBLOCK以及O_SYNC。在驅動中還可以檢查O_NONBLOCK標志查看是否有非阻塞請求。其它的標志較少使用。特別地注意的是,讀寫權限的檢查是使用f_mode而不是f_flog。所有的標量定義在頭文件中

d -- struct file_operations *f_op;

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

? ? file_operation 結構體解析如下:Linux 字符設備驅動結構(四)—— file_operations 結構體知識解析

e -- void *private_data;

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



二、?inode結構體

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

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

? ? ? inode結構體包含了一大堆文件相關的信息,但是就針對驅動代碼來說,我們只要關心其中的兩個域即可:

(1) dev_t i_rdev;

? ? ? 表示設備文件的結點,這個域實際上包含了設備號

(2) struct cdev *i_cdev;

? ? ? struct cdev是內核的一個內部結構,它是用來表示字符設備的,當inode結點指向一個字符設備文件時,此域為一個指向inode結構的指針。

下面是源代碼:

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. struct?inode?{??
  2. ?struct?hlist_node?i_hash;??
  3. ?struct?list_head?i_list;??
  4. ?struct?list_head?i_sb_list;??
  5. ?struct?list_head?i_dentry;??
  6. ?unsigned?long??i_ino;??
  7. ?atomic_t??i_count;??
  8. ?unsigned?int??i_nlink;??
  9. ?uid_t???i_uid;//inode擁有者id??
  10. ?gid_t???i_gid;//inode所屬群組id??
  11. ?dev_t???i_rdev;//若是設備文件,表示記錄設備的設備號??
  12. ?u64???i_version;??
  13. ?loff_t???i_size;//inode所代表大少??
  14. #ifdef?__NEED_I_SIZE_ORDERED??
  15. ?seqcount_t??i_size_seqcount;??
  16. #endif??
  17. ?struct?timespec??i_atime;//inode最近一次的存取時間??
  18. ?struct?timespec??i_mtime;//inode最近一次修改時間??
  19. ?struct?timespec??i_ctime;//inode的生成時間??
  20. ?unsigned?int??i_blkbits;??
  21. ?blkcnt_t??i_blocks;??
  22. ?unsigned?short??????????i_bytes;??
  23. ?umode_t???i_mode;??
  24. ?spinlock_t??i_lock;???
  25. ?struct?mutex??i_mutex;??
  26. ?struct?rw_semaphore?i_alloc_sem;??
  27. ?const?struct?inode_operations?*i_op;??
  28. ?const?struct?file_operations?*i_fop;???
  29. ?struct?super_block?*i_sb;??
  30. ?struct?file_lock?*i_flock;??
  31. ?struct?address_space?*i_mapping;??
  32. ?struct?address_space?i_data;??
  33. #ifdef?CONFIG_QUOTA??
  34. ?struct?dquot??*i_dquot[MAXQUOTAS];??
  35. #endif??
  36. ?struct?list_head?i_devices;??
  37. ?union?{??
  38. ??struct?pipe_inode_info?*i_pipe;??
  39. ??struct?block_device?*i_bdev;??
  40. ??struct?cdev??*i_cdev;//若是字符設備,對應的為cdev結構體??
  41. ?};??


三、chardevs 數組

? ? ?從圖中可以看出,通過數據結構 struct inode{...} 中的 i_cdev 成員可以找到cdev,而所有的字符設備都在 chrdevs 數組中

下面先看一下 chrdevs 的定義:

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. #define?CHRDEV_MAJOR_HASH_SIZE?255??
  2. static?DEFINE_MUTEX(chrdevs_lock);??
  3. ??
  4. static?struct?char_device_struct?{??
  5. ????struct?char_device_struct?*next;?//?結構體指針??
  6. ????unsigned?int?major;??????????????//?主設備號??
  7. ????unsigned?int?baseminor;??????????//?次設備起始號??
  8. ????int?minorct;?????????????????????//?次備號個數??
  9. ????char?name[64];??
  10. ????struct?cdev?*cdev;?/*?will?die?*/??
  11. }?*chrdevs[CHRDEV_MAJOR_HASH_SIZE];??????//?只能掛255個字符主設備<span?style="font-family:?Arial,?Helvetica,?sans-serif;?background-color:?rgb(255,?255,?255);">??</span>??

? ? ? ?可以看到全局數組 chrdevs 包含了255(CHRDEV_MAJOR_HASH_SIZE 的值)個 struct char_device_struct的元素,每一個對應一個相應的主設備號。

? ? ? ?如果分配了一個設備號,就會創建一個 struct char_device_struct 的對象,并將其添加到 chrdevs 中;這樣,通過chrdevs數組,我們就可以知道分配了哪些設備號。


相關函數,(這些函數在上篇已經介紹過,現在回顧一下:

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

  alloc_chrdev_region( ) 動態分配設備范圍

他們都主要是通過調用函數 __register_chrdev_region() 來實現的;要注意,這兩個函數僅僅是注冊設備號!如果要和cdev關聯起來,還要調用cdev_add()。

  register_chrdev( )申請指定的設備號,并且將其注冊到字符設備驅動模型中.

  它所做的事情為:

a -- 注冊設備號, 通過調用 __register_chrdev_region() 來實現

b -- 分配一個cdev, 通過調用 cdev_alloc() 來實現

c -- 將cdev添加到驅動模型中, 這一步將設備號和驅動關聯了起來. 通過調用 cdev_add() 來實現

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


四、cdev 結構體

? ? ? ? 在?Linux 字符設備驅動開發 (一)—— 字符設備驅動結構(上)?有解析。


五、文件系統中對字符設備文件的訪問

? ? ? ? 下面看一下上層應用open() 調用系統調用函數的過程

? ? ? ? 對于一個字符設備文件, 其inode->i_cdev 指向字符驅動對象cdev, 如果i_cdev為 NULL ,則說明該設備文件沒有被打開.

  由于多個設備可以共用同一個驅動程序.所以,通過字符設備的inode 中的i_devices 和 cdev中的list組成一個鏈表


? ? ? ? 首先,系統調用open打開一個字符設備的時候, 通過一系列調用,最終會執行到 chrdev_open

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

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

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

  1. 根據設備號(inode->i_rdev), 在字符設備驅動模型中查找對應的驅動程序, 這通過kobj_lookup() 來實現, kobj_lookup()會返回對應驅動程序cdev的kobject.

  2. 設置inode->i_cdev , 指向找到的cdev.

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

  4. 使用cdev的ops 設置file對象的f_op

  5. 如果ops中定義了open方法,則調用該open方法

  6. 返回

執行完 chrdev_open()之后,file對象的f_op指向cdev的ops,因而之后對設備進行的read, write等操作,就會執行cdev的相應操作。



本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457897.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457897.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457897.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何在VS和CB中配置MySQL環境

這里&#xff0c;由于我的MySQL安裝在D盤 MY SQL\MySQL Server 5.6該路徑下&#xff0c;所以后面的路徑均以D:\MY SQL\MySQL Server 5.6開頭 在VS中配置MySQL環境 包含目錄&#xff1a; D:\MY SQL\MySQL Server 5.6\include 庫目錄&#xff1a;D:\MY SQL\MySQL Server 5.…

點乘和叉乘的區別_關于延時和混響的區別與專用延時器與混響器的調控技巧

關于延時和混響的區別與專用延時器與混響器的調控技巧延時器與混響器是模擬室內聲場聲音信號特性的專用設備。在錄音節目制作中&#xff0c;延時器和混響器可以在模擬的藝術聲場中傳遞時間、空間、方位、距離等重要信息&#xff0c;并且可以制作某些特殊效果。延時器與混響器工…

zabbix監控工具

實驗環境網關 classroom 172.25.8.254workstation 172.25.8.9server a-jeth0 172.25.8.10-外網eth1 192.168.0.x內網eth2 192.168.1.x備用servera:webservere:server--------------------------------------------需求&#xff1a;監控設計&#xff1a;原理&#xff1a;硬件&…

linux驅動 自旋鎖

最近在內核頻繁使用了自旋鎖&#xff0c;自旋鎖如果使用不當&#xff0c;極易引起死鎖&#xff0c;在此總結一下。 自旋鎖是一個互斥設備&#xff0c;它只有兩個值&#xff1a;“鎖定”和“解鎖”。它通常實現為某個整數值中的某個位。希望獲得某個特定鎖得代碼測試相關的位。…

百度輸入法

[用戶界面]&#xff1a;界面美觀&#xff0c;有不同畫風的ui界面&#xff0c;適合不同消費群體的需求。 [記住用戶選擇]&#xff1a;會默認記住用戶以往的輸入習慣&#xff0c;只需輸入首拼音字母就會出現過去使用的高頻詞。 [短期刺激]&#xff1a;美化的用戶界面讓人眼前一新…

rs232讀取智能電表_三相電表怎么看度數 怎么計算總電量

現在的三相電表一般都是在屏幕上面直接看&#xff0c;屏幕上面是有文字提示顯示的&#xff0c;三相電表的總度數&#xff0c;上面的文字提醒一般是“正向有功總電量”&#xff0c;三相電表一般屏幕旁邊都會上翻鍵和下翻鍵&#xff0c;可以上下翻開電表里面的數據。如下圖所示&a…

android 學習隨筆十六(廣播 )

1、廣播接收者 BroadcastReceiver接收系統發出的廣播現實中的廣播&#xff1a;電臺為了傳達一些消息&#xff0c;而發送的廣播&#xff0c;通過廣播攜帶要傳達的消息&#xff0c;群眾只要買一個收音機&#xff0c;就可以收到廣播了 Android中的廣播&#xff1a;系統在運行過程中…

驅動面試題總結

1、字符型驅動設備你是怎么創建設備文件的&#xff0c;就是/dev/下面的設備文件&#xff0c;供上層應用程序打開使用的文件&#xff1f; 答&#xff1a;mknod命令結合設備的主設備號和次設備號&#xff0c;可創建一個設備文件。 評&#xff1a;這只是其中一種方式&#xff0…

python程序寫詩_將Python詩歌與D結合起來

在與docker一起使用poetry時&#xff0c;需要記住以下幾點。 安裝 安裝poetry的正式方法是通過&#xff1a;curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python 這種方式允許poetry及其依賴項與依賴項分離。但是&#xff0c;在我看來…

Azure運維系列 4:安裝和使用Azure PowerShell管理云

前面講到了很多的管理方式&#xff0c;包括Azure中國最近更新的預覽版管理門戶和Azure云助理&#xff0c;都是非常不錯的管理Azure的方式&#xff0c;今天我們再來介紹一種更加高效的管理方式Azure PowerShell。熟悉命令行的朋友都知道&#xff0c;Linux之所以那么好用是因為其…

[轉]char * 和字符數組

[轉]char * 和字符數組 原文地址&#xff1a;http://www.cnblogs.com/jeakon/archive/2012/05/27/2816809.html 代碼中的int * i就是我們關注的焦點。它是一個指向int指針。也就是說&#xff1a;i指向一個內存地址&#xff0c;從這個地址開始存儲了一個數據。int * i中的int標明…

設備模型1

作為開頭篇&#xff0c;我不想寫HELLLOWORLD驅動&#xff0c;甚至字符設備驅動的開發&#xff0c;這樣文章充斥在各大網站上的博客上&#xff0c;隨便搜搜&#xff0c;就可以找到幾百篇。這是最基本的東西&#xff0c;通過這些內容的學習&#xff0c;我們要掌握LINUX驅動的基本…

如何使用Android Studio把自己的Android library分享到jCenter和Maven Central

第一部分&#xff1a;在bintray上創建package首先&#xff0c;你需要在bintray上創建一個package。為此&#xff0c;你需要一個bintray賬號&#xff0c;并在網站上創建一個package。第一步&#xff1a;在bintray.com上注冊一個賬號。&#xff08;注冊過程很簡單&#xff0c;自己…

python2編碼_Python2字符編碼

我們通常見到的字符串編碼主要是三種GB2312/GBK、Unicode、UTF-8。GB2312/GBK是多字節(multibytes)編碼的一種&#xff0c;屬于“ASCII的加強版”&#xff0c;與之平行的由Big5、ShiftJIS之類的編碼各自為政&#xff0c;所有這些用兩個字節表示漢字的多字節編碼標準統稱為ANSI編…

angularJs關于指令的一些冷門屬性

我們使用ng的時候&#xff0c;經常會使用到指令&#xff0c;大家所熟知的屬性我在這里就不介紹了&#xff0c;講講大家沒怎么留意的屬性 1.multiElement 這是指定指令作用區間的功能&#xff0c;最常用的就是ng-repeat-start和ng-repeat-end了。 2.priority 指令優先級&#xf…

設備模型2

前言 在上一篇中&#xff0c;我們大致描述了LINUX設備模型&#xff0c;我們先來總結一下三要素的關系。 從圖中可以看出,Linux設備模型就是"總線、設備、驅動、類"這四個概念之前的相互關系;這也是Linux2.6內核抽象出來的用于管理系統中所有設備的模型圖; 簡單地描述…

angular自定義指令詳解

指令&#xff08;directive&#xff09;是angular里面最核心也是最難懂的東西&#xff0c;在慕課網看了下大漠窮秋老濕的視頻&#xff0c;自己百度半天做了一些小test&#xff0c;總算把一切都搞明白了。 先列出學習來源&#xff1a; 指令中controller和link的區別&#xff1a;…

delphi7aes加密解密與java互轉_跨語言(java vs python vs nodejs)的RSA加解密問題探討

多次被問到這樣的問題&#xff1a;java服務端的rsa加密操作已經完成&#xff0c;返回一個16進制的字符串給python平臺&#xff0c;但是在python進行私鑰解密的時候發現行不通。。。。前端python加密&#xff0c;后端用java解密&#xff0c;解不出來還有諸如nodejs從理論上來說&…

類的定義、成員定義修飾符

類的定義 修飾符含義1無或internal 只能在當前項目中訪問類&#xff0c;其它項目引用后也無法訪問2public 可以任何地方訪問類3abstract 不能實例化&#xff0c;只能供繼承之用4sealed 不能供派生之用&#xff0c;只能實例化5internal abstract136public abstract237intern…

設備模型3

在上一篇分析中&#xff0c;多次提到了SYSFS&#xff0c;這是個什么東西&#xff1f;這可是個很大的TOPIC&#xff0c;關于它的講述可以寫本書&#xff0c;但是我們暫時的目標不是要完全啃投它所有的東西&#xff0c;沒時間&#xff0c;沒精力&#xff0c;我們只要掌握我們需要…