当前位置: 首页 > Linux

Btrfs文件系统的子卷和快照

时间:2023-04-06 22:44:12 Linux

大多数文件系统都是在磁盘上创建文件系统,然后挂载到系统中来完成工作。但是对于Btrfs来说,除了在格式化和挂载时指定不同的参数外,还支持很多其他的功能,比如管理多个硬盘,支持LVM和RAID等,具体可以参考其官方文档或者Linux常用比较Btrfs下的文件系统是Linux下大家公认的将取代ext4的下一代文件系统,功能非常强大。本文不会介绍Btrfs的原理,也不会介绍Btrfs的所有功能,只是选择subvolume和snapshot这两个特性进行介绍。本文所有例子通过准备环境在ubuntu-server-x86_6416.04下执行首先创建一个虚拟硬盘,然后格式化成Btrfs,最后挂载到目录/mnt/btrfs#为了简单起见,只有一个硬盘disk用于测试(Btrfs可以管理多个硬盘或分区)。#创建一个新文件来虚拟一个硬盘dev@ubuntu:~$fallocate-l512M/tmp/btrfs.img#在上面创建一个Btrfs文件系统dev@ubuntu:~$mkfs.btrfs/tmp/btrfs.imgbtrfs-progsv4.4Seehttp://btrfs.wiki.kernel.org了解更多信息。标签:(空)UUID:fd5efcd3-adc2-406b-a684-e6c87dde99a1节点大小:16384扇区大小:4096文件系统大小:512.00MiBBlock组配置文件:数据:单个8.00MiB元数据:DUP40.00MiB系统:DUP12.00MiBSSD检测到:noIncompat功能:extref,skinny-metadata设备数量:1设备:IDSIZEPATH1512.00MiB/tmp/btrfs.img#Createfolderandmountdev@ubuntu:~$sudomkdir/mnt/btrfsdev@ubuntu:~$sudomount/tmp/btrfs.img/mnt/btrfs#修改权限,这样后面的操作不需要sudodev@ubuntu:~$sudochmod777/mnt/btrfssubvolume即可将subvolume理解为虚拟设备,由Btrfs管理。创建之后,它会自动挂载到Btrfs文件系统中的一个目录中,所以我们在文件系统中看到的subvolume是一个目录,只不过是一个具有挂载点一些属性的特殊目录。新建的Btrfs文件系统会创建一个默认的subvolume,路径为“/”,即rootsubvolume,ID为5(别名0),是一个预设了ID和目录的subvolume。#这里从挂载参数"subvolid=5,subvol=/"可以看出,#默认根子卷ID为5,路径为"/"dev@debian:/mnt/btrfs$mount|grepbtrfs/dev/loop1on/mnt/btrfstypebtrfs(rw,relatime,space_cache,subvolid=5,subvol=/)创建子卷这里我们将使用Btrfs提供的工具新建两个子卷和两个文件夹,我们来看看它们之间dev@ubuntu的区别:~$cd/mnt/btrfs#btrfs命令是Btrfs提供的一个应用层工具,可以用来管理Btrfs#这里依次创建两个子卷,将两个子卷创建完成后自动生成在当前目录下。A目录dev@ubuntu:/mnt/btrfs$btrfssubvolumecreatesub1Createsubvolume'./sub1'dev@ubuntu:/mnt/btrfs$btrfssubvolumecreatesub2Createsubvolume'./sub2'#创建两个文件夹dev@ubuntu:/mnt/btrfs$mkdirdir1dir2#分别在sub1,sub2,dir1创建文件dev@ubuntu:/mnt/btrfs$touchdir1/dir1-01.txtdev@ubuntu:/mnt/btrfs$touchsub1/sub1-01.txtdev@ubuntu:/mnt/btrfs$touchsub2/sub2-01.txt#最后看看目录结构,sub1和dir1好像没有什么区别?dev@ubuntu:/mnt/btrfs$tree.├──dir1│└──dir1-01.txt├──dir2├──sub1│└──sub1-01.txt└──sub2└──sub2-01.txt但是,由于每个subvolume都是一个独立的虚拟设备,所以不能跨subvolumes建立硬链接#虽然sub1和sub2属于同一个Btrfs文件系统,并且在一个物理硬盘上#但是因为属于不同的subvolume,放置dev@ubuntu:/mnt/btrfs$ln./sub1/sub1-01.txt./sub2/ln:未能创建硬链接'./sub2/sub1-01.txt'=>'./sub1/sub1-01.txt':Invalidcross-devicelinkDeletingsubvolumesubvolume不能用rm删除,只能用btrfs命令#普通目录可以用rm删除dev@ubuntu:/mnt/btrfs$rm-rdir2#Failedtodeletesubvolumethroughrmcommanddev@ubuntu:/mnt/btrfs$sudorm-rsub2rm:cannotremove'sub2':Operationnotpermitted#需要通过btrfs命令删除#删除sub2成功(即使subvolume中有文件,也可以删除)dev@ubuntu:/mnt/btrfs$sudobtrfssubvolumedelsub2Deletesubvolume(no-commit):'/mnt/btrfs/sub2'dev@ubuntu:/mnt/btrfs$tree.├──dir1│└──dir1-01.txt└──sub1└──sub1-01.txt删除的时候可以看到这样的提示:Deletesubvolume(no-commit),也就是说subvolume有被删除。但是还没有提交,也就是说在内存中已经生效了,但是磁盘上的内容还没有被删除,也就是说如果这时候系统崩溃了,subvolume可能会回来。btrfs的优点是删除速度很快,不会影响使用,缺点是在后台commit过程中系统可能会挂掉,导致commit失败。为了保证subvolume中的数据真正从磁盘中删除,可以在删除subvolume的时候指定-c参数,这样btrfs命令会等待提交完成再返回dev@ubuntu:/mnt/btrfs$sudobtrfssubvolumedel-csub2Deletesubvolume(commit):'/mnt/btrfs/sub2'mountsubvolume通过mount命令可以直接挂载子卷,与挂载其他设备没有区别。具体的挂载参数可以参考文档#创建挂载的mount点击目录dev@ubuntu:/mnt/btrfs$sudomkdir/mnt/sub1#首先查看iddev@debian:/mnt/btrfs$sudobtrfssubvolumelist/mnt/btrfs/ID256gen9toplevel5pathsub1#通过-o参数指定要挂载的子卷ID#通过path挂载效果相同:sudomount-osubvol=/sub1/tmp/btrfs.img/mnt/sub1/dev@debian:/mnt/btrfs$sudomount-osubvolid=256/tmp/btrfs.img/mnt/sub1/dev@debian:/mnt/btrfs$tree/mnt/sub1//mnt/sub1/└──sub1-01.txttosetsubvolumeread-onlysubvolume可以设置为只读状态#可以通过btrfs属性查看和修改subvolume的只读状态#默认情况下,subvolume的只读属性为false,即允许写入dev@ubuntu:/mnt/btrfs$btrfspropertyget-ts./sub1/ro=false#设置sub1的只读属性为truedev@ubuntu:/mnt/btrfs$btrfspropertyset-ts./sub1/rotruedev@ubuntu:/mnt/btrfs$btrfspropertyget-ts./sub1ro=true#写入文件失败,提示读取文件系统-只有开发者@ubuntu:/mnt/btrfs$touch./sub1/sub1-02.txttouch:cannottouch'./sub1/sub1-02.txt':Read-onlyfilesystem#把sub1的状态改回来,以免影响后续测试dev@ubuntu:/mnt/btrfs$btrfspropertyset-ts./sub1/rofalsenapshot可以做基于subvolume的快照,注意几点:默认情况下,subvolumes的快照是可写的snapshot是特殊的subvolumessubvolume的属性,所以也可以通过mount挂载快照,也可以通过btrfsproperty命令设置只读属性。由于快照的本质是一个子卷,所以可以在快照上做一个快照。在subvolume上做快照后,subvolume和快照中的所有文件都会共享,只有文件更新时才会触发COW(copyonwrite),所以创建快照速度很快,几乎不花时间,而且Btrfs的COW机制非常高效,即使多个快照共享一个文件,更新这个文件也和更新一个普通文件的速度差不多。如果你使用过git,你可以很容易地理解Btrfs中的快照。你可以把subvolume理解为git中的master分支,而snapshot是从mastercheckout出来的新分支,所以snapshot和git中的branch有相似的特点:几乎没有创建快照的开销。您可以根据快照创建快照。当前快照中的修改不会影响其他快照。可以删除快照。当然,subvolume也可以像git中的master一样删除。创建快照#创建基于根子卷的快照#默认情况下,快照是可写的。如果要创建只读快照,需要添加-r参数dev@debian:/mnt/btrfs$sudobtrfssubvolumesnapshot././snap-rootCreateasnapshotof'./in'./snap-root'#创建完成后可以看到我们已经有了两个subvolumedev@debian:/mnt/btrfs$sudobtrfssubvolumelist./ID256gen11toplevel5pathsub1ID257gen13toplevel5pathsnap-root#我们可以只指定快照dev@debian:/mnt/btrfs$sudobtrfssubvolumelist-s./ID257通过指定-s参数gen10cgen10toplevel5otime2017-03-0521:46:03pathsnap-root#再看snapshotsnap-root里面的文件,可以看到dir1和后面的文件,#但是看不到sub1下面的文件是因为sub1是子卷,#制作的时候子卷的快照,其中的子卷不会被作为快照dev@debian:/mnt/btrfs$tree./snap-root./snap-root├──dir1│└──dir1-01.txt└──sub1#创建sub1的快照,可以看到sub1中的文件出现在快照中dev@debian:/mnt/btrfs$sudobtrfssubvolumesnapshot./sub1/./snap-sub1创建'./sub1/'in'./snap-sub1'#然后在sub1下创建一个文件和它的快照snap-sub1,#会发现它们之间不受影响dev@debian:/mnt/btrfs$touchsnap-sub1/snap-sub1-01.txtdev@debian:/mnt/btrfs$touchsub1/sub1-02.txtdev@debian:/mnt/btrfs$tree.├──dir1│└──dir1-01.txt├──snap-root│├──dir1││└──dir1-01.txt│└──sub1├──snap-sub1│├──snap-sub1-01.txt│└──sub1-01.txt└──sub1├──sub1-01.txt└──sub1-02.txt删除删除快照和删除子卷一样,没有区别/mnt/btrfs$sudobtrfssubvolumedelsnap-sub1Deletesubvolume(no-commit):'/mnt/btrfs/snap-sub1'dev@debian:/mnt/btrfs$tree.├──dir1│└──dir1-01.txt└──sub1├──sub1-01.txt└──sub1-02.txtdefaultsubvolume可以设置Btrfs分区的默认子卷,即磁盘挂载时,分区中只有指定的子卷对用户可见看下面的例子:#查看sub1的IDdev@debian:/mnt/btrfs$sudobtrfssubvolumelist./ID256gen14toplevel5pathsub1#设置sub1为当前Btrfs文件系统的默认subvolumedev@debian:/mnt/btrfs$sudobtrfssubvolumeset-default256/mnt/btrfs/#重新挂载虚拟硬盘到新目录dev@debian:/mnt/btrfs$sudomkdir/mnt/btrfs1dev@debian:/mnt/btrfs$sudomount/tmp/btrfs.img/mnt/btrfs1/#这里只能看到sub1dev@debian:/mnt/btrfs$tree/mnt/btrfs1/mnt/btrfs1├──sub1-01.txt└──sub1-02.txt#因为Btrfs原来的默认子卷是根子卷,#它的ID是5(也可以用0来标识),#所以我们可以通过同样的命令把默认子卷改回dev@debian:/mnt/btrfs$sudobtrfssubvolumeset-default0/mnt/btrfs/defaultsubvolume有什么用?使用snapshot和defaultsubvolume,在不同系统版本之间切换非常方便。比如系统安装在子卷下,在做危险操作时,先在子卷的基础上做快照A。如果操作成功,则什么都不做(或删除A),继续使用原来的子卷。A不删除也没关系。多一张快照不会占用那里的空间。如果操作失败,您可以将A设置为默认子卷。并删除原来的subvolume,相当于系统回滚。有了这样的功能,linux中的每一个操作都可以回滚,而且可以养成修改操作前先快照的习惯,就不用担心rm误删文件了。有些发行版已经有类似的功能,比如ubuntu,它结合了安装工具(apt)和Btrfs,在安装软件前自动快照,然后安装软件。如果成功,则删除新快照。如果失败,则修改defaultsubvolume为新的快照,删除原快照,对系统无影响,所有操作对用户透明。随着Btrfs的成熟和流行,相信它会改变我们使用Linux的一些习惯。结语Btrfs的功能太多,需要在使用的过程中去熟悉。本文仅简单介绍子卷和快照。不涉及子卷的增量备份和磁盘配额。下次有时间我会继续这部分。参考新一代Linux文件系统btrfs简介BtrfsMainPageBtrfs:Subvolumesandsnapshots