Chipset: msm8926
OS: Android4.4
Kernel: 3.4.0
相關概念:
塊裝置與字元裝置差別:
- 以塊傳輸,字元裝置以位元組為機關。
- 有對應緩沖區。
- 可以随機通路。可以不按傳輸順序通路,比如通路的是1/10/3/2扇區,可以調整為1/2/3/10扇區。此設計是為了機械類塊裝置如硬碟設計的,對于SD/EMMC可以直接通路。
Struct block_device_operations:
[blkdev.h]
此struct和字元裝置的file_operations類似。
需要關注的有open/release/ioctl/getgeo.
Ioctl: 塊裝置的請求通過此接口。
Getgeo: 根據塊裝置的資訊填充hd_geometry, 裡面包含磁頭,扇區,柱面,俗稱CHS。
Struct gendisk:
[genhd.h]
Major: 主裝置号。
First_minor: 第一個次裝置号。
Minors: 最大支援次裝置号數。
Part_tbl: 分區資訊。
Part0: 磁盤資訊
Fops: 塊裝置操作函數集。
Queue: 請求隊列,使用者請求通過隊列來處理。
Gendisk相關函數:
1. struct gendisk *alloc_disk(int minors)
配置設定struct gendisk,驅動不能自己配置設定,需要調用此接口才行。
Minors表示改磁盤最大能支援多少分區。
2. void add_disk(struct gendisk *disk)
注冊disk,在驅動初始化完成之後調用。
3. void del_gendisk(struct gendisk *disk)
4. static inline void set_capacity(struct gendisk *disk, sector_t size)
設定disk容量,以扇區為機關。塊裝置最小尋址機關是扇區,最常見的是512bytes,還
有其他大小,對于核心,與塊裝置驅動互動的扇區都以512bytes為機關。
許多塊裝置一次能傳輸多個扇區。
Struct request:
[blkdev.h]
用request來表示一個等待I/O的請求。
Queuelist: 構成連結清單。
Q: 指向對應的queue。
__data_len: 要傳送的扇區數。
_sector: 要傳送的下個sector.
Bio: 請求的block io,裡面包含具體的block資訊。
Rq_disk: 對應disk裝置.
Part: 對應磁盤。
Struct request_queue:
[blkdev.h]
此結構主要描述裝置能夠支援的請求類型,扇區大小,對齊要求等參數。
還包含了一個I/O排程器,選使用哪種排程算法來控制目前的I/O請求排列,相鄰扇區合并等過程。不過對于SD/EMMC這類裝置,就不用I/O排程器,直接現來現寫。
相關接口:
-
struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)
[blk-core.c]初始化請求隊列, rfn為對應請求處理函數指針。
-
struct request_queue *blk_alloc_queue(gfp_t gfp_mask)
[blk-core.c] sd/ram等這些随機通路的非機械裝置,不需要複雜I/O排程,應使用此接口
,再調用blk_queue_make_request()将制造函數與隊列綁定,這樣就直接調用制造函數,而且不會調用請求函數了。
可參考如下比較:
Struct bio:
一個bio對應一個I/O請求。此結構包含具體的I/O請求資訊,如扇區索引,傳送大小,讀寫标志等。
Bi_sector: 要傳送的第一個sector。
Bi_rw: 讀還是寫。
Bi_io_vec: 包含對應傳輸的頁,位元組數以及偏移位址。
Struct bio_vec:
Gedisk/request/queue/bio/bio_vec關系圖:
注冊/登出:
int register_blkdev(unsigned int major, const char *name)
此接口可選,以後可能會被移除,它隻完成了兩件事:
1. 配置設定一個主裝置号。
2. 在/proc/devices下建立入口。
不使用請求處理函數:
手機都是對sd/emmc這類随機通路裝置操作,是以使用請求處理函數的方法就不闡述了。
在此模式下需要提供一個“制造函數”,類似于請求處理函數。
[blkdev.h]
雖然q參數還在,實際不包含任何請求。
核心是bio,處理完成之後使用bio_endio()通知處理結束。
[bio.c]
Ramdisk舉例:
Ramdisk是一種模拟磁盤,資料存在ram中,以塊裝置的方式通路,對應裝置檔案一般為/dev/ram%d。
我們來看看上面提到的這些關鍵資料是如何被使用到的。
[brd.c]
brd_init():
559: 調用register_blkdev()注冊塊裝置,主裝置号RAMDISK_MAJOR為1.
563: 配置設定brd,後面會看下它裡面做了什麼。
572: 在初始化完成之後将disk添加進去。
執行完register_blkdev()之後在/proc/devices下能看到:
執行完add_disk()之後能在/dev/block下看到ramx節點,總共有16個。
Note: /dev/下的節點和是udev監測sysfs裡的裝置而建立的。
/dev/block對應sysfs的建立是:
[genhd.c]
而ramx節點的建立對應的sysfs 執行code是:
[brd.c]
[genhd.c]
brd_alloc():
473: 配置設定request queue,且表示不是用I/O排程器。是以這裡沒使用請求處理函數的方法。
476: 對應的“制造函數”是brd_make_request().
483: 配置設定disk.
488: 表明對應的fops是brd_fops.
493: 設定disk的capacity.
brd_make_request():
344: 本次傳輸是讀還是寫。
349: 讀或者寫資料。
356: 結束讀寫。
314/318: 讀寫分别隻是将資料copy到brd或者從brd的sector copy出來。
brd_fops:
399~403: 如果有被打開了,就将device相關的buffer/cache清理掉。
Kris.Fei
2014/09/09