上次看sys_read()看得太亂了,主次不分,於是重新看了遍,對流程有了個大致的瞭解:
read()系統調用所涉及的內核組件如上圖所示,依次爲vsf層、磁盤高速緩存、映射層、通用塊設備層、I/O調度層、磁盤設備驅動。 作用大致如下: vfs層決定如何執行read操作,將filp->f_op->read指向具體的函數; 內核映射層確定數據的物理位置,主要執行兩步:1、確定數請求數據所在的塊號;2調用具體的文件系統的函數,訪問磁盤索引節點,根據邏輯塊號來確定請求數 據在磁盤上的位置; 通用塊層將上層的請求構造成bio結構,再將bio結構提交個I/O調度層; I/O調度層主要的工作則將上層的bio構造成request結構,將其加入到對應的request_queue中,並完成合並和排序的工作; 塊設備從request中取得請求,然後再完成這些請求。
vfs層
映射層
filp->f_op->read和filp->f_op->aio_read指向具體的文件系統的指針,在 ext2文件系統中這兩者分別對應generic_file_read()和generic_file_aio_read(),而 generic_file_read()和generic_file_aio_read()都將調用 __generic_file_aio_read()。
(注:大多數磁盤文件系統的read方法是由generic_file_read()通用函數實現,而 __generic_file_aio_read()函數是所有文件系統實現同步和異步讀操作所使用的通用例程。此外,對於大多數問價系統來說,從文件中 讀取一個數據頁就等同於在磁盤上查找所請求的數據存放在哪些塊上。只要這個過程完成了,內核就可以通過向通用塊層提交適當的I/O操作來填充這些頁)
通用塊設備層
I/O調度層
接下來說明q->make_request的賦值:
在塊設備驅動程序中(如sbull中),會調用blk_init_queue()來分配並初始化一個request隊列,"prepare a request queue for use with a block device";
blk_init_queue()函數調用函數blk_init_queue_node(),blk_init_queue_node() 的主要工作就是對request隊列進行初始化,在這裏我只關注兩個函數request_fn()和make_request_fn(),前者會被賦值爲 blk_init_queue()的第一個參數,而make_request_fn()則會由blk_queue_make_request()設置爲 __make_request()。
__make_request()函數會完成合並、排序等操作。
塊設備驅動層
request弄好了之後,使用了blk_init_queue()塊設備驅動程序就會通過request_fn()來處理器請求了。
在sbull中使用了兩種模式:RM_SIMPLE、RM_FULL。