1.
1.
1.1. 用戶態實現
對lv1創建一個快照卷時,有前面章節可知會創建多個dm設備,如下圖所示:
以上幾個設備的創建過程如下:
1. 創建snap_lv1,其類型爲linear,分配其存儲空間,與磁盤映射關係如上圖所示;
2. 創建lv1-real,其類型爲linear,其映射的磁盤空間和lv1原有的映射一致;
3. 更改lv1的類型爲origin,此時lv1被標記爲只讀,並且把io操作都重定向到lv1-real設備;
4. 創建snap_lv1-cow,其類型爲linear,將其映射到snap_lv1分配的磁盤空間上,也即是和snap_lv1的映射一致;
5. 更改snap_lv1的類型爲snapshot,此時將會創建一個lv1原有磁盤空間的寫時複製的表格,並且將lv1-real和snap_lv1-cow綁定,因爲以後更改lv1的內容將會保存到snap_lv1-cow中,而未修改的內容仍然在lv1-real中,這兩者一起構成了snap_lv1,即是snap_lv1的映射範圍爲兩者的和。
當然在做以上工作之前需要先凍結lv1,完成以上動作之後,元數據將被更新,同時lv1將被激活,io將正常進行。
1.2. 內核態實現
在內核態主要涉及dm下的linear、snapshot-origin、shnapshot幾個target的驅動。
其中最重要的幾個函數就是ctr和map的實現,下面簡單介紹以上三個target的ctr和map實現。
linear_ctr:將設備添加到dm_table的設備列表中,並記錄在該設備上的起始位置。
linear_map:更改bio的設備,並將bio的偏移量加上該線性卷在物理設備上的起始偏移量,然後重新提交bio,由真正的設備驅動來處理。
origin_ctr:這個很簡單,將real設備保存起來,方便後續的io重定向。
origin_map:重新映射io,如果是讀io,直接重定向到real設備,如果是寫io,則需查找保存shanshot的設備,並獲取標記寫時複製的表格,在其中查詢是否本次io位於範圍之內,如果該io地址範圍內已經發生過一次寫時複製,則直接重定向到real設備,如果還沒有,則將本次io緩存起來,同時開啓kcopy內核線程,從real設備上拷貝本次io地址範圍內的數據到snap cow設備上,完成之後再將緩存的io重定向到real設備。
snapshot_ctr:在snap cow設備的前8k上建立寫時複製的映射表,並建立real設備和snap cow設備的映射關係。
snapshot_map:如果爲讀io,且io對應地址沒有發生寫時複製,則從重定向到real設備,否則重定向到snap cow設備;如果爲寫io,則直接寫入到snap cow設備,禁止寫時複製。