已挂载文件系统的LVM快照

7
我希望能够使用LVM在Linux系统中以编程方式制作一个现有文件系统的快照,但不想卸载该文件系统,因为我有很多文件已经打开(最常见的情况是我有一个繁忙的桌面和许多程序)。由于内核缓冲区和一般文件系统活动的原因,磁盘上的数据可能处于某种更或多或少未定义的状态。是否有任何方法可以“原子”卸载一个文件系统,制作LVM快照并将其重新挂载?如果操作系统在执行此任务时阻止所有活动几秒钟,那么这将是可以接受的。或者可能是某种原子“同步+快照”?内核调用?我不知道这是否可能...

1
我曾经在LVM邮件列表上待了一段时间,我记得文件系统应该有钩子可以被调用来强制文件系统进行检查点操作(即设置所有日志条目以播放日志文件系统),就在LVM快照操作之前。这将确保快照中的文件系统本身至少处于一致状态。 - Omnifarious
6个回答

12

对于大多数Linux文件系统,您不必做任何事情。它应该可以在您不做任何努力的情况下正常工作。快照命令本身会查找使用正在进行快照的卷的已挂载文件系统,并调用一个特殊的钩子来以一致、可挂载的状态检查点它们,并原子地进行快照。

较旧版本的LVM附带了一组VFS锁定补丁,这些补丁将修补各种文件系统,使它们可以为快照进行检查点。但是,在新的内核中,这应该已经内置在大多数Linux文件系统中。

这个有关快照的介绍也这样声称。

进一步的研究表明,在2.6系列内核中,ext系列的文件系统都应该支持此功能。ReiserFS 也可能支持该功能。如果我了解btrfs的开发者,那么它也可能支持该功能。


当然,如果你正在对btrfs分区进行LVM快照,那么你可能有些傻。Btrfs比LVM更好地处理了所有这些问题。而且,由于其工作方式,btrfs不需要任何检查点挂钩。要么你得到超级块指向新的根,要么你没有。当然,它可能确实有这样的挂钩,但几乎是多余的。 - Omnifarious

5
有没有一种“原子”卸载文件系统、创建 LVM 快照并重新挂载的方法?即使文件系统不在 LVM 卷上,也可以对已挂载的文件系统进行快照。如果文件系统在 LVM 上,或者它具有内置的快照功能(例如 btrfs 或 ZFS),则应使用这些功能。

以下说明相当低级,但如果您想要快照一个不在 LVM 卷上的文件系统,并且无法将其移动到新的 LVM 卷中,则可能会很有用。但是,它们不适合胆小的人:如果您犯了一个错误,可能会损坏文件系统。请务必查阅官方文档dmsetup手册,三次检查您正在运行的命令,并备份

Linux 内核有一个称为 Device Mapper 的强大工具,可以创建作为其他块设备“视图”的块设备,当然还包括快照。它也是 LVM 在后台执行重要操作的工具。

在下面的示例中,我们假设要对位于/dev/sda2上的 ext4 文件系统 /home 进行快照。

首先,找到分区所挂载的设备映射器设备的名称:

# mount | grep home
/dev/mapper/home on /home type ext4 (rw,relatime,data=ordered)

在这里,设备映射器设备名称为home。如果块设备的路径不以/dev/mapper/开头,则需要创建一个设备映射器设备,并重新挂载文件系统以使用该设备而不是HDD分区。您只需要执行此操作一次。

# dmsetup create home --table "0 $(blockdev --getsz /dev/sda2) linear /dev/sda2 0"
# umount /home
# mount -t ext4 /dev/mapper/home /home

接下来,获取块设备的设备映射表:

# dmsetup table home
home: 0 3864024960 linear 9:2 0

您的数字可能会有所不同。设备目标应为linear;如果您的设备目标不是这样,您可能需要考虑特殊情况。如果最后一个数字(起始偏移量)不是0,则需要创建一个中间块设备(具有与当前设备相同的表),并将其用作基础,而不是/dev/sda2
在上面的示例中,home使用带有linear目标的单个条目表。您需要用一个新的表替换这个表,该表使用snapshot目标。
设备映射器提供了三个快照目标:
  • 快照目标snapshot,它保存对指定COW设备的写入。(请注意,即使它被称为快照,术语是误导性的,因为快照将是可写的,但底层设备将保持不变。)

  • 快照源目标snapshot-origin,它将写入发送到底层设备,但也将覆盖写入的旧数据发送到指定的COW设备。

通常,您会使home成为snapshot-origin目标,然后在其上创建一些snapshot目标。这是LVM所做的。但是,更简单的方法是直接创建一个snapshot目标,这就是我将在下面展示的内容。
无论您选择哪种方法,都不应该写入底层设备(/dev/sda2),否则快照将看到文件系统的损坏视图。因此,作为预防措施,您应将底层块设备标记为只读。
# blockdev --setro /dev/sda2

这不会影响由设备映射支持的设备,因此如果您已经将/home重新挂载到/dev/mapper/home上,则不应该有明显的影响。

接下来,您需要准备COW设备,它将存储自快照以来的更改。这必须是一个块设备,但可以由稀疏文件支持。如果您想使用32GB的稀疏文件:

# dd if=/dev/zero bs=1M count=0 seek=32768 of=/home_cow
# losetup --find --show /home_cow
/dev/loop0

显然,稀疏文件不应该在你正在快照的文件系统上 :)
现在你可以重新加载设备表并将其变成一个快照设备:
# dmsetup suspend home && \
  dmsetup reload home --table \
    "0 $(blockdev --getsz /dev/sda2) snapshot /dev/sda2 /dev/loop0 PO 8" && \
  dmsetup resume home

