歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

Linux CDP(連續性數據保護)實現方案、技術細節介紹及相關源碼文檔下載

一、塊級CDP(連續數據保護)

Block based CDP Module for Linux Kernel是Red Hat學術開源項目中一個基於塊的連續數據保護模塊,這個模塊在數據塊級別提供連續數據保護能力。連續數據保護是一種備份和恢復技術,它持續地捕獲所有I/O請求,並且為在這些請求打上時間戳標志。它將數據變化以及時間戳保存下來,以便恢復到過去的任意時刻。因此,這個模塊支持數據的任意時刻映像。 在Linux的CDP實現中,涉及三個設備:
  • >主機磁盤(Host Disk)設備;
  • CDP倉庫(Repository)設備;
  • CDP元數據(Metadata)設備;
CDP代碼對主機磁盤設備數據塊的在各個時刻所作的寫操作都被記錄下來,被順序保存到CDP倉庫設備中,同時對應的元數據也被保存在CDP元數據設備中。 元數據包括以下信息: struct metadata {
    int hrs, min, sec; 該數據塊被寫入主機磁盤設備的時間;
    unsigned int bisize; 該數據塊的以字節為單位的長度;
    sector_t cdp_sector; CDP倉庫設備中對應數據塊的起始扇區編號;
    sector_t host_sector; 該數據塊在主機磁盤設備中的起始扇區編號;
}; 下圖反映了主機磁盤設備和CDP倉庫設備之間的關系。CDP倉庫設備中按時間順序保存了對主機磁盤設備的數據修改。A為主機磁盤設備上的一個扇區,該扇區在9:00和9:05分別進行了修改,它在CDP倉庫設備中對應的扇區分別為A1和A2。 下圖反映了CDP倉庫設備和CDP元數據設備之間的關系,它們以寫入順序一一對應。CDP倉庫設備中的一個元數據對應CDP元數據設備中一個I/O請求,實際上可能是多個扇區。具體扇區數由元數據中的bisize指定,而起始扇區位置由cdp_sector指定。 1.1 CDP倉庫設備 全局變量maddr保存了下一個I/O請求在CDP倉庫設備上執行的地址(起始扇區編號)。maddr的初值被定義為宏START_METADATA(0)。 unsigned int maddr = START_METADATA; 當一個寫請求到來時,對應數據被寫到CDP倉庫設備中,這時所作的操作如下: l 將寫入CDP倉庫設備的數據塊起始扇區編號設置為maddr; l 根據要寫入主機磁盤設備的數據塊的扇區數目增加maddr。 這時,我們要將這裡寫入的CDP倉庫設備的數據塊編號記錄下來以便構造對應的元數據。 1.2 CDP元數據設備 全局變量taddr保存了下一個I/O請求對應的元數據在CDP元數據設備中保存的地址(起始扇區編號)。 taddr的初值被定義為宏START_METADATA(0)。 unsigned int taddr = START_METADATA; 當一個寫請求到來時,對應的元數據被記錄在CDP元數據設備中。 為了簡單起見,在元數據設備上,一個扇區(512字節)只保存一個元數據信息(只有32字節),這樣浪費了大量的存儲空間,但對元數據設備的處理卻非常簡單:
  • 將寫入CDP元數據設備的元數據起始扇區編號設置為taddr,長度為1個扇區;
  • 將taddr增1。
1.3 請求處理過程 請求處理過程是從make_request函數開始的。考慮到讀請求的處理的相似性,甚至更為簡單,我們這裡只分析對寫請求的處理過程。我們首先獲得當前的系統時間。之後,寫請求bio結構(為說明方便,我們記為B)被分為三個寫請求bio結構(分別為B0、B1和B2)。這三個bio結構的作用是:
  • B0:將數據塊寫到主機磁盤設備;
  • B1:將數據塊寫到CDP倉庫設備;
  • B2:將元數據寫到CDP元數據設備。
  同其它塊設備驅動程序的實現一樣。我們從B克隆產生B0、B1和B2。然後重定向它們要處理的設備,即bi_bdev域。另外一個大的變動是重新設置了bi_end_io域,用於在I/O請求完成之後進行善後處理。 為了處理善後,還將B0、B1和B2的bi_private指向同一個cdp_bio1結構。從這個結構,我們要能夠回到對B的處理。 struct cdp_bio {
    struct bio *master_bio; 原來的bio,通過這個域我們可以從B0、B1、B2找到B
    struct bio *bios[3]; 如果IO為WRITE,這個指針數組分別指向B0、B1、B2,為何需要這個域?
    atomic_t remaining; 這裡一個計數器,我們後面將解釋。
    unsigned long state; 在I/O完成方法中使用
}; 善後工作的主要目的是:在B0、B1和B2都執行完成後,回去執行B,為此,我們需要一個“have we finished”計數器,這就是原子整型變量remaining。在構造B0、B1、B2時分別遞增,同時在B0、B1和B2的I/O完成方法中遞減,最後根據該值是否遞減到0,來判斷B0、B1和B2是否都已經執行完畢。為了防止B0在構造後,在B1和B2構造之前就執行到B0的I/O完成方法,從而使得remaining變成0,這種錯誤情況。我們沒有將remaining的初值設置為0,而是設為1。並在B0、B1、B2都構造完成執行遞減一次。 B0、B1、B2都執行完成之後,進行如下的處理:
  1. 調用B的善後處理函數;
  2. 釋放期間分配的數據結構;
  3. 向上層buffer cache返回成功/錯誤碼。
