一旦這種關係建立好了以後,就可以開始執行請求了。來看
blk_execute_rq()
,來自block/ll_rw_blk.c
:2616 int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk,
2617struct request *rq, int at_head)
2618
2634
2635rq->end_io_data = &wait;
2636
blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq);
2637
wait_for_completion(&wait);
2638
2639if (rq->errors)
2640 err = -eio;
2641
2642return err;
2643 }
拋去那些用於錯誤處理的**,這個函式真正有意義的**就是兩行,
blk_execute_rq_nowait
和wait_for_completion
。先看前者,來自
block/ll_rw_blk.c
:2588 void blk_execute_rq_nowait(request_queue_t *q, struct gendisk *bd_disk,
2589struct request *rq, int at_head,
2590rq_end_io_fn *done)
2591
首先at_head
是表示往哪插。
而where
用來記錄
at_head
的值。在我們這個上下文中,
at_head
是從scsi_execute()
中呼叫blk_execute_rq
的時候傳遞下來的,當時我們設定的是
1。於是
where
被設定為
elevator_insert_front。回到
blk_execute_rq_nowait()
中,下乙個被呼叫的函式是
__generic_unplug_device
,依然是來自
block/ll_rw_blk.c
:1589 void __generic_unplug_device(request_queue_t *q)
1590
其實最有看點的就是
1597
行呼叫這個
request_fn
,struct request_queue
中的乙個成員
request_fn_proc *request_fn
,而至於
request_fn_proc
,其實又是
typedef
的小伎倆,來自
include/linux/blkdev.h
:334 typedef void (request_fn_proc) (request_queue_t *q);
那麼這個
request_fn
是多少呢
?還記得當初那個
scsi
子系統中申請佇列的函式了麼?沒錯
,就是__scsi_alloc_queue()
,設定成的
scsi_request_fn
函式。這個函式呼叫
elv_next_request
跟我們前面看到的一樣,只不過在執行
scsi_prep_fn
的時候,由於
request
的標識已經不是
按正路,我們會走到
1229
行這個switch
語句,並且會根據
scsi
命令的型別而執行不同的函式:
scsi_setup_blk_pc_cmnd
或者scsi_setup_fs_cmnd
。那麼我們
cmd_type
究竟是什麼呢?跟前面不同了,前面是
req_cmd
,而我們這次是在
scsi_execute()
中有這麼一行:
199req->cmd_type = req_block_pc;
所以,沒什麼好說的,我們會執行
scsi_setup_blk_pc_cmnd
,來自drivers/scsi/scsi_lib.c
:1090 static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
1091 else
1121
1122build_bug_on(sizeof(req->cmd) > sizeof(cmd->cmnd));
1123memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
1124cmd->cmd_len = req->cmd_len;
1125if (!req->data_len)
1126cmd->sc_data_direction = dma_none;
1127else if (rq_data_dir(req) == write)
1128cmd->sc_data_direction = dma_to_device;
1129else
1130cmd->sc_data_direction = dma_from_device;
1131
1132cmd->transfersize = req->data_len;
1133cmd->allowed = req->retries;
1134cmd->timeout_per_command = req->timeout;
1135cmd->done = scsi_blk_pc_done;
1136return blkprep_ok;
1137 }
如果曾經的你還對
scsi cmd
是如何形成的頗有疑義的話,那麼相信此刻,你應該會明白了吧,尤其是當你在
usb-storage
那個故事中看到對它
sc_data_direction
的判斷的時候,你不理解這個值是如何設定的,那麼此刻,這**活生生的展現在你面前,想必已經揭開了你心中那謎團吧。
最終,正常的話,函式返回
blkprep_ok
。prep
表示prepare
的意思,用我們的母語說就是準備的意思,最後
blkprep_ok
就說明準備好了,或者說準備就緒。而
scsi_prep_fn()
也將返回這個值,返回之前還設定了
cmd_flags
中的req_dontprep。(
注意elv_next_request()
函式741
行判斷的就是設這個
flag。)
後面的工作就和前面「
scsi
塊裝置驅動層處理」的內容一樣了。
第二次作業
execise02 1.查詢85年以後出生的學生姓名 性別和出生日期 2.列表顯示所有可能的學生選課組合 學號 課程號 3.查詢1 2 4班中陳姓同學的資訊 4.查詢所有及格的學生姓名 所選課程名及所得分數 5.統計各門課程的及格人數 課程編號 課程名 及格人數 6.統計各門課程的總人數 及格人數和...
第二次約會
第一次看來我沒把人家姑娘嚇壞,一周後的乙個星期一晚上,我迎來了和t第二次見面機會,那天我發了一條簡訊給t,今天晚上我們去外灘逛逛吧 t快下班的時候給我打了個 當時t和她的小朋友們都還在教室裡,t很爽快的答應我的邀請,並且叫他們班所有的 學生異口同聲在 的那端大聲叫 叔叔好!當時差點沒把我耳朵震聾,呵...
第二次作業
第一題 p1 1 遞迴寫法,效率低 include 1.寫乙個函式返回引數值為1的個數 比如 15 0000 1111 4個1 程式原型 int count one bits unsigned int value int fuc int x else return 0 void mainp1 p1 ...