Linux 內核中的 Device Mapper 機制

Device Mapper 是 Linux2.6 內核中支持邏輯卷管理的通用設備映射機制,它爲實現用於存儲資源管理的塊設備驅動提供了一個高度模塊化的內核架構,如圖 1。 linux


圖1 Device Mapper的內核體系架構
圖1 Device Mapper的內核體系架構  

在內核中它經過一個一個模塊化的 target driver 插件實現對 IO 請求的過濾或者從新定向等工做,當前已經實現的 target driver 插件包括軟 raid、軟加密、邏輯卷條帶、多路徑、鏡像、快照等,圖中 linear、mirror、snapshot、multipath 表示的就是這些 target driver。Device mapper 進一步體現了在 Linux 內核設計中策略和機制分離的原則,將全部與策略相關的工做放到用戶空間完成,內核中主要提供完成這些策略所須要的機制。Device mapper 用戶空間相關部分主要負責配置具體的策略和控制邏輯,好比邏輯設備和哪些物理設備創建映射,怎麼創建這些映射關係等等,而具體過濾和重定向 IO 請求的工做由內核中相關代碼完成。所以整個 device mapper 機制由兩部分組成--內核空間的 device mapper 驅動、用戶空間的device mapper 庫以及它提供的 dmsetup 工具。在下文中,咱們份內核和用戶空間兩部分進行介紹。 數組

內核部分 數據結構

Device mapper 的內核相關代碼已經做爲 Linux 2.6 內核發佈版的一部分集成到內核源碼中了,相關代碼在內核源碼的 driver/md/ 目錄中,其代碼文件能夠劃分爲實現 device mapper 內核中基本架構的文件和實現具體映射工做的 target driver 插件文件兩部分。文章下面的分析結果主要是基於上述源碼文件獲得的。 架構

重要概念 併發

Device mapper 在內核中做爲一個塊設備驅動被註冊的,它包含三個重要的對象概念,mapped device、映射表、target device。Mapped device 是一個邏輯抽象,能夠理解成爲內核向外提供的邏輯設備,它經過映射表描述的映射關係和 target device 創建映射。從 Mapped device 到一個 target device 的映射表由一個多元組表示,該多元組由表示 mapped device 邏輯的起始地址、範圍、和表示在 target device 所在物理設備的地址偏移量以及target 類型等變量組成(這些地址和偏移量都是以磁盤的扇區爲單位的,即 512 個字節大小)。Target device 表示的是 mapped device 所映射的物理空間段,對 mapped device 所表示的邏輯設備來講,就是該邏輯設備映射到的一個物理設備。Device mapper 中這三個對象和 target driver 插件一塊兒構成了一個可迭代的設備樹。在該樹型結構中的頂層根節點是最終做爲邏輯設備向外提供的 mapped device,葉子節點是 target device 所表示的底層物理設備。最小的設備樹由單個 mapped device 和 target device 組成。每一個 target device 都是被mapped device 獨佔的,只能被一個 mapped device 使用。一個 mapped device 能夠映射到一個或者多個 target device 上,而一個 mapped device 又能夠做爲它上層 mapped device的 target device 被使用,該層次在理論上能夠在 device mapper 架構下無限迭代下去。 app


圖2 Device mapper 內核中各對象的層次關係
圖2 Device mapper 內核中各對象的層次關係  

在圖2 中咱們能夠看到 mapped device1 經過映射表和 a、b、c 三個 target device 創建了映射關係,而 target device a 又是經過 mapped device 2 演化過來,mapped device 2 經過映射表和 target device d 創建映射關係。 模塊化