另一個需要說明的是對B2的構造,這個bio結構需要處理的是元數據。時間戳已經在進入make_request時獲得了保存,而對主機磁盤設備操作的起始扇區和長度從B中可以獲得,對應的CDP倉庫和CDP元數據的起始地址分別保存在全局變量maddr和taddr中。 1.4 數據恢復過程 我們可以將數據恢復到以前的任意時刻。CDP實現代碼中提供了一個blk_ioctl函數,用戶空間以GET_TIME為參數調用該函數,將主機磁盤設備中的數據恢復到指定的時間點。恢復的過程分為以下幾步: 1. 順序讀取CDP元數據設備的所有扇區,構造一個從主機磁盤設備數據塊到CDP倉庫設備的(在這個時間點之前)更新數據塊的映射。其結果保存在以mt_home為首的(映射表)鏈表中。 這裡需要構造taddr個對CDP元數據設備的讀請求,每個請求讀取一個扇區。在這些請求的I/O完成方法中,從讀到的數據中構造元數據,並遞減計數器count。 如果元數據中的時間戳早於或等於指定的恢復時間點,則需要添加或修改mt_home鏈表的元數據結構。需要說明的是,這些項是以host_sector為關鍵字索引的,因此添加或修改取決於前面是否出現對同一個host_sector的修改。我們以順序方式讀取的過程中,可以保證host_sector(在指定的恢復時間點之前)的最新修改cdp_sector會出現在這個鏈表中。 由於計數器count為taddr,如果它遞減為0,說明CDP元數據設備中的所有數據均已讀出並處理,這時我們可以繼續往後面執行。 2. 從CDP倉庫設備中讀取這些更新的數據塊,構造以mt_bi_home為首的鏈表。 同上面的處理類似,我們需要為mt_home鏈表中的每一項構造對CDP倉庫設備的讀請求,每個請求在CDP倉庫設備的起始編號取決於cdp_sector域,長度則根據bisize而定。這個請求讀出的數據需要被寫入到主機磁盤設備中,為此我們在讀請求I/O完成函數中,構造一個對應的往主機磁盤設備的寫請求bio,該寫請求的起始編號取決於host_sector域,長度根據bisize而定,而要寫入的數據是剛剛從CDP倉庫設備中讀出的數據。另外,在讀請求I/O完成函數中,還要遞減一個計數器,當該計數器遞減到0時,說明我們已經全部處理了mt_home鏈表中的項,這時得到一個以mr_bio_home為首,每項中都指向一個bio結構的鏈表。 struct list_head mt_home; //BIO更新鏈表
struct most_recent_blocks { //BIO更新表項
    struct bio *mrbio;
    struct list_head list;
}; 3. 將mt_bi_home鏈表的數據塊都恢復到主機磁盤設備中。 這個操作相對比較簡單,我們只需要在主機磁盤設備上執行mt_bi_home鏈表的每一個bio請求項即可。當然,我們要在這些請求項的I/O完成方法中做善後處理,即如果所有請求項都已經執行完畢,則釋放mt_home鏈表和mt_bi_home鏈表。 另一點要引起注意的是,上面的第2步操作和第3步操作采用tasklet實現,不知作何考慮?是否是因為它們在I/O完成方法中處理。 這個模塊是如何使用的? struct bio {         sector_t             bi_sector;         /* associated sector on disk */         struct bio           *bi_next;          /* list of requests */         struct block_device *bi_bdev;          /* associated block device */         unsigned long        bi_flags;          /* status and command flags */         unsigned long        bi_rw;             /* read or write? */         unsigned short       bi_vcnt;           /* number of bio_vecs off */         unsigned short       bi_idx;            /* current index in bi_io_vec */         unsigned short       bi_phys_segments; /* number of segments after coalescing */         unsigned short       bi_hw_segments;    /* number of segments after remapping */         unsigned int         bi_size;           /* I/O count */         unsigned int         bi_hw_front_size; /* size of the first mergeable segment */         unsigned int         bi_hw_back_size;   /* size of the last mergeable segment */         unsigned int         bi_max_vecs;       /* maximum bio_vecs possible */         struct bio_vec       *bi_io_vec;        /* bio_vec list */         bio_end_io_t         *bi_end_io;        /* I/O completion method */         atomic_t             bi_cnt;            /* usage counter */         void                 *bi_private;       /* owner-private method */         bio_destructor_t     *bi_destructor;    /* destructor method */ };   struct bio_vec {         /* pointer to the physical page on which this buffer resides */         struct page     *bv_page;           /* the length in bytes of this buffer */         unsigned int    bv_len;           /* the byte offset within the page where the buffer resides */         unsigned int    bv_offset; };   1.5 塊級CDP源碼下載與安裝 你可從這裡獲得Block Based CDP module for linux kernel的源碼以及所有的相關安裝配置文檔: Project Title  Block based CDP Module for Linux Kernel                      Download The CDP module, which lies below buffer cache, records every write request to the Host Disk (to which CDP is to be provided) and timestamp these IO events. It sends these write requests to both the Host Disk and CDP Repository Disk. Thus CDP Repository holds mirror copy of the data on Host Disk ensuring Physical Data Protection. The timestamps of the data blocks are stored on CDP Repository Disk. On data corruption or disk failure, the System Administrator specifies the time at which data is to be restored. Using the time stamped blocks on the CDP Repository disk we can rollback at the specified time and restore the data to obtain the Any Point In Time image. This ensures Logical Data Protection. 參考文獻 1. Block Based CDP module for linux kernel, http://sourceforge.net/projects/q-phoenix; http://ekalavya.it.iitb.ac.in/rhs/summary.do 2.張冬. 大話存儲Ⅱ—存儲系統架構與底層原理極限剖析[M], 2011:466-470

