NVMe接口學習筆記4 其餘數據結構

2021-02-14 SSD存儲知識匯總和分享

NVMe接口學習筆記1 基本概念

NVMe接口學習筆記2 寄存器

NVMe接口學習筆記3 隊列和PRP/SGL

上回目學習了Command的隊列和其中entry的數據結構,以及怎樣填寫entry和它所對應buffer的位置描述,這篇文章則繼續完成NVMe spec當中數據結構章節的其他內容。

大致回憶一下隊列,隊列通過發送方更新tail指針指向的空描述符,填寫command的ID和對應位置,最後更新該隊列對應的doorbell寄存器,通知接收方有新的entry發送過來。接收方則通過head指針或者Phase tag取得接收到的entry,從而確定哪些是未處理的entry,哪些是已經處理的。

傳輸數據是通過16bytes的地址描述空間來描述數據的位置的,有兩種常用的數據空間描述方法,PRP和SGL,PRP要求所有的數據空間按照最小一個physical page的大小進行定義,在page內數據連續,在結尾處如果有更多數據需要傳輸,則通過指針形式指向下一個page。SGL則更加靈活,每段描述空間不需要指定長度,但是需要更多的描述段類型來判斷數據存放的位置。

一,Metadata Region

這個Metadata可以被定義為每個logical block(LBA 一般512B或者4KiB)所附帶的一個區域,以512bytes的Logical block為例,可以將8B的metadata放在這512B的數據之後,組成一個520B的數據塊一起傳輸,也可分兩次傳輸,放在獨立的metadata buffer裡,但是metadata不能被分割到Logical block和metadata buffer兩個不同的區域。舉個慄子,Logical block是512B,Metadata是8B,分配給Logical block的空間是516B,分4B給Meta data空間。放在一起還是520B,這樣是不允許的。

當我們把namespace定義成metadata和logical block分開存放的格式的時候,我們就使用了Metadata Region,Command的描述符內將定義Metadata Pointer來指向Metadata真正的位置。這個指針必須是32位對齊的地址。

一個NVMe Controller一般支持多種格式的metadata,由於該數據最終會被保存到NAND上,並且會做ECC校驗和加密動作,所以不同的size的metadata最終會呈現出略微不同的performance,這個現象的主要原因還是硬體操作的速率問題,一般對齊的數據會更快,而增加或者減少8-16B會導致ECC和加解密效率下降。所以對於特定的controller硬體實現,一般都會有一個metadata的效率最優解。

如果Namespace enable了Protection information(PI)這個功能,那麼Metadata中的最開始8B或者最後8B是PI,這個數據是提供給host和Drive用來校驗Logical block數據的校驗信息。

二,Completion Queue Entry

CQ的entry和SQ有些不同,每個entry的大小是16B,4個DW。

DW0是command自己定義的信息,如果一個command需要使用DW0那麼可以自己定義內容。DW1是完全reserved。DW2裡面是SQ ID(該CQ可以對應多個SQ,所以需要指定SQ),SQ Head Pointer,通過這種方式可以讓host知道SQ現在的Head在哪裡,是否滿,是否可以塞下一個。

DW3中的status field用來匯報給host這個命令處理的狀態如何。

P表示我們前面提到的phase tag,這個tag只有一個bit,用來表示CQ中真正有效的entry的數目,這個bit在寫入一個有效entry的時候會被反轉,當head回到queue開始的位置的時候也會反轉,這樣就可以判斷當head自加,到達下一個phase tag和當前head的phase tag不一致時,是有效entry的結尾位置。我來手繪一張圖:

這張圖表示所有現在的phase tag都是0,host看不到tail指針,只能看到head指針和tag的情況下,它如何判斷當前的哪個entry是tail呢?這裡如果所有的tag都是一樣的,說明CQ是空的。

如果在這個深度為6的queue裡寫入3個,其中前面的3個的phase tag位就會被置為1,這時看到的head指針的phase tag是1,然後進入一個循環,head++直到找到一個phase tag不為1的entry,這個entry就是tail指針指向的位置。

那麼如果tail寫到了隊列結束的位置繞圈了怎麼辦?這個時候要將寫入的tag值反轉,也就是說如果之前valid entry寫入1,從queue end跳到queue begin的位置的時候,需要改成寫入0。

