iscsi是什么,iscsi:IO操作流程(一)

 2023-10-05 阅读 16 评论 0

摘要:從應用的視角,iscsi展現為一個塊設備,即一塊硬盤。在Linux操作系統中可以通過fdisk -l看到這塊磁盤。iscsi協議所涉及的一系列的組件經過層層虛擬化,在多個層次上其操作與本地硬盤無異。這實際上是一個性能、可靠性、實現多個角度權衡的結果。事實上

從應用的視角,iscsi展現為一個塊設備,即一塊硬盤。在Linux操作系統中可以通過fdisk -l看到這塊磁盤。iscsi協議所涉及的一系列的組件經過層層虛擬化,在多個層次上其操作與本地硬盤無異。這實際上是一個性能、可靠性、實現多個角度權衡的結果。事實上,在所經歷的各層次中,有一些次層對于iscsi磁盤來說是多余的,但操作系統的設計者為了共用SCSI實現層,將scsi initiator對接到SCSI中間層以下,作為一個scsi傳輸層實現。因此,自scsi層以上,iscsi提供的塊設備與sas、SATA提供的塊設備所經歷的IO流轉一致。

本文所涉及的iscsi集中考慮iscsi協議承接塊設備應用說起。事實上,iscsi作為一個承載SCSI協議的傳輸層,除能夠支持基于磁盤價值的塊設備外,還可以支持其他的SCSI設備。比如磁 帶、CDROM。業界也有通過iscsi實現為磁帶的應用,如VTL。虛擬為其他設備時,其IO流轉略有區別。scsi子系統通過INQUIRY探測LUN的設備類型,進而由上層驅動“認領”對應的設備。

IO層次結構

