前言:
最近对快照感兴趣, 初步分析了下dm-thin-provision的代码, 初步感觉实现方式很不错, 但不足的是性能比较差, metadata写了数据过多.
但整体实现方式还是值得参考的.
dm-thin-provision简介
thin-provision是device mapper的一种, 可以完成存储设备的特定映射, 这种设备有下面的特点:
(1)允许多个虚拟设备存储在相同的数据卷中,从而达到共享数据,节省空间的目的;
(2)支持任意深度的快照。之前的实现的性能为O(n),新的实现通过一个单独的数据避免了性能随快照深度的增加而降低。
(3)支持元数据存储到单独的设备上。这样就可以将元数据放到镜像设备或者更快的SSD上。
创建thin provision
有两种方法创建dm thin-provision, 一种是通过dmsetup工具创建, 另外一种是通过lvm管理工具创建.
通过dmsetup创建dm-thin-provision
a: 创建pool
# dmsetup create pool \
--table "0 20971520 thin-pool $metadata_dev $data_dev \
$data_block_size $low_water_mark"
# dmsetup create yy_thin_pool --table '0 409600 thin-pool /dev/loop6 /dev/loop7 128 0'
# dmsetup table /dev/mapper/yy_thin_pool
0 409600 thin-pool 7:6 7:7 128 0 0
b: 创建thin volume
# dmsetup message /dev/mapper/yy_thin_pool 0 "create_thin 0"
# dmsetup table /dev/mapper/thin
0 40960 thin 253:3 0
c: 创建快照snapshot
# dmsetup suspend /dev/mapper/thin
# dmsetup message /dev/mapper/yy_thin_pool 0 "create_snap 1 0"
# dmsetup resume /dev/mapper/thin
# dmsetup create snap --table "0 40960 thin /dev/mapper/yy_thin_pool 1"
通过lvm创建thin provision
a: 创建thin pool
# dd if=/dev/zero of=lvm0.img bs=1024k count=256
# losetup /dev/loop7 lvm0.img
# pvcreate /dev/loop7
Physical volume "/dev/loop7" successfully created
# vgcreate vg_test /dev/loop7
Volume group "vg_test" successfully created
# lvcreate -L 200M -T vg_test/mythinpool
Logical volume "lvol0" created
Logical volume "mythinpool" created
# ls /dev/mapper/* |grep mythin
/dev/mapper/vg_test-mythinpool
/dev/mapper/vg_test-mythinpool_tdata
/dev/mapper/vg_test-mythinpool_tmeta
/dev/mapper/vg_test-mythinpool-tpool
b: 创建thin
# lvcreate -T vg_test/mythinpool -V 300M -n lvol1
Logical volume "lvol1" created
c: 创建snapshot
# lvcreate -s --name mysnapshot1 vg_test/lvol1
Logical volume "mysnapshot1" created
dm-thin-provision架构
thin-provision记录了每次写的block的映射关系, 具体对应关系放到了metadata dev中, 每个block介于64k 和1G中间, 创建pool的时候传入, 在pool_ctr中有检查
/*
* The block size of the device holding pool data must be
* between 64KB and 1GB.
*/
#define DATA_DEV_BLOCK_SIZE_MIN_SECTORS (64 * 1024 >> SECTOR_SHIFT)
#define DATA_DEV_BLOCK_SIZE_MAX_SECTORS (1024 * 1024 * 1024 >> SECTOR_SHIFT)
而无论读写, 首先会有一个从metadata中找block的过程, 例如:
thin_bio_map-> dm_thin_find_block. 如果是读命令, 结果却发现找不到block的情况, 这种情况就说明之前根本没有写入数据,所以应该返回全0.
如果是写命令, 没有找到block, 就可以往metadata的树中插入新的项目, 当下次写命令查找时能返回正确的block信息.
snapshot和对应的thin一样, 也是一种thin device, 只不过这种thin device是有一部分能共享. 当对某个thin创建snapshot时, 需要怎么来处理呢?
a: 创建snapshot也就是创建了一个新的thin_id的设备, 只不过有一个time值记录当前的snapshotted_time, 如果找到的block的时间小于当前设备的time, 则说明是共享的,代表当前block是比较老的版本.
b: 如果是共享的, 其实已经找到了block号,
c: 如果不是共享的,则需要重新创建一个block, 并于当前bio进行map, 同时写入map的结果到metadata dev中保存.
关键的数据结构
pool ,代表最开始创建的pool
Thin_c, 代表已创建好的thin dev