二、相關:linux設備管理

Linux是一種類Unix系統,Unix的一個基本特點是“一切皆為文件”,它抽象了設備的處理,將所有的硬件設備都像普通文件一樣看待,也就是說硬件可以跟普通文件一樣來打開、關閉和讀寫。 系統中的設備都用一個設備特殊文件代表,叫做設備文件,設備文件又分為Block(塊)型設備文件、Character(字符)型設備文件和Socket(網絡插件)型設備文件。Block設備文件常常指定哪些需要以塊(如512字節)的方式寫入的設備,比如IDE硬盤、SCSI硬盤、光驅等。 而Character型設備文件常指定直接讀寫,沒有緩沖區的設備,比如並口、虛擬控制台等。Socket(網絡插件)型設備文件指定的是網絡設備訪問的BSD socket 接口。 #ls -l /dev/hda /dev/video0 /dev/log
brw-rw—- 1 root disk 3, 0 Sep 15 2003 /dev/hda
srw-rw-rw- 1 root root 0 Jun 3 16:55 /dev/log
crw——- 1 root root 81, 0 Sep 15 2003 /dev/video0 上面顯示的是三種設備文件,注意它們最前面的字符,Block型設備為b,Character型設備為c,Socket設備為s。 由此可以看出,設備文件都放在/dev目錄下,比如硬盤就是用/dev/hd*來表示,/dev/hda表示第一個IDE接口的主設備,/dev/hda1表示第一個硬盤上的第一個分區;而/dev/hdc 表示第二個IDE接口的主設備。可以使用下面命令: #dd if=/dev/hda of=/root/a.img bs=446 count=1 把第一個硬盤上前446個字節的MBR信息導入到a.img文件中。 對於Block和Character型設備,使用主(Major)和輔(minor)設備編號來描述設備。主設備編號來表示某種驅動程序,同一個設備驅動程序模塊所控制的所有設備都有一個共同的主設備編號,而輔設備編號用於區分該控制器下不同的設備,比如,/dev/hda1(block 3/1)、/dev/hda2(block 3/2 )和/dev/hda3( block3/3 )都代表著同一塊硬盤的三個分區,他們的主設備號都是3,輔設備號分別為1、2、3。 這些設備特殊文件用mknod命令來創建: # mknod harddisk b 3 0

我們就在當前位置創建出一個與 /dev/hda一樣的、可以訪問第一個IDE設備主硬盤的文件,文件名叫做harddisk。

使用下面命令可以查看設備編號:

#file /dev/hda/dev/hda: block special (3/0) 其中Block代表/dev/hda是系統的Block型(塊型)設備文件,它的主設備編號為3,輔設備編號為0。 #ls -l /dev/hda /dev/hdb
brw-rw—- 1 root disk 3, 0 Sep 15 2003 /dev/hda
brw-rw—- 1 root disk 3, 64 Sep 15 2003 /dev/hdb

使用ls -l也可以看到設備編號,/dev/hdb代表第一個IDE接口的從設備(Slave)也是Block設備,編號為(3/64),還有另外一種設備文件是/dev/tty*。使用如下命令:

#echo "hello tty1" > /dev/tty1

將字符串“hello tty1”輸出到/dev/tty1代表的第一個虛擬控制台上,此時按“Alt + F1”可以看到該字符出現在屏幕上,這個特殊的文件就代表著我們的第一虛擬控制台。

#file /dev/tty1/dev/tty1: character special (4/1)

由上可以看到,它的類型為Character 型(字符型)設備文件,主設備號為4,輔設備號為1。同樣,/dev/tty2代表著第二個虛擬控制台,是Character設備,編號為 (4/2)。

Copyright © Linux教程網 All Rights Reserved