iscsi是什么、用戶的數據在initiator節點上依次經過文件系統層、塊設備層、SCSI層。理論上我們也可以將通過裸scsi設備直接發送IO相關SCSI指令到SCSI中間層,但這條路徑的初衷并非如此,沒有針對IO處理進行優化。故只在上圖中表示出來,并不做具體分析。
文件系統、裸設備在應用角度,其一般流程均為:
- 打開文件,獲得句柄(系統調用open
- 一次或多次以字節為單位對文件進行讀寫(系統調用readwrite
- 關閉文件(系統調用close)

應用的IO請求通過系統調用到達內存。在適合當的時機,操作系統會將上述操作構建為bio結構,調用submit_bio將請求傳遞到通用塊層。bio是通用塊核心的IO處理單元。bio核心表達的是數據在內存和在磁盤中的映射關系。其中,
緩存中的地址以內存頁號和頁面偏移表示。以struct bio_vec表達:

struct bio_vec {struct page    *bv_page;   /*存儲數據的頁面*/unsigned int    bv_len;     /*數據長度*/unsigned int    bv_offset; /*數據在頁面中的偏移*/
};

在磁盤上的地址以bvec_iter表達:

struct bvec_iter {sector_t            bi_sector;    /* device address in 512 byte sectors */unsigned int     bi_size;    /* residual I/O count */unsigned int     bi_idx;        /* current index into bvl_vec */unsigned int     bi_done;    /* number of bytes completed */unsigned int     bi_bvec_done;    /* number of bytes completed in current bvec */
};

在新的內核版本中,對bio數據結構進行了一些調整。老的版本中扇區號、扇區數等信息直接放在bio成員中。新的版本中將其集中放到bev_iter中。此變化不影響bio在設計中的位置

iscsi發起程序,submit_bio最終調用generic_make_request函數將bio插入到請求隊列。generic_make_request接收一個bio組成的鏈表,并對其進行分個處理。對于每個bio首先進行一系列應用的檢查,然后調用具體塊磁盤驅動的make_request_fn進行處理。scsi磁盤驅動初始化的過程中,將make_request_fn直接指定為blk_queue_bio。這個函數根據內核配置的IO電梯算法,將IO拆分合并到請求隊列中。
上述的故事就是大家耳熟能祥的IO緩存與IO調度。在此不詳細描述。可以參考其他資料研究buffer cache以及電梯調度算法相關的算法。轉到iscsi實現的角度。initiator的處理過程并不需要電梯算法。畢竟到目前為止,我們數據離落盤還有很遠很遠。況且系統數據落盤是在target端進行,在initiator端進行電梯算法意義不大,target端有可能對數據進行重新散列,當下排序也用的LBA還需要經過再次映射,邏輯上相鄰不代表物理是想鄰。
還是那句話,在iscsi流程過程中,之所以將這些流程納入,完全是一種設計的權衡、抽象的哲學問題。
我們的故事剛剛開始。
自sd設備驅動開始,便進入SCSI處理的流程。也即iscsi相關語境的上下文。從此刻,系統要回答的問題有以下幾方面:
1. IO如何封裝成scsi指令,封裝成什么樣的scsi指令
2. IO如何根據設備的特點構建任務,經過協議所定義的host、taget、lun等相應的處理
3. IO處理過程中的異常采用什么方式,以什么形式報告給initiator等

sd實現了一個塊設備(drivers/scsi/sd.c)用以接受IO請求,并最終調用scsi_setup_fs_cmnd將請求向scsi_cmd轉換,進而分發到scsi中間層進行處理。scsi中間層可以理解為SCSI處理的一個框架實現,提供了SCSI系統初始化、設備掃描、SCSI命令調度執行以及錯誤恢復框架等。從IO角度,SCSI中間層主要是接受IO相關的SCSI指令,進一步完善相應用的信息,調用scsi_dispatch_cmd傳遞到下層進行處理。
最終的scsi指令的執行是在target端進行。scsi transport層是負責SCSI指令傳輸的,像SAS、FC、iscsi等都是傳輸層的具體實現。傳輸層有對應的協議實現,其核心實現思路是scsi請求進行的封裝。上述的SCSI命令只是scsi請求的一個方面,除此之外還有目的LUN、任務管理、數據等信息,具體信息可參考SAM相關文檔。一個SCSI的具體執行可以形式性的表達為:

Service Response =Execute Command (IN ( I_T_L_Q Nexus, CDB, Task Attribute, [Data-In Buffer Size],
[Data-Out Buffer], [Data-Out Buffer Size], [Command Reference Number], [Task
Priority]), OUT ( [Data-In Buffer], [Sense Data], [Sense Data Length], Status ))

一個SCSI指令相關的請求在傳輸層被稱為一個task(任務),當SCSI命令被發送到scsi傳輸協議服務系統時,任務被建立。任務用于管理SCSI在傳輸層流轉的一系列狀態信息。當SCSI target返回響應之后task重命周期完成。一個傳輸任務可分為一個或者多個數據包傳輸給target。在iscsi協議中用PDU表示每個數據包。iscsi協議是scsi傳輸層的具體實現,它實現的了initiator與target間的認證、會話建立、數據聯接管理、數據傳輸、任務控制、數據安全等一系列的服務。iscsi采用PDU描述傳輸數據包,是iscsi層各節點間交互的基本單位,iscsi協議是scsi傳輸層的具體實現。iscsi PDU將使TCP協議或者其它流式協議進行傳輸。在Linux系統中實現了iscsi_tcpiscsi_iser兩個傳輸模塊。

以上就是Linux內核中iscsi協議initiator端實現的具體流程,流轉過程中,一個IO請求自上而下經歷了biorequestscsi_cmdiscsi_task以及iscsi hdr(PDU)等變化。

iscsi發起程序連接不上、思考:
本文提到為了系統實現概念的統一性、設計的一致性以及層次抽象與共用,操作系統將iscsi協議對接到scsi中間層。這種實現對性能的損失有多大?如果我們在device-mapper之下實現又會怎么樣?歡迎討論。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/114750.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息