1. 程式人生 > >iSCSI 中 SCSI 讀寫請求處理分析

iSCSI 中 SCSI 讀寫請求處理分析

 iSCSI Initiator 是通過 SCSI Command PDU 向 Target 發出 SCSI 請求,Target 接收請求,執行 SCSI 命令,然後返回資料以及 SCSI 狀態。在 SCSI 任務執行時,Initiator/Target 之間會涉及大量資料 I/O。RFC3720 中對這些 I/O 的組織有特別的規定,以下結合 RFC3720, 分析一下 iSCSI 中對 SCSI 請求的具體實現。

    SCSI Read 比較簡單,就先說說 SCSI Read 吧。Initiator 發出 SCSI Read 請求以後,Target 從裝置中讀取出資料,然後通過 DataIn 資料包返回給 Initiator。如果資料長度太長,就要分成多個 DataIn 資料包。至於每個 DataIn 資料包最大資料段長度為多少由 Login 時 Initiator 給出的 MaxRecvDataSegmentLength 值控制,不能超過該值。另外, 這些 DataIn 是否按順序傳送同則由 DataSequenceInOrder 以及 DataPDUInOrder 控制。具體請參閱《iscsi幾個關鍵字協商與實現》一文。資料包互動流程大致如下:
  SCSI Read (128)   --------> 
                                  <--------     DataIn(flags=0, data_sn=0, data_offset=0)
                                  <--------     DataIn(flags=0, data_sn=1, data_offset=8192)
                                  <--------     DataIn(flags=0, data_sn=2, data_offset=16384)
                                  <--------     DataIn(flags=0x81, data_sn=3, data_offset=32768)
                                                  # 結束包帶F標記以及Status

作為 Target 端來說,似乎想不出有什麼理由不按順序傳送 DataIn,但有一種情況就是 MC/s 時,有可能從各個 Connection 中分發 DataIn(這樣可提高率能),如果各個鏈路走的路徑不一樣,那麼到達 Initiator 端的 DataIn 包就有可能為非順序的了。別外,在協議相容性測試時,為了增加測試覆蓋率,也會想盡辦法產生這樣的 Case。當然最簡單的處理方式為 Target 端直接協商時就直接宣告按順序收發 DataIn,如果是這種情況,我想每一個 SCSI 任務,只能由一個 Connect 上進行收到資料包了,否則沒有辦法保證 DataIn 的順序性(至少理論上沒法保證吧)。

   SCSI Write 實現與 SCSI Read 稍有不同,主要是受幾個協商關鍵字的影響。一般 SCSI Write 過程為:首先發 SCSI 寫指令,Target 端收到請求後會分配置相應緩衝區進行接收,然後返回 R2T 包要求 Initiator 先發這個範 圍的資料,R2T 包中指定了Initiator 要傳送的資料範圍。Initiator 就是根據 R2T 劃定的範圍依次發出這個範圍的資料。如果整個資料沒有完全接收完,會再發出一下個 R2T 要求 Initiator 繼續發資料,重複上面過程直到接收全部資料,最後返回 SCSI Response 告訴 Initiator 任務執行完成。Initiator 資料是通過 DataOut 形式進行發出的,當然 DataOut 順序與 DataIn 一樣,受協商關鍵字影響。由於這些DataOut 中的資料是由 R2T 指定範圍,也就是說應答 R2T 的這些 DataOut 資料包屬於請求類資料 (solicated),根據 R2T 的請求來發送。當然還有一些屬於非請求數(Unsolicated),也就是說在沒有 R2T 請求之前就已經發出去,也就是說從 SCSI Write 到第一個 R2T 之間,Initiator 所發了的資料都稱為非請求資料(包括立即資料以及最開始幾個 DataOut 資料),非請求類資料位於整個資料的最前面。這段資料的長度由 FirstBurstLength 控制,另外,是否允許這些非請求類資料由 InitialR2T,以及ImmediateData 所控制。R2T 中的請求範圍值也是控制的,主要受 MaxBurstLength 值所限制。可以這樣去理解,ImmediateData 是立即資料開關,InitiR2T 是非請求DataOut 開關。比如:


1.ImmediateData=Yes, InitialR2T=Yes,這時只允許立即資料,不允許非請求類DataOut:
  SCSI_Write    ------------>
                   ImmediateData
                           <-------------      R2T0(請求範圍<=MaxBurstLength)
  DataOut0     ------------->     # 單PDU資料段長度<= MaxRecvDataSegmentLength
  DataOut1      ------------->
  DataOutn      -------------> # DataOut(0,1,2..n)總長<= MaxBurstLength
                           <-------------  R2T1(請求範圍<=MaxBurstLength)
  DataOut0      ------------->
  DataOut1      ------------->
  DataOutn      -------------> 
                           <-------------  SCSI_Response