咱們進一步看一下上述三個對象在代碼中的具體實現,dm.c 文件定義的 mapped_device 結構用於表示 mapped device,它主要包括該 mapped device 相關的鎖,註冊的請求隊列和一些內存池以及指向它所對應映射表的指針等域。Mapped device 對應的映射表是由 dm_table.c 文件中定義的 dm_table 結構表示的,該結構中包含一個 dm_target結構數組,dm_target 結構具體描述了 mapped_device 到它某個 target device 的映射關係。而在 dm_table 結構中將這些 dm_target 按照 B 樹的方式組織起來方便 IO 請求映射時的查找操做。Dm_target 結構具體記錄該結構對應 target device 所映射的 mapped device 邏輯區域的開始地址和範圍,同時還包含指向具體 target device 相關操做的 target_type 結構的指針。Target_type 結構主要包含了 target device 對應的 target driver 插件的名字、定義的構建和刪除該類型target device的方法、該類target device對應的IO請求重映射和結束IO的方法等。而表示具體的target device的域是dm_target中的private域,該指針指向mapped device所映射的具體target device對應的結構。表示target device的具體結構因爲不一樣的target 類型而不一樣,好比最簡單的線性映射target類型對應target device的結構是dm-linear.c文件中定義的linear_c結構。其定義以下: 函數


struct linear_c {
	struct dm_dev *dev;
	sector_t start;
};

該target device的定義至關簡單,就只包括了表示對應物理設備的dm_dev結構指針和在該物理設備中以扇區爲單位的偏移地址start。上述幾個數據結構關係如圖3所示: 工具


圖3 device mapper中幾個重要數據結構的關係
圖3  device mapper中幾個重要數據結構的關係  

內核中創建過程 加密

在下面咱們結合具體的代碼簡要介紹下在內核中建立一個mapped device的過程:

一、 根據內核向用戶空間提供的ioctl 接口傳來的參數,用dm-ioctl.c文件中的dev_create函數建立相應的mapped device結構。這個過程很簡單,主要是向內核申請必要的內存資源,包括mapped device和爲進行IO操做預申請的內存池,經過內核提供的blk_queue_make_request函數註冊該mapped device對應的請求隊列dm_request。並將該mapped device做爲磁盤塊設備註冊到內核中。

二、 調用dm_hash_insert將建立好的mapped device插入到device mapper中的一個全局hash表中,該表中保存了內核中當前建立的全部mapped device。

三、 用戶空間命令經過ioctl調用table_load函數,該函數根據用戶空間傳來的參數構建指定mapped device的映射表和所映射的target device。該函數先構建相應的dm_table、dm_target結構,再調用dm-table.c中的dm_table_add_target函數根據用戶傳入的參數初始化這些結構,而且根據參數所指定的target類型,調用相應的target類型的構建函數ctr在內存中構建target device對應的結構,而後再根據所創建的dm_target結構更新dm_table中維護的B樹。上述過程完畢後,再將創建好的dm_table添加到mapped device的全局hash表對應的hash_cell結構中。

四、 最後經過ioctl調用do_resume函數創建mapped device和映射表之間的綁定關係,事實上該過程就是經過dm_swap_table函數將當前dm_table結構指針值賦予mapped_device相應的map域中,而後再修改mapped_device表示當前狀態的域。

經過上述的4個主要步驟,device mapper在內核中就創建一個能夠提供給用戶使用的mapped device邏輯塊設備。

IO流

Device mapper本質功能就是根據映射關係和target driver描述的IO處理規則,將IO請求從邏輯設備mapped device轉發相應的target device上。Device mapper處理全部從內核中塊一級IO子系統的generic_make_request和submit_bio接口[兩個接口具體的描述能夠查看參考文獻[1]和[2],這兩本書對內核中的塊IO層有比較詳盡的講解。] 中定向到mapped device的全部塊讀寫IO請求。IO請求在device mapper的設備樹中經過請求轉發從上到下地進行處理。當一個bio請求在設備樹中的mapped deivce向下層轉發時,一個或者多個bio的克隆被建立併發送給下層target device。而後相同的過程在設備樹的每個層次上重複,只要設備樹足夠大理論上這種轉發過程能夠無限進行下去。在設備樹上某個層次中,target driver結束某個bio請求後,將表示結束該bio請求的事件上報給它上層的mapped device,該過程在各個層次上進行直到該事件最終上傳到根mapped device的爲止,而後device mapper結束根mapped device上原始bio請求,結束整個IO請求過程。