如上圖就是一個寫滿了的cq的phase tag排布,可以看到,除了queue從結尾到開始的跳轉的一次轉變外,tail永遠都是指向phase tag變化的第一個entry的位置。Nvme 的drive也很好寫:

731 static irqreturn_t nvme_process_cq(struct nvme_queue *nvmeq)

732 {

733         u16 head, phase;

734 

735         head = nvmeq->cq_head;

736         phase = nvmeq->cq_phase;  //獲取當前phase tag值

737 

738         for (;;) {

739                 void *ctx;

740                 nvme_completion_fn fn;

741                 struct nvme_completion cqe = nvmeq->cqes[head];

742                 if ((le16_to_cpu(cqe.status) & 1) != phase)  //如果當前P和head取出來的P不一樣,則直接break,說明沒有新的valid entry

743                         break;

744                 nvmeq->sq_head = le16_to_cpu(cqe.sq_head);

//        如果到達隊列結尾位置,則將當前phase tag值反轉

745                 if (++head == nvmeq->q_depth) {

746                         head = 0;

747                         phase = !phase;

748                 }

749 

750                 ctx = free_cmdid(nvmeq, cqe.command_id, &fn);

751                 fn(nvmeq->dev, ctx, &cqe);

752         }

753 

754         /* If the controller ignores the cq head doorbell and continuously

755          * writes to the queue, it is theoretically possible to wrap around

756          * the queue twice and mistakenly return IRQ_NONE.  Linux only

757          * requires that 0.1% of your interrupts are handled, so this isn't

758          * a big problem.

759          */

760         if (head == nvmeq->cq_head && phase == nvmeq->cq_phase)

761                 return IRQ_NONE;

762 

763         writel(head, nvmeq->q_db + (1 << nvmeq->dev->db_stride));

764         nvmeq->cq_head = head;

765         nvmeq->cq_phase = phase;

766 

767         return IRQ_HANDLED;

768 }

最後還有一個command ID(2Bytes)用來表示具體是SQ發送出來的哪個Command,這個位置的大小直接關係到SQ的深度上限,2^16最多64K的SQ深度。

三,Status Feild Definition

這個域是用來定義command所出的各種錯誤的域,如果這個域是0,說明command沒有出錯,不需要處理,但是你我都知道,一個軟體或者固件有80%的code都是用來做各種各樣的錯誤處理的,他們才是系統的主角。

這個域如果不包括Phase Tag這個bit的話一共有15位,從17-31,詳細信息如下:

最低的8位是Status Code,用來描述錯誤或者信息的一個域,之後是3個bit的Status Code Type域,這裡感覺上是SC的擴充位,28-29兩位用來表示host需要等多久之後可以再試一次當前出錯的命令,30位表示該條command出錯還有很多信息可以獲取,使用Get Log Page(一個admin指令)可以獲取這個錯誤的更多信息。最後31位用來表示這個command是不是host可以重新發送該命令並且有可能成功,如果是1表示這個command不用再次嘗試,本來就是期望錯誤,或者不可能成功。如果是0表示該command如果再次嘗試,有可能成功。

Status Code Type

這個code type 用來分類,有些是通用錯誤,比如command被abort了,或者namespace防寫了之類的,這個是Generic Status,另外和command強相關的,在Command specific status這一類中,比如admin創建Q的時候size設置超過最大值了。

Media 和數據完整性錯誤,就是NAND出了問題,而且firmware的糾正功能沒有糾正回來。

Path Related Status這一類是在drive內部的路徑上出現的錯誤,比如DDR或者總線上的傳輸出現了bitflip。

最後是為了測試和debug,設計drive的廠商可以自定義一些command以及對應的錯誤。

三,Controller Memory Buffer (CMB)

這是一個drive上的可選支持功能,並非所有的標準NVMe SSD都需要支持的。在CAP.CMBS位,可以查到當前的nvme controller是不是支持這個功能,另外同樣通過CMB寄存器的CMBLOC和CMBSZ可以得到CMB在host端看到的位置和大小。

CMB是drive和host的一段share memory,從drive和host都可以訪問到這個buffer,並且看到的offset是線性映射的,buffer大小也一樣。

