驅動開發學習筆記---塊設備

来源:https://www.cnblogs.com/zhuzi1/archive/2022/12/04/16949505.html
-Advertisement-
Play Games

一、塊設備簡介 塊設備驅動是存儲設備驅動,塊設備驅動相比字元設備驅動的主要區別如下: ①、塊設備只能以塊為單位進行讀寫訪問,塊是 linux 虛擬文件系統(VFS)基本的數據傳輸單位。字元設備是以位元組為單位進行數據傳輸的,不需要緩衝。 ②、塊設備在結構上是可以進行隨機訪問的,對於這些設備的讀寫都是按 ...


一、塊設備簡介

塊設備驅動是存儲設備驅動,塊設備驅動相比字元設備驅動的主要區別如下:

①、塊設備只能以塊為單位進行讀寫訪問,塊是 linux 虛擬文件系統(VFS)基本的數據傳輸單位。字元設備是以位元組為單位進行數據傳輸的,不需要緩衝。

②、塊設備在結構上是可以進行隨機訪問的,對於這些設備的讀寫都是按塊進行的,塊設備使用緩衝區來暫時存放數據,等到條件成熟以後再一次性將緩衝區中的數據寫入塊設備中。

二、塊設備驅動框架

1、註冊註銷塊設備

int register_blkdev(unsigned int major, const char *name)  
void unregister_blkdev(unsigned int major, const char *name)

major: 要註銷的塊設備主設備號。 name: 要註銷的塊設備名字。

2、申請和刪除磁碟設備

struct gendisk *alloc_disk(int minors)  

minors: 次設備號數量, 也就是 gendisk 對應的分區數量。

void del_gendisk(struct gendisk *gp)

gp: 要刪除的 gendisk。

3、將 gendisk 添加到內核

void add_disk(struct gendisk *disk)  

disk: 要添加到內核的 gendisk。

4、設置 gendisk 容量

void set_capacity(struct gendisk *disk, sector_t size)  

disk: 要設置容量的 gendisk。 size: 磁碟容量大小,註意這裡是扇區數量。塊設備中最小的可定址單元是扇區,一個扇區一般是 512 位元組,有些設備的物理扇區可能不是 512 位元組。不管物理扇區是多少,內核和塊設備驅動之間的扇區都是 512 位元組。所以 set_capacity 函數設置的大小就是塊設備實際容量除以512 位元組得到的扇區數量。比如一個 2MB 的磁碟,其扇區數量就是(210241024)/512=4096。

5、調整 gendisk 引用計數

內核會通過 get_disk 和 put_disk 這兩個函數來調整 gendisk 的引用計數,根據名字就可以知道, get_disk 是增加 gendisk 的引用計數, put_disk 是減少 gendisk 的引用計數。

truct kobject *get_disk(struct gendisk *disk)
void put_disk(struct gendisk *disk)

6、塊設備操作集

struct block_device_operations {
int (*open) (struct block_device *, fmode_t);
void (*release) (struct gendisk *, fmode_t);
int (*rw_page)(struct block_device *, sector_t, struct page *,int rw);
int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
long (*direct_access)(struct block_device *, sector_t,void **, unsigned long *pfn, long size);
unsigned int (*check_events) (struct gendisk *disk,unsigned int clearing);
 /* ->media_changed() is DEPRECATED, use ->check_events() instead */
int (*media_changed) (struct gendisk *);
void (*unlock_native_capacity) (struct gendisk *);
int (*revalidate_disk) (struct gendisk *);
int (*getgeo)(struct block_device *, struct hd_geometry *);
 /* this callback is with swap_lock and sometimes page table lock
held */
void (*swap_slot_free_notify) (struct block_device *,unsigned long);
struct module *owner;
 };  

塊設備數據讀寫過程:

(1)、請求隊列 request_queue

①、初始化請求隊列

我們首先需要申請並初始化一個 request_queue,然後在初始化 gendisk 的時候將這個request_queue 地址賦值給 gendisk 的 queue 成員變數。使用 blk_init_queue 函數來完成request_queue 的申請與初始化。

request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)

rfn: 請求處理函數指針,每個 request_queue 都要有一個請求處理函數,請求處理函數request_fn_proc

void (request_fn_proc) (struct request_queue *q)  

lock: 自旋鎖指針,需要驅動編寫人員定義一個自旋鎖,然後傳遞進來。,請求隊列會使用這個自旋鎖。

②、刪除請求隊列

當卸載塊設備驅動的時候我們還需要刪除掉前面申請到的 request_queue,刪除請求隊列使用函數 blk_cleanup_queue

void blk_cleanup_queue(struct request_queue *q)  

q: 需要刪除的請求隊列。

③、分配請求隊列並綁定製造請求函數

