天天看點

[筆記分享] [SD] 塊裝置驅動學習小結

Chipset: msm8926

OS: Android4.4

Kernel: 3.4.0

相關概念:

塊裝置與字元裝置差別:

  1. 以塊傳輸,字元裝置以位元組為機關。
  2. 有對應緩沖區。
  3. 可以随機通路。可以不按傳輸順序通路,比如通路的是1/10/3/2扇區,可以調整為1/2/3/10扇區。此設計是為了機械類塊裝置如硬碟設計的,對于SD/EMMC可以直接通路。

Struct block_device_operations:

[blkdev.h]

[筆記分享] [SD] 塊裝置驅動學習小結

此struct和字元裝置的file_operations類似。

需要關注的有open/release/ioctl/getgeo.

Ioctl: 塊裝置的請求通過此接口。

Getgeo: 根據塊裝置的資訊填充hd_geometry, 裡面包含磁頭,扇區,柱面,俗稱CHS。

Struct gendisk:

[genhd.h]

[筆記分享] [SD] 塊裝置驅動學習小結

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]

[筆記分享] [SD] 塊裝置驅動學習小結
[筆記分享] [SD] 塊裝置驅動學習小結

用request來表示一個等待I/O的請求。

Queuelist: 構成連結清單。

Q: 指向對應的queue。

__data_len: 要傳送的扇區數。

_sector: 要傳送的下個sector.

Bio: 請求的block io,裡面包含具體的block資訊。

Rq_disk: 對應disk裝置.

Part: 對應磁盤。

Struct request_queue:

[blkdev.h]

[筆記分享] [SD] 塊裝置驅動學習小結
[筆記分享] [SD] 塊裝置驅動學習小結
[筆記分享] [SD] 塊裝置驅動學習小結

此結構主要描述裝置能夠支援的請求類型,扇區大小,對齊要求等參數。

還包含了一個I/O排程器,選使用哪種排程算法來控制目前的I/O請求排列,相鄰扇區合并等過程。不過對于SD/EMMC這類裝置,就不用I/O排程器,直接現來現寫。

相關接口:

  1. struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)

    [blk-core.c]初始化請求隊列, rfn為對應請求處理函數指針。

  2. struct request_queue *blk_alloc_queue(gfp_t gfp_mask)

    [blk-core.c] sd/ram等這些随機通路的非機械裝置,不需要複雜I/O排程,應使用此接口

    ,再調用blk_queue_make_request()将制造函數與隊列綁定,這樣就直接調用制造函數,而且不會調用請求函數了。

    可參考如下比較:

    [筆記分享] [SD] 塊裝置驅動學習小結

Struct bio:

[筆記分享] [SD] 塊裝置驅動學習小結

一個bio對應一個I/O請求。此結構包含具體的I/O請求資訊,如扇區索引,傳送大小,讀寫标志等。

Bi_sector: 要傳送的第一個sector。

Bi_rw: 讀還是寫。

Bi_io_vec: 包含對應傳輸的頁,位元組數以及偏移位址。

Struct bio_vec:

[筆記分享] [SD] 塊裝置驅動學習小結

Gedisk/request/queue/bio/bio_vec關系圖:

[筆記分享] [SD] 塊裝置驅動學習小結

注冊/登出:

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

此接口可選,以後可能會被移除,它隻完成了兩件事:

1. 配置設定一個主裝置号。

2. 在/proc/devices下建立入口。

不使用請求處理函數:

手機都是對sd/emmc這類随機通路裝置操作,是以使用請求處理函數的方法就不闡述了。

在此模式下需要提供一個“制造函數”,類似于請求處理函數。

[blkdev.h]

[筆記分享] [SD] 塊裝置驅動學習小結

雖然q參數還在,實際不包含任何請求。

核心是bio,處理完成之後使用bio_endio()通知處理結束。

[bio.c]

[筆記分享] [SD] 塊裝置驅動學習小結

Ramdisk舉例:

Ramdisk是一種模拟磁盤,資料存在ram中,以塊裝置的方式通路,對應裝置檔案一般為/dev/ram%d。

我們來看看上面提到的這些關鍵資料是如何被使用到的。

[brd.c]

brd_init():

[筆記分享] [SD] 塊裝置驅動學習小結

559: 調用register_blkdev()注冊塊裝置,主裝置号RAMDISK_MAJOR為1.

563: 配置設定brd,後面會看下它裡面做了什麼。

572: 在初始化完成之後将disk添加進去。

執行完register_blkdev()之後在/proc/devices下能看到:

[筆記分享] [SD] 塊裝置驅動學習小結

執行完add_disk()之後能在/dev/block下看到ramx節點,總共有16個。

[筆記分享] [SD] 塊裝置驅動學習小結
[筆記分享] [SD] 塊裝置驅動學習小結
Note: /dev/下的節點和是udev監測sysfs裡的裝置而建立的。

/dev/block對應sysfs的建立是:

[genhd.c]

[筆記分享] [SD] 塊裝置驅動學習小結

而ramx節點的建立對應的sysfs 執行code是:

[brd.c]

[筆記分享] [SD] 塊裝置驅動學習小結

[genhd.c]

[筆記分享] [SD] 塊裝置驅動學習小結

brd_alloc():

[筆記分享] [SD] 塊裝置驅動學習小結

473: 配置設定request queue,且表示不是用I/O排程器。是以這裡沒使用請求處理函數的方法。

476: 對應的“制造函數”是brd_make_request().

483: 配置設定disk.

488: 表明對應的fops是brd_fops.

493: 設定disk的capacity.

brd_make_request():

[筆記分享] [SD] 塊裝置驅動學習小結

344: 本次傳輸是讀還是寫。

349: 讀或者寫資料。

356: 結束讀寫。

[筆記分享] [SD] 塊裝置驅動學習小結

314/318: 讀寫分别隻是将資料copy到brd或者從brd的sector copy出來。

[筆記分享] [SD] 塊裝置驅動學習小結

brd_fops:

[筆記分享] [SD] 塊裝置驅動學習小結
[筆記分享] [SD] 塊裝置驅動學習小結

399~403: 如果有被打開了,就将device相關的buffer/cache清理掉。

Kris.Fei
                                                    2014/09/09