Bio在device mapper的設備樹進行逐層的轉發時,最終轉發到一個或多個葉子target節點終止。由於一個bio請求不能夠跨多個target device(亦即物理空間段), 所以在每個層次上,device mapper根據用戶預先告知的mapped device 的target映射信息克隆一個或者多個bio,將bio進行拆分後轉發到對應的target device上。這些克隆的bio先交給mapped device上對應的target driver上進行處理,根據target driver中定義的IO處理規則進行IO請求的過濾等處理,而後再提交給target device完成。上述過程在dm.c文件中的dm_request函數中完成。Target driver能夠對這些bio作以下處理:

1、 將這些bio在本驅動內部排隊等待之後進行處理;

2、 將bio從新定向到一個或多個target device上或者每一個target device上的不一樣扇區;

3、 向device mapper返回error 狀態。

IO請求就按照上文中描述的過程在圖2中所示的設備樹中逐層進行處理,直到IO請求結束。

小結

Device mapper在內核中向外提供了一個從邏輯設備到物理設備的映射架構,只要用戶在用戶空間制定好映射策略,按照本身的須要編寫處理具體IO請求的target driver插件,就能夠很方便的實現一個相似LVM的邏輯卷管理器。Device mapper以ioctl的方式向外提供接口,用戶經過用戶空間的device mapper庫,向device mapper的字符設備發送ioctl命令,完成向內的通訊。它還經過ioctl提供嚮往的事件通知機制,容許target driver將IO相關的某些事件傳送到用戶空間。

回頁首

用戶空間部分

Device mapper在用戶空間相對簡單,主要包括device mapper庫和dmsetup工具。Device mapper庫就是對ioctl、用戶空間建立刪除device mapper邏輯設備所需必要操做的封裝,dmsetup是一個提供給用戶直接可用的建立刪除device mapper設備的命令行工具。由於它們的功能和流程相對簡單,在本文中對它們的細節就不介紹了,用戶空間主要負責以下工做:

一、 發現每一個mapped device相關的target device;

二、 根據配置信息建立映射表;

三、 將用戶空間構建好的映射表傳入內核,讓內核構建該mapped device對應的dm_table結構;

四、 保存當前的映射信息,以便將來從新構建。

如下咱們主要經過實例來講明dmsetup的使用,同時進一步說明device mapper這種映射機制。用戶空間中最主要的工做就是構建並保存映射表,下面給出一些映射表的例子:

1)
0 1024 linear /dev/sda 204
1024 512 linear /dev/sdb 766

1536 128 linear /dev/sdc 0

2) 0 2048 striped 2 64 /dev/sda 1024 /dev/sdb 0

3) 0 4711 mirror core 2 64 nosync 2 /dev/sda 2048 /dev/sdb 1024

例子1中將邏輯設備0~1023扇區、1024~1535扇區以及1536~1663三個地址範圍分別以線形映射的方式映射到/dev/sda設備第204號扇區、/dev/sdb設備第766號扇區和/dev/sdc設備的第0號扇區開始的區域。

例子2中將邏輯設備從0號扇區開始的,長度爲2048個扇區的段以條帶的方式映射的到/dev/sda設備的第1024號扇區以及/dev/sdb設備的第0號扇區開始的區域。同時告訴內核這個條帶類型的target driver存在2個條帶設備與邏輯設備作映射,而且條帶的大小是64個扇區,使得驅動能夠該值來拆分跨設備的IO請求。

例子3中將邏輯設備從0號扇區開始的,長度爲4711個扇區的段以鏡像的方式映射到/dev/sda設備的第2048個扇區以及/dev/sdb設備的第1024號扇區開始的區域。

映射表肯定後,建立、刪除邏輯設備的操做就相對簡單,經過dmsetup以下命令就能夠完成相應的操做。

dmsetup create 設備名 映射表文件 /* 根據指定的映射表建立一個邏輯設備 */

dmsetup reload 設備名 映射表文件 /* 爲指定設備從磁盤中讀取映射文件,從新構建映射關係 */

