scsi命令的第二次轉變

2021-05-24 05:37:22 字數 3599 閱讀 6490

一旦這種關係建立好了以後,就可以開始執行請求了。來看

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 ...