2.ImmediateData=Yes, InitialR2T=No,這時即允許立即資料,也允許非請求類DataOut:
  SCSI_Write ------------>
                   ImmediateData
  DataOut0  -------------> # 單PDU資料段長度<= MaxRecvDataSegmentLength
  DataOut1  ------------->
  DataOutn  -------------> # ImmediateData + 幾個DataOut總長 <= FirstBurstLength
                       <-------------  R2T0(請求範圍<=MaxBurstLength)
  DataOut0  -------------> # 單PDU資料段長度<= MaxRecvDataSegmentLength
  DataOut1  ------------->
  DataOutn  -------------> # DataOut(0,1,2..n)總長<= MaxBurstLength
                        <-------------  R2T1(請求範圍<=MaxBurstLength)
  DataOut0  ------------->
  DataOut1  ------------->
  DataOutn  -------------> 
                       <-------------  SCSI_Response


3.ImmediateData=No, InitialR2T=Yes,這時不允許立即資料,也不允許非請求類DataOut:
  SCSI_Write------------>
                       <-------------  R2T0(請求範圍<=MaxBurstLength)
  DataOut0  -------------> # 單PDU資料段長度<= MaxRecvDataSegmentLength
  DataOut1  ------------->
  DataOutn  -------------> # DataOut(0,1,2..n)總長<= MaxBurstLength
                       <-------------  R2T1(請求範圍<=MaxBurstLength)
  DataOut0  ------------->
  DataOut1  ------------->
  DataOutn  -------------> 
                       <-------------  SCSI_Response


4.ImmediateData=No, InitialR2T=No,這時不允許立即資料,允許非請求類DataOut:
  SCSI_Write------------>
  DataOut0  -------------> # 單PDU資料段長度<= MaxRecvDataSegmentLength
  DataOut1  ------------->
  DataOutn  -------------> # ImmediateData + 幾個DataOut總長 <= FirstBurstLength
                       <-------------  R2T0(請求範圍<=MaxBurstLength)
  DataOut0  -------------> # 單PDU資料段長度<= MaxRecvDataSegmentLength
  DataOut1  ------------->
  DataOutn  -------------> # DataOut(0,1,2..n)總長<= MaxBurstLength
                       <-------------  R2T1(請求範圍<=MaxBurstLength)
  DataOut0  ------------->
  DataOut1  ------------->
  DataOutn  -------------> 

                       <-------------  SCSI_Response

相關推薦

iSCSI SCSI 請求處理分析

 iSCSI Initiator 是通過 SCSI Command PDU 向 Target 發出 SCSI 請求,Target 接收請求,執行 SCSI 命令,然後返回資料以及 SCSI 狀態。在 SCSI 任務執行時,Initiator/Target 之間會涉及大量資料

資料庫持久化效能原理分析---基於儲存引擎和索引原理

1.儲存引擎的型別 型別 功能 應用 hash 增刪改、隨機讀、順序掃描 Key-Value儲存系統  redis、memcached B-Tree 增刪改、隨機讀、順序掃描 關係型資料庫,MongoDB採用了B-Tree+lock-free, LSM

《Java併發程式設計的藝術》-Java併發包鎖及其實現分析

1. 前言 在Java併發包中常用的鎖(如:ReentrantLock),基本上都是排他鎖,這些鎖在同一時刻只允許一個執行緒進行訪問,而讀寫鎖在同一時刻可以允許多個讀執行緒訪問,但是在寫執行緒訪問時,所有的讀執行緒和其他寫執行緒均被阻塞。讀寫鎖維護了一對鎖,一個讀鎖和一個寫鎖,通過分離讀鎖和

Glusterfs下請求處理流程

Glusterfs基於核心的fuse模組,fuse模組除了建立fuse檔案系統外,還提供了一個字元裝置(/dev/fuse),通過這個字元裝置,Glusterfs可以讀取請求,併發送響應,並且可以傳送notify訊息。 下面是在Glusterfs下的一個讀/寫請求的完整流程

22、Java並發性和多線程-Java/

權限 原理 目的 str sco readers 閱讀 操作 wait 以下內容轉自http://ifeve.com/read-write-locks/: 相比Java中的鎖(Locks in Java)裏Lock實現,讀寫鎖更復雜一些。假設你的程序中涉及到對一些共享資源

Qt快速Excel方法封裝

import mon works body oid ati ebo set 區域 #include "RwExcel.h"/*快速讀寫的機制是實現獲取有效區域只調用一次dynamicCall("Value");或setProperty("Value", var);即可, *

redis 突然大量逐出導致請求block

