我对 LVM 快照的理解是:当源上的某个块发生更改时,该块首先被复制到快照(在更改之前)。然后,该块会像平常一样在源上进行更改。
因此,从理论上讲,当第一次创建快照时,它应该不包含任何内容。然后,随着原点发生变化,这些块开始填充快照。
但是,如果出于测试目的,我创建了一个 1G 的小型 LV,并在其中放置了几个文件;然后我创建了一个 200MB 的快照。正如预期的那样,lvs 显示快照的 LSize 为 200M,原始的 LSize 为 1G。但是当我挂载快照卷时,df 显示它的大小为 1G。当我检查其内容时,我发现它包含原始卷中的所有内容,即使原始文件没有更改。
这是为什么?我假设“mount”命令中有一些逻辑可以对原始 LV 和快照 LV 进行比较?有人能解释一下这是如何工作的吗?如果我查看每个卷(原始卷和快照卷)上文件的 inode 编号,它们是不同的(正如预期的那样,因为每个卷都是自己独特的文件系统),但我假设快照使用某种“指针”来引用原始卷上未更改的块。
按照同样的思路,我假设如果我将快照逻辑卷本身复制到另一个位置,我将获得原始文件的子集 - 仅那些已更改的文件。 ... 但是,如果我首先安装快照文件系统,然后执行文件系统级复制 (cp),我将获得原始文件上的所有内容,就像创建快照时一样。对吗?
答案1
LVM 快照的工作原理是,在快照卷中保留已更改块及其内容的列表,同时将所有读取未更改数据的请求传递到底层块设备。所有这些智能都内置在内核中的 LVM 中,并且mount
对此一无所知。至于任何事物就用户空间而言,有两个可用的块设备,它们的大小相同(在您的示例中为 1G)。除了必须处理该问题的 dm(设备映射器)系统部分外,其他人都无需关心一个是 LVM 原始卷,另一个是快照。
200MB 大小的快照是它在超出其接缝范围并将数据块散落到各处之前可以存储的更改数据量。
如果您复制快照卷(作为块设备或通过复制其中的文件),无论哪种方式,您都将获得完整的内容。
所有这些都有一个警告:你能进入快照 LV 中的元数据并执行“时髦”的事情,例如高效的设备级 rsync。我提到这一点是因为我曾写过lvm同步就是为了做到这一点,从你的问题的语气来看,你可能正在追求这种功能。
答案2
快照是 LVM 子系统的一部分,数据块是文件系统下方的抽象层。
快照是原始卷的完整副本,因此当您安装时其大小也相同。两者均为 1 GB。
除了快照会做一些小把戏,这样您实际上就不必完全复制整个 1 GB。事实上没有任何内容被复制在拍摄快照时,这就是为什么它非常快并且最初几乎不占用任何空间的原因。
相反,快照仅在原始数据被修改时才开始复制数据(写时复制)但只有“即将修改”只复制原始数据(块),不复制其他内容。快照的 200 MB 空间是您为这些副本保留的空间量。换句话说,您可以在快照中跟踪 200 MB 的修改。
诀窍在于,快照一开始是指向原始数据块的指针集合。原始卷中的每次更改都会触发将原始数据块复制到 COW 表(慢慢填满为此预留的 200 MB)并相应地更新指针。读取快照时,将跟踪这些指针,然后通过跟踪那里的指针返回原始卷中未修改的数据,或者跟踪指向 COW 表中复制块的指针。