dmsetup remove 設備名 /* 刪除指定的邏輯設備 */


圖4 根據例子1中映射表在內核中創建的邏輯設備
圖4 根據例子1中映射表在內核中創建的邏輯設備  

當用戶空間根據映射表下達建立邏輯設備命令後,device mapper在內核中就根據傳入的參數和映射關係創建邏輯地址到物理地址的映射關係。根據映射表例子1中的映射關係創建的設備如圖4所示,圖中的下半部分就抽象地描繪出了按照該映射表在內核中創建的邏輯地址到物理地址的映射關係。

Device mapper的用戶空間部分對開發者要實現本身的存儲管理工具來講是可選的,事實上,不少咱們常見的邏輯卷管理器,好比LVM二、dmraid等工具都利用device mapper的提供的device mapper用戶空間庫,根據本身的管理需求創建獨立的一套管理工具,而並無使用它提供的dmsetup工具,甚至IBM的開源項目企業級的邏輯卷管理系統-EVMS,在實現中都沒有采用device mapper的用戶空間庫,徹底根據內核中的ioctl定義實現了一套本身的函數庫。

回頁首

Target Driver

Device mapper提供了一個統一的架構,經過target driver 插件的方式容許用戶根據實際的須要指定本身的IO處理規則,所以target driver充分體現了device mapper的靈活性。在上文中咱們已經不止一次的提到過target driver,也描述過target driver的功能,在這裏咱們結合最簡單的linear target driver具體介紹target driver的實現。

Target driver主要定義對IO請求的處理規則,在device mapper中對target driver的操做已定義好了統一的接口,在實現中該接口由咱們上文提到的target_type結構中定義,它定義瞭如下target driver的方法:

1、 構建target device 的方法;
2、 刪除target device 的方法;
3、 Target的映射IO請求的方法;
4、 Target結束IO請求的方法;
5、 暫停target device讀寫的方法;
6、 恢復target device讀寫的訪問;
7、 獲取當前target device狀態的訪問;
8、 Target 處理用戶消息的方法;

用戶能夠根據具體需求選擇性地實現上述方法,但通常最少要實現前3種方法,不然在device mapper下不可以正常的工做。linear target driver就只實現了前3種方法和方法7,它完成邏輯地址空間到物理地址空間的線性映射,能夠將多個物理設備以線性鏈接的方式組成一個邏輯設備,就如圖4中描述的那樣,經過linear target driver將/dev/sda、/dev/sdb、/dev/sdc的三段連續空間組成了一個大的邏輯塊設備。Linear target的實現很簡單,它的建立和刪除方法主要完成申請和釋放描述linear target device所用結構的內存資源;IO映射處理方法的實現更是簡單,以下代碼所示:


static int linear_map(struct dm_target *ti, struct bio *bio,
		      union map_info *map_context)
{
	struct linear_c *lc = (struct linear_c *) ti->private;

	bio->bi_bdev = lc->dev->bdev;
	bio->bi_sector = lc->start + (bio->bi_sector - ti->begin);

	return 1;
}

該映射方法就是將發送給邏輯設備mapped device的bio請求,根據映射關係以線性的方式從新定向到linear target device所表示物理設備的相應位置,如代碼所示具體實現方法就是修改bio的bi_bdev設備指針爲target device對應的設備指針,並根據target device的起始地址和該bio請求在mapped device設備上的偏移值改變IO請求開始的扇區號bi_sector,從而完成IO請求的重定向。其餘target driver的實現也都大同小異,按照device mapper所定義的接口規範,結合本身須要的功能進行實現便可,這裏就不一一介紹了,有興趣的讀者能夠看內核中具體的target driver代碼。


總結

Device Mapper是Linux操做系統中塊設備一級提供的一種主要映射機制,如今已被多數Linux下的邏輯卷管理器所採用。在該機制下,實現用戶自定義的存儲資源管理策略變得極其方便。理解device mapper所提供的映射機制,也是進一步理解Linux下一些常見邏輯卷管理器實現的基礎。

相關文章
相關標籤/搜索