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

歡迎訪問 生活随笔!

生活随笔

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

linux

Linux设备驱动--块设备(二)之相关结构体

發布時間:2025/3/21 linux 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux设备驱动--块设备(二)之相关结构体 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上回最后面介紹了相關數據結構,下面再詳細介紹

塊設備對象結構 block_device

內核用結構block_device實例代表一個塊設備對象,如:整個硬盤或特定分區。如果該結構代表一個分區,則其成員bd_part指向設備的分區結構。如果該結構代表設備,則其成員bd_disk指向設備的通用硬盤結構gendisk

當用戶打開塊設備文件時,內核創建結構block_device實例,設備驅動程序還將創建結構gendisk實例,分配請求隊列并注冊結構block_device實例。

塊設備對象結構block_device列出如下(在include/Linux/fs.h中)

[cpp]?view plaincopy print?
  • struct?block_device?{??
  • dev_t?bd_dev;??/*?not?a?kdev_t?-?it's?a?search?key?*/??
  • struct?inode?*?bd_inode;?/*?分區節點?*/??
  • struct?super_block?*?bd_super;??
  • int?bd_openers;??
  • struct?mutex?bd_mutex;/*?open/close?mutex?打開與關閉的互斥量*/??
  • struct?semaphore?bd_mount_sem;????/*掛載操作信號量*/???
  • struct?list_head?bd_inodes;??
  • void?*?bd_holder;??
  • int?bd_holders;??
  • #ifdef?CONFIG_SYSFS??
  • struct?list_head?bd_holder_list;??
  • #endif??
  • struct?block_device?*?bd_contains;??
  • unsigned?bd_block_size;?????/*分區塊大小*/??
  • struct?hd_struct?*?bd_part;??
  • unsigned?bd_part_count;???/*打開次數*/??
  • int?bd_invalidated;??
  • struct?gendisk?*?bd_disk;?/*設備為硬盤時,指向通用硬盤結構*/??
  • struct?list_head?bd_list;??
  • struct?backing_dev_info?*bd_inode_backing_dev_info;??
  • unsigned?long?bd_private;??
  • /*?The?counter?of?freeze?processes?*/??
  • int?bd_fsfreeze_count;??
  • /*?Mutex?for?freeze?*/??
  • struct?mutex?bd_fsfreeze_mutex;??
  • };??

  • 通用硬盤結構 gendisk

    結構體gendisk代表了一個通用硬盤(generic hard disk)對象,它存儲了一個硬盤的信息,包括請求隊列、分區鏈表和塊設備操作函數集等。塊設備驅動程序分配結構gendisk實例,裝載分區表,分配請求隊列并填充結構的其他域。

    支持分區的塊驅動程序必須包含 <linux/genhd.h> 頭文件,并聲明一個結構gendisk,內核還維護該結構實例的一個全局鏈表gendisk_head,通過函數add_gendisk、del_gendisk和get_gendisk維護該鏈表。

    結構gendisk列出如下(在include/linux/genhd.h中):

    [cpp]?view plaincopy print?
  • struct?gendisk?{??
  • ????int?major;????????????/*?驅動程序的主設備號?*/??
  • ????int?first_minor;???????/*第一個次設備號*/??
  • ????int?minors;??????????/*次設備號的最大數量,沒有分區的設備,此值為1?*/??
  • ????char?disk_name[32];??/*?主設備號驅動程序的名字*/??
  • ????struct?hd_struct?**part;???/*?分區列表,由次設備號排序?*/??
  • ????struct?block_device_operations?*fops;??/*塊設備操作函數集*/??
  • ????struct?request_queue?*queue;?????????/*請求隊列*/??
  • ????struct?blk_scsi_cmd_filter?cmd_filter;??
  • ????void?*private_data;?????????????????/*私有數據*/??
  • ????sector_t?capacity;?????/*?函數set_capacity設置的容量,以扇區為單位*/??
  • ????int?flags;?????????????????/*設置驅動器狀態的標志,如:可移動介質為?
  • GENHD_FL_REMOVABLE*/??
  • ????struct?device?dev;?????????????????/*從設備驅動模型基類結構device繼承*/??
  • ????struct?kobject?*holder_dir;??
  • ????struct?kobject?*slave_dir;??
  • ?struct?timer_rand_state?*random;??
  • ????int?policy;???
  • ????atomic_t?sync_io;????????/*?RAID?*/??
  • ????unsigned?long?stamp;??
  • ????int?in_flight;??
  • #ifdef??CONFIG_SMP??
  • ????struct?disk_stats?*dkstats;????
  • #else??
  • /*硬盤統計信息,如:讀或寫的扇區數、融合的扇區數、在請求隊列的時間等*/??
  • ????struct?disk_stats?dkstats;??
  • #endif??
  • ????struct?work_struct?async_notify;??
  • #ifdef??CONFIG_BLK_DEV_INTEGRITY??
  • ????struct?blk_integrity?*integrity;???/*用于數據完整性擴展*/??
  • #endif??
  • };??

  • Linux內核提供了一組函數來操作gendisk,主要包括:
    分配gendisk
    struct gendisk *alloc_disk(int minors);
    minors 參數是這個磁盤使用的次設備號的數量,一般也就是磁盤分區的數量,此后minors不能被修改。
    增加gendisk
    gendisk結構體被分配之后,系統還不能使用這個磁盤,需要調用如下函數來注冊這個磁盤設備:
    void add_disk(struct gendisk *gd);
    特別要注意的是對add_disk()的調用必須發生在驅動程序的初始化工作完成并能響應磁盤的請求之后。

    ?釋放gendisk
    當不再需要一個磁盤時,應當使用如下函數釋放gendisk:
    void del_gendisk(struct gendisk *gd);

    設置gendisk容量
    void set_capacity(struct gendisk *disk, sector_t size);
    塊設備中最小的可尋址單元是扇區,扇區大小一般是2的整數倍,最常見的大小是512字節。扇區的大小是設備的物理屬性,扇區是所有塊設備的基本單元,塊設備 無法對比它還小的單元進行尋址和操作,不過許多塊設備能夠一次就傳輸多個扇區。雖然大多數塊設備的扇區大小都是512字節,不過其它大小的扇區也很常見, 比如,很多CD-ROM盤的扇區都是2K大小。不管物理設備的真實扇區大小是多少,內核與塊設備驅動交互的扇區都以512字節為單位。因此,set_capacity()函數也以512字節為單位。

    分區結構hd_struct代表了一個分區對象,它存儲了一個硬盤的一個分區的信息,驅動程序初始化時,從硬盤的分區表中提取分區信息,存放在分區結構實例中。

    塊設備操作函數集結構 block_device_operations

    字符設備通過 file_operations 操作結構使它們的操作對系統可用. 一個類似的結構用在塊設備上是 struct block_device_operations,
    定義在 <linux/fs.h>.?
    int (*open)(struct inode *inode, struct file *filp);?
    int (*release)(struct inode *inode, struct file *filp);?
    就像它們的字符驅動對等體一樣工作的函數; 無論何時設備被打開和關閉都調用它們. 一個字符驅動可能通過啟動設備或者鎖住門(為可移出的介質)來響應一個 open 調用. 如果你將介質鎖入設備, 你當然應當在 release 方法中解鎖.
    int (*ioctl)(struct inode *inode, struct file *filp,?
    ????????????????????????? unsigned int cmd, unsigned long arg);?
    實現 ioctl 系統調用的方法. 但是, 塊層首先解釋大量的標準請求; 因此大部分的塊驅動 ioctl 方法相當短.

    PS:在block_device_operations中沒有實際讀或寫數據的函數. 在塊 I/O 子系統, 這些操作由請求函數處理

    請求結構request

    結構request代表了掛起的I/O請求每個請求用一個結構request實例描述,存放在請求隊列鏈表中,由電梯算法進行排序,每個請求包含1個或多個結構bio實例

    [cpp]?view plaincopy print?
  • struct?request?{??
  • ????//用于掛在請求隊列鏈表的節點,使用函數blkdev_dequeue_request訪問它,而不能直接訪??
  • 問??
  • ????struct?list_head?queuelist;???
  • ????struct?list_head?donelist;??/*用于掛在已完成請求鏈表的節點*/??
  • ????struct?request_queue?*q;???/*指向請求隊列*/??
  • ????unsigned?int?cmd_flags;????/*命令標識*/??
  • ????enum?rq_cmd_type_bits?cmd_type;??/*命令類型*/??
  • ????/*各種各樣的扇區計數*/??
  • ???/*為提交i/o維護bio橫斷面的狀態信息,hard_*成員是塊層內部使用的,驅動程序不應該改變?
  • 它們*/??
  • ????sector_t?sector;?????/*將提交的下一個扇區*/??
  • ????sector_t?hard_sector;????????/*?將完成的下一個扇區*/??
  • ????unsigned?long?nr_sectors;??/*?整個請求還需要傳送的扇區數*/??
  • ????unsigned?long?hard_nr_sectors;?/*?將完成的扇區數*/??
  • ?/*在當前bio中還需要傳送的扇區數?*/??
  • ????unsigned?int?current_nr_sectors;??
  • ????/*在當前段中將完成的扇區數*/??
  • ????unsigned?int?hard_cur_sectors;??
  • ????struct?bio?*bio;?????/*請求中第一個未完成操作的bio*、?
  • ????struct?bio?*biotail;?/*請求鏈表中末尾的bio*、?
  • ????struct?hlist_node?hash;??/*融合?hash?*/??
  • ????/*?rb_node僅用在I/O調度器中,當請求被移到分發隊列中時,?
  • 請求將被刪除。因此,讓completion_data與rb_node分享空間*/??????
  • ????union?{??
  • ????????struct?rb_node?rb_node;???/*?排序/查找*/??
  • ????????void?*completion_data;??
  • ????};??
  • ?request結構體的主要成員包括:
    ?sector_t hard_sector;?
    unsigned long hard_nr_sectors;?
    unsigned int hard_cur_sectors;?
    上述3個成員標識還未完成的扇區,hard_sector是第1個尚未傳輸的扇區,hard_nr_sectors是尚待完成的扇區數,hard_cur_sectors是并且當前I/O操作中待完成的扇區數。這些成員只用于內核塊設備層,驅動不應當使用它們。


    ?sector_t sector;?
    unsigned long nr_sectors;?
    unsigned int current_nr_sectors;?
    驅動中會經常與這3個成員打交道,這3個成員在內核和驅動交互中發揮著重大作用。它們以512字節大小為1個扇區,如果硬件的扇區大小不是512字節,則需要進行相應的調整。例如,如果硬件的扇區大小是2048字節,則在進行硬件操作之前,需要用4來除起始扇區號。


    ?hard_sector、hard_nr_sectors、hard_cur_sectors與sector、nr_sectors、current_nr_sectors之間可認為是“副本”關系。


    struct bio *bio;?
    bio是這個請求中包含的bio結構體的鏈表,驅動中不宜直接存取這個成員,而應該使用后文將介紹的rq_for_each_bio()。

    請求隊列結構request_queue

    每個塊設備都有一個請求隊列,每個請求隊列單獨執行I/O調度,請求隊列是由請求結構實例鏈接成的雙向鏈表,鏈表以及整個隊列的信息用結構request_queue描述,稱為請求隊列對象結構或請求隊列結構。它存放了關于掛起請求的信息以及管理請求隊列(如:電梯算法)所需要的信息。結構成員request_fn是來自設備驅動程序的請求處理函數。

    請求隊列結構request_queue列出如下(在/include/linux/blk_dev.h中)

    太長了,此處略,其實也看不懂,- -#

    Bio結構

    通常1個bio對應1個I/O請求,IO調度算法可將連續的bio合并成1個請求。所以,1個請求可以包含多個bio。

    內核中塊I/O操作的基本容器由bio結構體表示,定義 在<linux/bio.h>中,該結構體代表了正在現場的(活動的)以片段(segment)鏈表形式組織的塊I/O操作。一個片段是一小 塊連續的內存緩沖區。這樣的好處就是不需要保證單個緩沖區一定要連續。所以通過片段來描述緩沖區,即使一個緩沖區分散在內存的多個位置上,bio結構體也 能對內核保證I/O操作的執行,這樣的就叫做聚散I/O.
    bio為通用層的主要數據結構,既描述了磁盤的位置,又描述了內存的位置,是上層內核vfs與下層驅動的連接紐帶

    [cpp]?view plaincopy print?
  • struct?bio?{??
  • sector_t????????bi_sector;//該bio結構所要傳輸的第一個(512字節)扇區:磁盤的位置??
  • struct?bio????????*bi_next;????//請求鏈表??
  • struct?block_device????*bi_bdev;//相關的塊設備??
  • unsigned?long????????bi_flags//狀態和命令標志??
  • unsigned?long????????bi_rw;?//讀寫??
  • unsigned?short????????bi_vcnt;//bio_vesc偏移的個數??
  • unsigned?short????????bi_idx;????//bi_io_vec的當前索引??
  • unsigned?short????????bi_phys_segments;//結合后的片段數目??
  • unsigned?short????????bi_hw_segments;//重映射后的片段數目??
  • unsigned?int????????bi_size;????//I/O計數??
  • unsigned?int????????bi_hw_front_size;//第一個可合并的段大小;??
  • unsigned?int????????bi_hw_back_size;//最后一個可合并的段大小??
  • unsigned?int????????bi_max_vecs;????//bio_vecs數目上限??
  • struct?bio_vec????????*bi_io_vec;????//bio_vec鏈表:內存的位置??
  • bio_end_io_t????????*bi_end_io;//I/O完成方法??
  • atomic_t????????bi_cnt;?//使用計數??
  • void????????????*bi_private;?//擁有者的私有方法??
  • bio_destructor_t????*bi_destructor;????//銷毀方法??
  • };??

  • 內存數據段結構bio_vec

    ?????? 結構bio_vec代表了內存中的一個數據段,數據段用頁、偏移和長度描
    述。I/O需要執行的內存位置用段表示,結構bio指向了一個段的數組。
    結構bio_vec列出如下(在include/linux/bio.h中):
    struct bio_vec {
    ?????? struct page???? *bv_page;?? /*數據段所在的頁*/
    ?????? unsigned short? bv_len;???? /*數據段的長度*/
    ?????? unsigned short? bv_offset;? /*數據段頁內偏移*/
    };

    塊設備各個結構體間關系

    轉載于:https://www.cnblogs.com/Ph-one/p/6435916.html

    總結

    以上是生活随笔為你收集整理的Linux设备驱动--块设备(二)之相关结构体的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。