blk_init_queue 函數完成了請求隊列的申請以及請求處理函數的綁定,這個一般用於像機械硬碟這樣的存儲設備,需要 I/O 調度器來優化數據讀寫過程。但是對於 EMMC、 SD 卡這樣的非機械設備,可以進行完全隨機訪問,所以就不需要複雜的 I/O 調度器了。對於非機械設備我們可以先申請 request_queue,然後將申請到的 request_queue 與“製造請求”函數綁定在一起。

struct request_queue *blk_alloc_queue(gfp_t gfp_mask)

gfp_mask: 記憶體分配掩碼

2、 請求 request

請求隊列(request_queue)裡面包含的就是一系列的請求(request), request 是一個結構體, 需要從 request_queue 中取出一個一個的 request,然後再從每個 request 裡面取出 bio,最後根據 bio 的描述講數據寫入到塊設備,或者從塊設備中讀取數據。

①、 獲取請求

request *blk_peek_request(struct request_queue *q)  

q: 指定 request_queue。 返回值: request_queue 中下一個要處理的請求(request),如果沒有要處理的請求就返回NULL。

②、開啟請求

void blk_start_request(struct request *req)

③、一步到位處理請求

blk_fetch_request 函數來一次性完成請求的獲取和開啟

struct request *blk_fetch_request(struct request_queue *q)
{
struct request *rq;
​
rq = blk_peek_request(q);
if (rq)
blk_start_request(rq);
return rq;
}  

3、 bio 結構

每個 request 裡面會有多個 bio, bio 保存著最終要讀寫的數據、地址等信息。上層應用程式對於塊設備的讀寫會被構造成一個或多個 bio 結構, bio 結構描述了要讀寫的起始扇區、要讀寫的扇區數量、是讀取還是寫入、頁偏移、數據長度等等信息。上層會將 bio 提交給 I/O 調度器,I/O 調度器會將這些 bio 構造成 request 結構,而一個物理存儲設備對應一個 request_queue,request_queue 裡面順序存放著一系列的 request。新產生的 bio 可能被合併到 request_queue 里現有的 request 中,也可能產生新的 request,然後插入到 request_queue 中合適的位置,這一切都是由 I/O 調度器來完成的。

 
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 原文鏈接: JWT詳解:https://blog.csdn.net/weixin_45070175/article/details/118559272 1、什麼是JWT 通俗地說,JWT的本質就是一個字元串,它是將用戶信息保存到一個Json字元串中,然後進行編碼後得到一個JWT token,並且這個 ...
  • Hello,大家好,我是阿粉,對接文檔是每個開發人員不可避免都要寫的,友好的文檔可以大大的提升工作效率。 阿粉最近將項目的文檔基於 Gitbook 和 Gitlab 的 Webhook 功能的在內網部署了一套實時的,使用起來特方便了。跟著阿粉的步驟,教你部署自己的文檔服務。 步驟 安裝 Node 和 ...
  • 序列的修改、散列和切片 from array import array import reprlib, math, numbers from functools import reduce from operator import xor from itertools import chain # ...
  • JZ26 樹的子結構 描述 輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(我們約定空樹不是任意一個樹的子結構) 假如給定A為{8,8,7,9,2,#,#,#,#,4,7},B為{8,9,2},2個樹的結構如下,可以看出B是A的子結構 題解1 深度遍歷 思路 既然是要找到A樹中是否有B樹這樣子樹,如 ...
  • 1、Seata 簡介 1.1 Seata是什麼 Seata 是一款開源的分散式事務解決方案,致力於提供高性能和簡單易用的分散式事務服務。Seata 將為用戶提供了 AT、TCC、SAGA 和 XA 事務模式,為用戶打造一站式的分散式解決方案。AT模式是阿裡首推的模式,阿裡雲上有商用版本的GTS(Gl ...
  • 從藍牙模塊的不同的分類方式上去梳理藍牙模塊的類型,詳細的從分類方式的角度去瞭解藍牙模塊所具備一些特性和功能。 ...
  • 題目:監控記憶體剩餘空間,小於10M則發出信號,給出錯誤代碼,要求調試,如下: #!/bin/bash #mem monitor mem_size=$(free | awk ‘/mem /{print $4}’) if [$mem_size -le 102400] then echo “warning ...
  • 前言 在CAN協議中,CAN匯流排除了眾多優秀的特點外,還具有錯誤監測功能、錯誤通知功能、和錯誤恢復功能、故障封閉功能。下麵系統瞭解以下CAN匯流排上的錯誤幀。 ###錯誤檢測 所有ECU均有可以檢測錯誤的功能。 ###錯誤通知 檢測出錯誤的ECU會立即通知其他ECU ###錯誤恢復 正常發送消息的EC ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...