CMB可以有很多中靈活的用法,比如可以用來放SQ的entry,可以用來放PRP和SGL的buffer,也可以用來放unaligned寫入的數據。總之這個buffer可以有很大的想像空間,可以支持很多種優化的做法。

這個buffer必須是4KiB對齊的,最好是8KiB對齊,寫入buffer的數據要在command寫入doorbell寄存器之前就寫完成。

四,Persistent Memory Region (PMR)

和CMB一樣是一個可選的功能,這個功能保證這個區域的數據在遇到異常掉電事件的時候可以被固化或者已經被固化在非易失介質上,從而保證數據的安全性可靠性。這個buffer更像是一個可以固化的DRAM區域,是一種非常理想化的存儲邏輯。但是現在的實現場景上看,固化和速度是一對天敵,固化在現有的介質上,速度一定會比DRAM訪問慢,所以如果實現這個功能,同步狀態檢查和效率上的損失是一定的。

五,NVMe Sets

NVMe Sets是一種後端概念,他們是一組物理上的介質組,

比如一個960GB的drive,host可以按照lun的數目進行劃分,如果有32個lun,可以把前16個和後16個分在不同的NVMe Set上,也可以把不同的block和page分在不同的NVMe set上,通過不同的劃分和組合,可以讓兩個set在進行不同的操作時做到相互影響最小化,從而達到latency可控的目的。

這種做法本質上和Open Channel,ZNS的做法和目的並無不同,只是對於drive內的media介質的開放程度不同,從host角度上來說,可以獲取和配置的信息不同。可以說這種進一步開放media信息給host的做法已經被驗證過是大勢所趨,但是上下分層的界限到底在哪裡最合適,將會是存儲業界通過實踐尋找的一個結果。

六,Namespace List

一個用來顯示現有namespace ID的數據結構。每4個Bytes表示一個NS ID。

七,Controller list

用來顯示有多少Controller以及每個controller的ID。每兩個byte是一個controller ID,最低2B是共有多少個controller,最多有2047個controller。

八,Fused Operations

這是一種通過設置Fused位來將兩個簡單command合併處理的技術,這兩個command將會作為一個原子操作進行處理,並且按照嚴格的順序(NVMe 隊列中的command先後順序並不能決定command真正執行的先後順序),如果第一個command出錯,第二個command將會被abort,如果第二個出錯,第一個command將會回sequence specific狀態。

兩個command操作的LBA range必須是一致的,如果不一致,將會被abort並且返回Invalid Field狀態。

兩個command必須插入在一個SQ裡,必須是連續的,必須update兩個entry到doorbell寄存器裡。(一次加2)

如果host要abort fused command,需要發兩個獨立的abort指令。同時兩個command各自都會收到自己的CQE。

九,Command Arbitration

因為有很多Queue,所以drive針對如何取queue內的entry都有一套自己的算法,所有的controller都應當默認支持round robin的方法,如果學有餘力,可以實現有權重的round robin的算法,或者廠家自定義的算法。

 Round Robin方法,

這種方法非常簡單,按照順序從每個Queue中取一個或者幾個command進行處理。

有權重的Round Robin

這種方法有三個權重優先級,高中低三擋,並且還有Urgent和Admin兩種strict policy。

最後是用戶自定義優先級這種優先級可以按照定製用戶的規則來設計,想必航空航天等高安全和高可靠實時設備會更加需要嚴格的優先級設計。

總結,本文主要介紹了Metadata,CQE的數據結構,Cmd的錯誤狀態,CMB和PMR兩種未來可能會大放異彩的NVMe SSD高階功能,NVMe sets這種將media進行初步劃分的功能,以及NVMe SQ之間是如何調度優先級的。

CMB, PMR,NVMe Sets和Q的優先級調度都能在存儲系統中對SSD的功能和性能進行優化,是還有很大發展潛力的NVMe feature。

參考文章:https://blog.csdn.net/Memblaze_2011/article/details/52767226

https://www.sohu.com/a/294397317_505795