如果成功,现在对/home的新写入应该会记录在/home_cow文件中,而不是写入/dev/sda2。请确保监视COW文件的大小以及其所在的文件系统的可用空间,以避免COW空间不足。
一旦您不再需要快照,可以合并它(将COW文件中的更改永久提交到底层设备)或丢弃它。
  • To merge it:

    1. replace the table with a snapshot-merge target instead of a snapshot target:

      # dmsetup suspend home && \
        dmsetup reload home --table \
          "0 $(blockdev --getsz /dev/sda2) snapshot-merge /dev/sda2 /dev/loop0 P 8" && \
        dmsetup resume home
      
    2. Next, monitor the status of the merge until all non-metadata blocks are merged:

      # watch dmsetup status home
      ...
      0 3864024960 snapshot-merge 281688/2097152 1104
      

      Note the 3 numbers at the end (X/Y Z). The merge is complete when X = Z.

    3. Next, replace the table with a linear target again:

      # dmsetup suspend home && \
        dmsetup reload home --table \
          "0 $(blockdev --getsz /dev/sda2) linear /dev/sda2 0" && \
        dmsetup resume home
      
    4. Now you can dismantle the loop device:

      # losetup -d /dev/loop0
      
    5. Finally, you can delete the COW file.

      # rm /home_cow
      
  • To discard the snapshot, unmount /home, follow steps 3-5 above, and remount /home. Although Device Mapper will allow you to do this without unmounting /home, it doesn't make sense (since the running programs' state in memory won't correspond to the filesystem state any more), and it will likely corrupt your filesystem.


1
当我读到“即使文件系统不在LVM卷上”时,我想,“这将是一些很好的devicemapper黑魔法!”太棒了!不过有一个问题——这个过程会触发相同的钩子来确保快照处于一致状态吗?我认为它必须是blockdev --setro /dev/sda2调用的一部分。 - liori
你需要创建一个设备映射器(device mapper)设备[...]. 你只需要执行一次就可以了。如何才能让它在重启后也能持久化呢?建议的方式每次重启后都需要重新处理... - remram
如果最后一个数字(起始偏移量)不为0,则需要创建一个中间块设备。您能否详细说明为什么需要这样做?如果不这样做会发生什么? - jurez
@jurez 因为通常 DM 目标(包括 snapshotsnapshot-origin)不会针对它们所基于的设备提供起始参数。但是,linear 目标可以提供。实际上,您需要先切掉您需要处理的磁盘部分(在该示例中为 sda2)。在实践中,我认为这永远不会成为问题,因为当您挂载一个分区时,您将使用整个分区的数据。 - Vladimir Panteleev
这个回答太棒了!非常感谢!找到关于如何使用磁盘映射器的好资源真的很难。如果可以的话,我会给你点赞很多次的! - undefined
显示剩余3条评论

4
我知道在RedHat Enterprise、Fedora和CentOS中,ext3和ext4在创建LVM快照时会自动检查点。这意味着挂载快照永远不会有问题,因为它总是干净的。
我相信XFS也有同样的支持。我不确定其他文件系统是否也有类似的支持。

1
"当创建 LVM 快照时,RedHat Enterprise、Fedora 和 CentOS 会自动检查点。是否有任何文档证明这一点?这个特性是特定于 RH 吗?" - Benoît
1
好的,这其实是相当新的 http://kernelnewbies.org/Linux_2_6_29#head-b6c330f9e6d252b514138f042ac9b01e9d4170ca! - Benoît
"RedHat Enterprise、Fedora和CentOS" - 那将是它们的哪个版本? - 0x89
当我在一个特定版本的系统上,升级不在我的控制范围内时,这并没有太大的帮助,我只想知道该功能是否在该系统上受支持。 - 0x89
@0x89:进行LVM快照。将其挂载。如果需要进行日志恢复,则您的操作系统和文件系统不会自动检查点。 - Zan Lynx
显示剩余2条评论

3

这取决于您使用的文件系统。如果使用XFS文件系统,您可以使用xfs_freeze -f命令同步和冻结文件系统,然后使用xfs_freeze -u命令重新激活它,这样您就可以从冻结的卷创建快照,这应该是一个安全状态。


1

我不确定这是否对您有帮助,但是您可以将文件系统重新挂载为只读。使用mount -o remount,ro /lvm(或类似命令)即可实现。 在完成快照后,可以使用mount -o remount,rw /lvm重新挂载为读写模式。


只有在没有文件被打开进行写入时才能实现这一点......使用桌面电脑时,有很多文件,即使应用程序并不一直在写入它们;例如 Firefox 和其他应用程序的 SQLite 数据库。 - liori

-1

只要你不在任何类型的专业环境中工作,文件系统损坏是“高度不可能”的。否则,你将会面对现实,你可能会试图责怪“位烂”或“硬件”或其他任何东西,但这归根结底是因为你没有负责任。 正确定义的冻结/解冻(如前面提到的,在数据库环境之外)就足够了。对于数据库,你仍然无法获得完整的事务备份,如果你认为还原时回滚一些事务的备份就可以了:请看起始句子。 根据活动情况,如果需要这个备份,你可能会增加另外5-10分钟的停机时间。 我们大多数人都能轻松承担这一点,但这不能成为普遍建议。 诚实面对缺点吧,伙计们。


谢谢您的留言。但是,请不要将评论添加为单独的答案。这就是StackExchange平台中评论的作用。我建议您将有关文件系统损坏的部分作为评论添加到Vladimir Panteleev的答案中(我假设您指的是他的答案),而有关数据库的部分最好作为对问题本身的评论。 - liori

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接