服務 long 字節 tno 過程 aof 測試的 pull 文件 現象 redis作為緩存場景使用,內存耗盡時,突然出現大量的逐出,在這個逐出的過程中阻塞正常的讀寫請求,導致 redis 短時間不可用; 背景 redis 中的LRU是如何實現的? 當mem_used內存

pysparkdataframe資料庫

本文只討論spark藉助jdbc讀寫mysql資料庫 一,jdbc 想要spark能夠從mysql中獲取資料,我們首先需要一個連線mysql的jar包,mysql-connector-java-5.1.40-bin.jar 將jar包放入虛擬機器中合適的位置,比如我放置在/home/sx

改進的中科院分詞系統NLPIR程式碼(加入使用者詞典,去停用詞,檔案)+情感分析字典包+工具包+論文包

NLPIR分詞,加入使用者詞典,去停用詞,檔案讀寫等 原始碼下載地址 優化的分詞系統程式碼 原始碼下載地址 NLPIR分詞系統 優化的分詞系統程式碼 以下是核心程式碼 完整程式碼可以直接執行分詞,點我跳轉 public cl

STM32f429開發USB檔案涉及到的庫移植

第一步  USB_HID移植(原創http://blog.csdn.net/xbl1986/article/details/17577685#comments) ├── STM32_USB_Device_Library        

emmc速度效能分析

環境:linux (aarch64 cpu) 分析: 1)linux系統的啟動,從bootloader到linux kernel startup,最後掛載rootfs。整個過程的啟動速度,除去軟體驅動因素,若是emmc boot,硬體因素為emmc的讀寫速度+cache效能 2)分清

python檔案

讀寫檔案是最常見的IO操作。Python內建了讀寫檔案的函式,用法和C是相容的。 讀寫檔案前,我們先必須瞭解一下,在磁碟上讀寫檔案的功能都是由作業系統提供的,現代作業系統不允許普通的程式直接操作磁碟,所以,讀寫檔案就是請求作業系統開啟一個檔案物件(通常稱為檔案描述符),然後,通過作業系統提供的介面從

javaFile類和IO輸入輸出流隨機類RandomAccessFile類的講解

今天來複習一下IO流的api, 在java中用io流來進行檔案的輸出和輸出操作,那麼首先類講解一下什麼是輸入和輸出: 所有往記憶體中送資料都是輸入 所有從記憶體出資料都是輸出 能用java.io包中的api操作的輸入輸出: 記憶體–>外存(硬碟,光碟,U盤) 本地流輸出

多執行緒學習筆記五之鎖實現分析

目錄 簡介 讀寫狀態 讀鎖計數器 共享鎖的獲取 tryAcquireShared(int unused) doAcquireShared(int arg) 共享鎖的釋放 tryReleaseShared(int unus

C#GDALshp圖層

採用GDAL17的C#庫進行shp圖層屬性表讀取和修改操作,C#DLL庫解壓後包含檔案如下:   新增引用主要是帶csharp的gdal、ogr、osr三個DLL,程式程式碼如下: using OSGeo.OGR; using OSGeo.OSR; using OS

MongoDB

原文地址 1. MongoDB 使用的鎖 MongoDB 使用的是“readers-writer”鎖, 可以支援併發但有很大的侷限性 當一個讀鎖存在,許多讀操作可以使用這把鎖,然而, 當一個寫鎖的存在,一個單一的寫操作會”exclusively“持有該鎖,同一時間其它寫操作

PCIe學習筆記(11)--- 配置空間的請求

1. 有兩種型別的讀寫請求 分別是TYPE 0與1 2 TYPE 0的REQUEST HEADER中 TYPE FIELD = 00100 TYPE 1的REQUEST HEADER中 TYPE FIELD = 00101 3. 讀與寫的區別在於: REQUEST

可重入鎖原理分析

前段時間看了一系列併發程式設計部落格,感覺寫的不錯。這裡記錄一下其中可重入讀寫鎖的自己實現方法,雖然java中都有封裝好的讀寫鎖可用,但分析一下程式碼有助於理解鎖機制的原理。 部落格原地址 package cn.wcl.readWriteLock;

在python如何txt文字文件

    1、tell()函式 返回當前檔案中游標的位置       獲取游標的位置       number = file_handle.tell() 2、seek()函式       第一個引數 offset 直接指定檔案的游標位置,調整游標位置 offset:偏移量      第二個引數 w

c語言格式化函式fscanf()和fprintf()

fscanf():從指定檔案中按指定格式讀入資料,並賦值給相應的變數 格式: fscanf(檔案指標,格式字串,輸出列表) e.g. fscanf(fp,"%d",&i) fscanf(fp,"%d %d",&