相關焦點

  • Linux NVMe Driver學習筆記之10: Block IO請求處理過程
    > .init_hctx = nvme_init_hctx, .init_request = nvme_init_request, .map_queues = nvme_pci_map_queues, .timeout = nvme_timeout, .poll = nvme_poll,};我們在這裡主要點名結構體中的第一個成員
  • 嚴蔚敏數據結構C語言版課後習題答案及筆記
    向然學習資料網為同學們提供嚴蔚敏數據結構C語言版課後習題答案及筆記
  • 一日一技:python中4大數據結構常用接口簡介
    具體到python中數據結構的選擇運用,雖然有很多類型可供選擇:除了基本的列表、字典、集合和元組4個基本類型外,collections模塊中提供了很多定製化的數據結構,還有專用的堆heapq和枚舉enum等。誠然,特定數據結構在某些應用場景下可能有神奇的效果,但把基礎數據類型用到極致也可堪稱是絕招。
  • NVME固態搭配USB3.2硬碟盒是什麼神仙體驗?
    從一個從IDE接口硬碟時代過來的人來看,不禁感嘆如今存儲領域的發展之快,隨著M.2 SSD的普及,開始價格高高在上的NVME固態也慢慢變得平易近人,目前的PC和筆電端基本上都配備有M.2接口,M.2 SSD似乎對2.5寸SSD也漸有了取代之勢。
  • 淺析U.2接口NVMe SSD雙埠模式(下)——可靠性及性能測試
    淺析U.2接口NVMe SSD雙埠模式(上)——應用模式與設計實現相關閱讀:《淺析U.2接口NVMe SSD雙埠模式(上)——應用模式與設計實現》上篇說了雙埠的一些概念和實現,這篇將進一步通過測試介紹NVMe SSD雙埠特性的可靠性和性能的驗證
  • Simple is better than complex——python中4大數據結構常用接口簡介
    具體到python中數據結構的選擇運用,雖然有很多類型可供選擇:除了基本的列表、字典、集合和元組4個基本類型外,collections模塊中提供了很多定製化的數據結構,還有專用的堆heapq和枚舉enum等。誠然,特定數據結構在某些應用場景下可能有神奇的效果,但把基礎數據類型用到極致也可堪稱是絕招。
  • 數據結構基礎:樹結構的學習筆記
    當n=0時稱為空樹,當n>0 為非空樹,任何非空樹中,有且僅有一個根節點;其餘節點可分為m(m>=0)個互不相交的有限集合T1、T2 等,其中每一個集合都可以稱為一棵樹,稱為根節點的子樹。
  • 常用數據接口匯總,百度、谷歌、頭條、微博指數,高校名單,疫情數據...
    同時本項目提供的數據接口及相關數據僅用於學術研究,任何個人、機構及團體使用本項目的數據接口及相關數據請注意商業風險。 然後回復  數據接口  即可獲取。新經濟公司:千裡馬公司、獨角獸公司、倒閉公司、商業特許經營公司0.1.4利率數據:Shibor數據、Shibor報價數據、Shibor均值數據、LPR數據0.1.1宏觀經濟:中國宏觀經濟0.1.0 規範說明文檔格式指數數據:微博指數、百度指數疫情數據:網易疫情數據、丁香園疫情數據、百度疫情數據、百度遷徙數據
  • USB接口內部結構
    該器件採用模塊化的方法實現一個USB接口,允許使用現存的體系結構並使固件投資減到最小。這種靈活性通過使用己有的結構和減少固件上的投資,減少了開發時間、風險和成本,是開發低成本且高效的USB外圍設備解決方案的一種有效途徑。  PDIUSBD12內置的串行接口引擎SIE,實現了全部的USB協議層,完全由硬體實現而不需要固件的參與。
  • lightning接口內部結構詳解
    打開APP lightning接口內部結構詳解 發表於 2018-03-09 13:52:28   也就是說,早在蘋果iPhone 5開始就用上了Lightning數據接口,支持正反插,與安卓用戶熟悉的USB-C接口類似。而安卓手機配備的支持正反插的USB Type-C接口,基本是2014年才開始出現,2015年開始流行的。
  • 性能強悍——奧睿科M_2 NVMe & SATA 固態硬碟盒
    固態硬碟擁有機械硬碟沒有的一些特點,首先是抗摔,固態硬碟採用的是儲存晶片,不具備機械硬碟的機械結構,抗摔能力比機械硬碟好很多。然後是固態的超高寫入讀取速度,平均讀寫水平都能達到400m/s左右,而機械硬碟的最高7200轉,也不過可憐159m/s左右。最後就是體積,固態有nvme與sata,就算是體積稍大的sata也比筆記本機械硬碟小,nvme就更不用說了,體積甚至比一張銀行卡還要小。
  • 真是一分錢一分貨 NVme SSD都有哪些優勢?
    【IT168 評論】SSD 固態硬碟近年來被廣泛的應用,在機械硬碟過渡固態硬碟的期間,也擁有更高的追求,而要讓 SSD 發揮到極致的性能,原來的 SATA 模式與 AHCI 模式已經不能夠滿足,但現在最新的存儲接口 M.2 和 SARA-E 接口都是採用的 PCI-E 通道,而 PCI-E 接口發揮最高性能就需要新的 NVMe 標準
  • Go 語言中無心插柳柳成蔭的接口和無為而治的空接口
    如果你還了解編程概念中的接口概念,那麼我建議你最好還是先閱讀上一篇文章.詳情請點擊 go 學習筆記之萬萬沒想到寵物店竟然催生出面向接口編程?,否則的話,請自動忽略上文,繼續探索 Go 語言的接口有什麼不同之處.
  • 基於USB接口的數據採集系統總體結構解析
    基於USB接口的數據採集系統總體結構解析 電子工程網 發表於 2019-09-16 15:31:38 數據採集任務多在戶外進行,所以數據採集系統通常要滿足實時性、專用性
  • PBlaze5 520 系列 NVMe SSD——NVMe-MI接口的帶外管理
    在上周最新發布的 PBlaze5 520 低功耗系列 NVMe SSD中,有一個全新功能——NVMe-MI接口的帶外管理,這是從PBlaze5 520系列最新增加的功能,那麼這個帶外管理指的是什麼,又怎麼實現呢?
  • 重學數據結構(七、圖)
    在線性表中,數據元素之間僅有線性關係,每個數據元素只有一個直接前驅和一個直接後繼;在樹形結構中,數據元素之間有著明顯的層次關係,並且每一層中的數據元素可能和下一層中的多個元素(即其孩子結點)相關,但只能和上一層中一個元素(即其雙親結點)相關; 而在圖結構中,結點之間的關係可以是任意的,圖中任意兩個數據元素之間都可能相關。
  • 網絡編程基礎學習筆記2:socket接口及網絡編程三要素
    對於網絡編程而言,由於其底層語言是通過C語言來實現的,所以建議在學習的時候使用C語言來進行學習!網絡編程中常用的socket接口如下:socket()接口,用於創建socket;bind():用於綁定socket到本地地址和埠,通常由服務端調用(客戶端一般直接由connect直接主動去連結服務端);listen():用於開啟監聽模式,TCP專用;accept():用於伺服器等待客戶端連接,該情況一般在阻塞狀態下產生
  • Python For Data Analysis筆記(1)|Python 的數據結構、函數和文件
    數據科學路漫漫,讀起書來真沒完,可是還得看。一個人看也是看,一群人看更挑戰!所以,歡迎累了就到我公眾號話題「讀書蟲啃數據」裡把我的筆記瞅一瞅,當作入門、回顧、準備面試,都可以!在向數據大牛靠近的路上慢慢披荊斬棘。所有的練習code和思維導圖都放在了GitHub中,思維導圖來自軟體Xmind,可以下載下來。每個板塊都有code案例,或者下面連結中的Python-Code文件夾即可。
  • 騰訊T4竟然把《數據結構與算法》講明白了,附源碼筆記
    如果不會,可能面試就直接掛了先來帶大家看下學習用的數據結構與算法的腦圖吧數據結構與算法思維腦圖圖片太大,只能這樣展示了,需要清晰圖片的朋友可以私信回復【學習】來獲取不扯遠了,如果有還在上大學的同學可以考慮先以排序和各種的基本數據結構開始入門。
  • 小築筆記——工作、學習、閱讀、資料、靈感筆記
    小築筆記app是一款專門用於資料保存管理的軟體,該軟體是適合於學生或者工作者,是可以將自己的筆記、工作內容可以進行很好的整理,非常方便。小築筆記,樹形結構,無限分層,自由排序。利於分析分解、梳理知識、思想、事情。整潔清晰,為長久的積累、使用而設計。