1 Btrfs简介
Btrfs 被称为是下一代 Linux 文件系统。近年来 ext2/3 遇到越来越多的扩展性问题,在期待 ext4 的同时,人们发现了 btrfs,据说它采用了很多先进的文件系统设计,不仅解决了 ext2/3 的扩展性问题,还让人们看到了下一代文件系统所具有的许多其他特性。
在 btrfs 的主页上看到 btrfs 的特性列表。首先是扩展性 (scalability) 相关的特性,btrfs 最重要的设计目标是应对大型机器对文件系统的扩展性要求。 Extent,B-Tree 和动态 inode 创建等特性保证了 btrfs 在大型机器上仍有卓越的表现,其整体性能而不会随着系统容量的增加而降低。其次是数据一致性 (data integrity) 相关的特性。系统面临不可预料的硬件故障,Btrfs 采用 COW 事务技术来保证文件系统的一致性。 btrfs 还支持 checksum,避免了 silent corrupt 的出现。而传统文件系统则无法做到这一点。第三是和多设备管理相关的特性。 Btrfs 支持创建快照 (snapshot),和克隆 (clone) 。 btrfs 还能够方便的管理多个物理设备,使得传统的卷管理软件变得多余。最后是其他难以归类的特性。这些特性都是比较先进的技术,能够显著提高文件系统的时间 / 空间性能,包括延迟分配,小文件的存储优化,目录索引等。
2 Btrfs使用说明
2.1. 文件系统的建立
2.1.1在虚拟机中添加一个硬盘(略)
2.1.2查看硬盘是否添加成功
通过命令:# fdisk -l 查看硬盘信息,可以看到新添加的硬盘属性,这里假设新添加的硬盘名为:sdd1。
通过命令:# fdisk /dev/sdd1(具体磁盘名称),可进入分割硬盘模式。
Ø 输入 m 显示所有命令列示。
Ø 输入 p 显示硬盘分割情形。
Ø 输入 a 设定硬盘启动区。
Ø 输入 n 设定新的硬盘分割区。
Ø 输入 e 硬盘为[延伸]分割区(extend)。
Ø 输入 p 硬盘为[主要]分割区(primary)。
Ø 输入 t 改变硬盘分割区属性。
Ø 输入 d 删除硬盘分割区属性。
Ø 输入 q 结束不存入硬盘分割区属性。
Ø 输入 w 结束并写入硬盘分割区属性。
dmesg命令说明如下:
功能说明:显示开机信息。
语 法:dmesg [-cn][-s ]
补充说明:kernel会将开机信息存储在ring buffer中。您若是开机时来不及查看信息,可利用dmesg来查看。开机信息亦保存在/var/log目录中,名称为dmesg的文档里。
参 数:
-c 显示信息后,清除ring buffer中的内容。
-s 预配置为8196,刚好等于ring buffer的大小。
-n 配置记录信息的层级。
2.1.3 对要挂载的硬盘创建磁盘分区
创建磁盘分区步骤举例如下:
# fdisk /dev/sdd1
进入fdisk模式:
Command (m for help):m //查看fdisk命令帮助
Command (m for help):n //创建新分区
Command action:
e extended //输入e为创建扩展分区
p primary partition (1-4) //输入p为创建主分区,这里我们选择p
Partion number(1-4):1 //第一个扩展分区,按需求可以最多分4个主分区
First Cylinder(1-1014,default 1): 1 //第一个主分区起始的磁盘块数,可以选择默认值
Last cylindet or +siza or +sizeM or +sizeK: +1024MB //可以是以MB为单位的数字或者
以磁盘块数,这里我们输入+1024MB表示分区大小为1G
这样我们就创建完一个分区,如果要创建更多分区可以照上面的步骤继续创建。所有分区创建完后用w保存分区。
Command (m for help): w
The partition table has been altered!
保存完成后重启服务器,可以用#fdisk -l 命令检查刚刚所建分区,可以在返回结果中确认/dev/sdb1的信息。
2.1.4 建立文件系统
可以用mkfs.btrfs 命令建立一个 btrfs 格式的文件系统。可以用如下命令在设备 sdd1 上建立一个 btrfs 文件系统.
#mkfs.btrfs /dev/sdd1
[root@localhost btrfs]# mkfs.btrfs /dev/sdd1
WARNING! - Btrfs Btrfs v0.19 IS EXPERIMENTAL WARNING! - see http://btrfs.wiki.kernel.org before using
fs created label (null) on /dev/sdd1 nodesize 4096 leafsize 4096 sectorsize 4096 size 7.99GB Btrfs Btrfs v0.19 |
可以看到在建立btrfs系统时出现了WARNING,这是因为在我使用的linux版本中btrfs还属于一个实验性的产品,并未完全成熟,不过对我们影响不大,可以忽略。
2.1.5 挂载文件
首先通过mkdir创建一个挂载文件点
# mkdir mybtrfs
然后通过mount命令挂载
#mount -t btrds /dev/sdd1 mybtrfs
[root@localhost mnt]# pwd /mnt [root@localhost mnt]# mkdir mybtrfs [root@localhost mnt]# mount -t btrfs /dev/sdd1 /mnt/mybtrfs [root@localhost mnt]# df -T 文件系统 类型 1K-块 已用 可用 已用% 挂载点 /dev/sda1 ext4 18577148 11560744 6072740 66% / tmpfs tmpfs 510984 264 510720 1% /dev/shm /dev/sdb1 ext4 20641404 6161100 13431780 32% /opt /dev/sdd1 btrfs 8379372 56 7512812 1% /mnt/mybtrfs [root@localhost mnt]# |
通过 df –T命令可以看到文件已挂载成功。
为了在每次系统启动时自动挂载新分区,可以修改/etc/fstab文件来进行自动挂载。在文件的末位加入如下一行:
/dev/sdd1 /mnt/mybtrfs btrfs defaults 1 2
这样服务器每次启动都会自动挂载此分区.
至此,btrfs文件系统就OK了,可以通过# df 命令进行查看
2.2 Btrfs操作命令
2.2.1 修改btrfs文件系统的大小
当文件系统建立好之后,您可以修改文件系统的大小。 /dev/sda5 挂载到了 /mnt/mybtrfs下,大小为 8G 。假如您希望只使用其中的 7G,则需要减小当前文件系统的大小,这可以通过如下命令实现:
#btrfsctl -r -1024M /mnt/mybtrfs
[root@localhost mnt]# df -l 文件系统 1K-块 已用 可用 已用% 挂载点 /dev/sda1 18577148 11560744 6072740 66% / tmpfs 510984 264 510720 1% /dev/shm /dev/sdb1 20641404 6161100 13431780 32% /opt /dev/sdd1 8379372 56 7512812 1% /mnt/mybtrfs [root@localhost mnt]# btrfsctl -r -1024M /mnt/mybtrfs operation complete Btrfs Btrfs v0.19 [root@localhost mnt]# df -l 文件系统 1K-块 已用 可用 已用% 挂载点 /dev/sda1 18577148 11560744 6072740 66% / tmpfs 510984 264 510720 1% /dev/shm /dev/sdb1 20641404 6161100 13431780 32% /opt /dev/sdd1 7330796 56 6464236 1% /mnt/mybtrfs [root@localhost mnt]# |
同样的,您可以使用 btrfsctl 命令增加文件系统的大小。
#btrfsctl -r +1024M /mnt/mybtrfs
2.2.2 扫描文件系统
扫描整个btrfs文件系统:
#btrfsctl –a
[root@localhost mnt]# btrfsctl -a Scanning for Btrfs filesystems failed to read /dev/fd0 failed to read /dev/sr0 [root@localhost mnt]# |
扫描指定btrfs文件系统:
#btrfsctl -A /dev/sdd1
[root@localhost mnt]# btrfsctl -A /dev/sdd1 operation complete Btrfs Btrfs v0.19 [root@localhost mnt]# |
2.2.3 整理文件系统
整理一个文件:
#btrfsctl -d 文件
[root@localhost mybtrfs]# pwd /mnt/mybtrfs [root@localhost mybtrfs]# ls test.txt [root@localhost mybtrfs]# btrfsctl -d /mnt/mybtrfs/test.txt operation complete Btrfs Btrfs v0.19 [root@localhost mybtrfs]# |
整理一个目录:
#btrfsctl -d 目录
[root@localhost mnt]# btrfsctl -d /mnt/mybtrfs operation complete Btrfs Btrfs v0.19 [root@localhost mnt]# |
2.2.4 创建/删除 快照(snapshot)
快照是对文件系统某一时刻的完全备份。建立快照之后,对文件系统的修改不会影响快照中的内容。这是非常有用的一种技术。比如数据库备份。假如在时间点 T1,管理员决定对数据库进行备份,那么他必须先停止数据库。备份文件是非常耗时的操作,假如在备份过程中某个应用程序修改了数据库的内容,那么将无法得到一个一致性的备份。因此在备份过程中数据库服务必须停止,对于某些关键应用这是不能允许的。
利用快照,管理员可以在时间点 T1 将数据库停止,对系统建立一个快照。这个过程一般只需要几秒钟,然后就可以立即重新恢复数据库服务。此后在任何时候,管理员都可以对快照的内容进行备份操作,而此时用户对数据库的修改不会影响快照中的内容。当备份完成,管理员便可以删除快照,释放磁盘空间。
快照一般是只读的,当系统支持可写快照,那么这种可写快照便被称为克隆。克隆技术也有很多应用。比如在一个系统中安装好基本的软件,然后为不同的用户做不同的克隆,每个用户使用自己的克隆而不会影响其他用户的磁盘空间。非常类似于虚拟机。
下面的例子中,创建快照 snap1 时系统存在 1 个文件。创建快照之后,对 test 的内容进行修改。再回到 snap1,打开 test 文件,可以看到 test1 的内容依旧是之前的内容。
#btrfsctl -s snap1(快照名) dir
[root@localhost mybtrfs]# btrfsctl -s snap1 /mnt/mybtrfs operation complete Btrfs Btrfs v0.19 [root@localhost mybtrfs]# ls snap1 test.txt [root@localhost mybtrfs]# cat snap1/test.txt This a test! [root@localhost mybtrfs]# vim test.txt [root@localhost mybtrfs]# cat snap1/test.txt This a test! [root@localhost mybtrfs]# |
可以从上面的例子看到,快照 snap1 保存的内容不会被后续的写操作所改变。
同理,可以通过#btrfsctl –D snap(快照名) . 删除快照
[root@localhost mybtrfs]# ls snap text [root@localhost mybtrfs]# btrfsctl -D snap . operation complete Btrfs Btrfs v0.19 [root@localhost mybtrfs]# ls text [root@localhost mybtrfs]# |
2.2.5 创建子卷(subvolume)
Subvolume即是把文件系统的一部分配置为一个完整的子文件系统,称之为 subvolume 。
采用 subvolume,一个大的文件系统可以被划分为多个子文件系统,这些子文件系统共享底层的设备空间,在需要磁盘空间时便从底层设备中分配,类似应用程序调用 malloc() 分配内存一样。可以称之为存储池。这种模型有很多优点,比如可以充分利用 disk 的带宽,可以简化磁盘空间的管理等。
所谓充分利用 disk 的带宽,指文件系统可以并行读写底层的多个 disk,这是因为每个文件系统都可以访问所有的 disk 。传统的文件系统不能共享底层的 disk 设备,无论是物理的还是逻辑的,因此无法做到并行读写。
所谓简化管理,是相对于 LVM 等卷管理软件而言。采用存储池模型,每个文件系统的大小都可以自动调节。而使用 LVM,如果一个文件系统的空间不够了,该文件系统并不能自动使用其他磁盘设备上的空闲空间,而必须使用 LVM 的管理命令手动调节。
Subvolume 可以作为根目录挂载到任意 mount 点。 subvolume 是非常有趣的一个特性,有很多应用。假如管理员只希望某些用户访问文件系统的一部分,比如希望用户只能访问 /var/test/ 下面的所有内容,而不能访问 /var/ 下面其他的内容。那么便可以将 /var/test 做成一个 subvolume 。 /var/test 这个 subvolume 便是一个完整的文件系统,可以用 mount 命令挂载。比如挂载到 /test 目录下,给用户访问 /test 的权限,那么用户便只能访问 /var/test 下面的内容了。
使用 btrfs 命令,用户可以方便的建立 subvolume 。假设 /mnt/mybtrfs 已经挂载到了 btrfs 文件系统,则用户可以在这个文件系统内创建新的 subvolume 。比如建立一个 /sub1 的 subvolume,并 将 sub1 挂载到 /mnt/test 下:
#mkdir /mnt/test
#btrfsctl – S sub1 mnt/mybtrfs
#mount – t btrfs – o subvol=sub1 /dev/sdd1 /mnt/test
[root@localhost mnt]# mkdir /mnt/test [root@localhost mnt]# btrfsctl -S sub1 /mnt/mybtrfs operation complete Btrfs Btrfs v0.19 [root@localhost mnt]# mount -t btrfs -o subvol=sub1 /dev/sdd1 /mnt/test [root@localhost mnt]# df -T 文件系统 类型 1K-块 已用 可用 已用% 挂载点 /dev/sda1 ext4 18577148 11560792 6072692 66% / tmpfs tmpfs 510984 264 510720 1% /dev/shm /dev/sdb1 ext4 20641404 6161100 13431780 32% /opt /dev/sdd1 btrfs 7330796 72 6464236 1% /mnt/mybtrfs /dev/sdd1 btrfs 7330796 72 6464236 1% /mnt/test [root@localhost mnt]# |
Subvolme 可以方便管理员在文件系统上创建不同用途的子文件系统,并对其进行一些特殊的配置,比如有些目录下的文件关注节约磁盘空间,因此需要打开压缩,或者配置不同的 RAID 策略等。目前 btrfs 尚处于开发阶段,创建的 subvolme 和 snapshot 还无法删除。此外针对 subvolume 的磁盘 quota 功能也未能实现。但随着 btrfs 的不断成熟,这些功能必然将会进一步完善。
2.2.6 创建 RAID
RAID 技术有很多非常吸引人的特性,比如用户可以将多个廉价的 IDE 磁盘组合为 RAID0 阵列,从而变成了一个大容量的磁盘; RAID1 和更高级的 RAID 配置还提供了数据冗余保护,从而使得存储在磁盘中的数据更加安全。Btrfs 很好的支持了软件 RAID,RAID 种类包括 RAID0,RAID1 和 RAID10.
mkfs 的时候,可以指定多个设备,并配置 RAID 。下面的命令演示了如何使用 mkfs.btrfs 配置 RAID1 。磁盘sde1 和 sdf1 可以配置为 RAID1,即 mirror 。用户可以选择将数据配置为 RAID1,也可 以选择将元数据配置为 RAID1 。 将数据配置为 RAID1,可以使用 mkfs.btrfs 的 -d 参数。如下所示:
# mkfs.btrfs -d raid1 /dev/sde1 /dev/sdf1
# mount -t btrfs /dev/sde1 /mnt/raid1
[root@localhost mnt]# df -T 文件系统 类型 1K-块 已用 可用 已用% 挂载点 /dev/sda1 ext4 18577148 11560780 6072704 66% / tmpfs tmpfs 510984 264 510720 1% /dev/shm /dev/sdb1 ext4 20641404 6161100 13431780 32% /opt /dev/sdd1 btrfs 7330796 72 6464236 1% /mnt/mybtrfs /dev/sdd1 btrfs 7330796 72 6464236 1% /mnt/test [root@localhost mnt]# mkfs.btrfs -d raid1 /dev/sde1 /dev/sdf1
WARNING! - Btrfs Btrfs v0.19 IS EXPERIMENTAL WARNING! - see http://btrfs.wiki.kernel.org before using
adding device /dev/sdf1 id 2 fs created label (null) on /dev/sde1 nodesize 4096 leafsize 4096 sectorsize 4096 size 15.99GB Btrfs Btrfs v0.19 [root@localhost mnt]# mount -t btrfs /dev/sde1 /mnt/raid1 [root@localhost mnt]# df -T 文件系统 类型 1K-块 已用 可用 已用% 挂载点 /dev/sda1 ext4 18577148 11560780 6072704 66% / tmpfs tmpfs 510984 264 510720 1% /dev/shm /dev/sdb1 ext4 20641404 6161100 13431780 32% /opt /dev/sdd1 btrfs 7330796 72 6464236 1% /mnt/mybtrfs /dev/sdd1 btrfs 7330796 72 6464236 1% /mnt/test /dev/sde1 btrfs 16765268 56 14639444 1% /mnt/raid1 [root@localhost mnt]# |
挂载的时候可以是sde1,也可以是sdf1,示例中用的sde1,容量是两个盘的总量,但当存储文件时,占用的存储空间同时也是文件大小2倍。
2.2.7添加/删除 新设备
当设备的空间快被使用完的时候,用户可以使用 btrfs-vol 命令为文件系统添加新的磁盘设备,从而增加存储空间。下面的命令向 /mnt/mybtrfs 文件系统增加一个设备 /sdg
# btrfs-vol -a /dev/sdg /mnt/mybtrfs
[root@localhost mnt]# df -T 文件系统 类型 1K-块 已用 可用 已用% 挂载点 /dev/sda1 ext4 18577148 11560796 6072688 66% / tmpfs tmpfs 510984 264 510720 1% /dev/shm /dev/sdb1 ext4 20641404 6161100 13431780 32% /opt /dev/sdd1 btrfs 7330796 72 6464236 1% /mnt/mybtrfs /dev/sdd1 btrfs 7330796 72 6464236 1% /mnt/test /dev/sde1 btrfs 16765268 56 14639444 1% /mnt/raid1 [root@localhost mnt]# btrfs-vol -a /dev/sdg /mnt/mybtrfs ioctl returns 0 [root@localhost mnt]# df -T 文件系统 类型 1K-块 已用 可用 已用% 挂载点 /dev/sda1 ext4 18577148 11560804 6072680 66% / tmpfs tmpfs 510984 264 510720 1% /dev/shm /dev/sdb1 ext4 20641404 6161100 13431780 32% /opt /dev/sdd1 btrfs 15719404 72 14852844 1% /mnt/mybtrfs /dev/sdd1 btrfs 15719404 72 14852844 1% /mnt/test /dev/sde1 btrfs 16765268 56 14639444 1% /mnt/raid1 |
可以看到,通过btffs-vol命令为/mnt/mybtrfs文件系统增加了8G的容量。
为了灵活利用设备空间,Btrfs 将磁盘空间划分为多个 chunk 。每个 chunk 可以使用不同的磁盘空间分配策略。比如某些 chunk 只存放 metadata,某些 chunk 只存放数据。一些 chunk 可以配置为 mirror,而另一些 chunk 则可以配置为 stripe 。这为用户提供了非常灵活的配置可能性。
添加设备后可以通过命令平衡chunks
# btrfs-vol -b /dev/sdg /mnt/mybtrfs
[root@localhost mnt]# btrfs-vol -b /mnt/mybtrfs ioctl returns 0 [root@localhost mnt]# |
同理,可以通过命令
# btrfs-vol -r /dev/sdg /mnt/mybtrfs
移除添加的设备。
2.2.8同步文件系统
为了提高效率,btrfs 的 IO 操作由一些内核线程异步处理。这使得用户对文件的操作并不会立即反应到磁盘上。
您可以做一个实验,在 btrfs 上创建一个文件后,稍等 5 到 10 秒将系统电源切断,再次重启后,新建的文件并没有出现。
对于多数应用这并不是问题,但有些时候用户希望 IO 操作立即执行,此时就需要对文件系统进行同步。下面的 btrfs 命令用来同步文件系统:
# btrfsctl -c /mnt/mybtrfs
[root@localhost mnt]# btrfsctl -c /mnt/mybtrfs operation complete Btrfs Btrfs v0.19 |
2.2.9文件系统转化
可以通过如下命令将非btrfs转化为btrfs,下面的例子是将EXT3文件系统的sdd1转化为btrfs。
# btrfs-convert /dev/sdd1
[root@localhost mnt]# btrfs-convert /dev/sdd1 creating btrfs metadata. creating ext2fs image file. cleaning up system chunk. conversion complete. [root@localhost mnt]# mount /dev/sdd1 /mnt/mybtrfs [root@localhost mnt]# df -T 文件系统 类型 1K-块 已用 可用 已用% 挂载点 /dev/sda1 ext4 18577148 11563724 6069760 66% / tmpfs tmpfs 510984 264 510720 1% /dev/shm /dev/sdb1 ext4 20641404 6161100 13431780 32% /opt /dev/sde1 btrfs 16765268 56 14639444 1% /mnt/raid1 /dev/sdd1 btrfs 8379372 281344 5326336 6% /mnt/mybtrfs [root@localhost mnt]# |
同时,也可以通过命令将文件系统回滚到之前的状态:
# btrfs-convert -r /dev/sdd1
[root@localhost mnt]# btrfs-convert -r /dev/sdd1 rollback complete. [root@localhost mnt]# mount /dev/sdd1 /mnt/mybtrfs [root@localhost mnt]# df -T 文件系统 类型 1K-块 已用 可用 已用% 挂载点 /dev/sda1 ext4 18577148 11563716 6069768 66% / tmpfs tmpfs 510984 264 510720 1% /dev/shm /dev/sdb1 ext4 20641404 6161100 13431780 32% /opt /dev/sde1 btrfs 16765268 56 14639444 1% /mnt/raid1 /dev/sdd1 ext3 8247716 149624 7679124 2% /mnt/mybtrfs [root@localhost mnt]#
|
btrfs-convert命令其他用法:
usage: btrfs-convert [-d] [-i] [-n] [-r] device
-d disable data checksum
-i ignore xattrs and ACLs
-n disable packing of small files
-r roll back to ext2fs
2.2.10显示所有btrfs
可以通过birfs-show命令查看当前所有btrfs设备
# btrfs-show
[root@localhost mnt]# btrfs-show failed to read /dev/fd0 failed to read /dev/sr0 Label: none uuid: fa51764c-b9cf-4ebb-b0a5-3f0a0f46c5ff Total devices 2 FS bytes used 36.00KB devid 2 size 8.00GB used 0.00 path /dev/sdg *** Some devices missing
Label: none uuid: 4565d768-ca00-4786-aa59-3046e4e085bd Total devices 2 FS bytes used 28.00KB devid 2 size 8.00GB used 2.01GB path /dev/sdh *** Some devices missing
Label: none uuid: de697cdb-36d5-42eb-802d-2d85c571cba6 Total devices 2 FS bytes used 28.00KB devid 1 size 8.00GB used 2.03GB path /dev/sde1 devid 2 size 7.99GB used 2.01GB path /dev/sdf1
Btrfs Btrfs v0.19 |
2.2.11检查btrfs文件系统
可以通过命令检查btrfs文件系统
# btrfsck /dev/sdd1
[root@localhost mnt]# btrfsck /dev/sdd1 found 288096256 bytes used err is 0 total csum bytes: 0 total tree bytes: 65536 total fs tree bytes: 32768 btree space waste bytes: 36111 file data blocks allocated: 288030720 referenced 288030720 Btrfs Btrfs v0.19 |
2.2.12更新种子值
当我们需要将一个文件系统设置为只读时,我们可以通过btrfstune命令来实现。
#btrfstune -S 1 /dev/sdd1
[root@localhost mnt]# btrfstune -S 1 /dev/sdd1 [root@localhost mnt]# mount /dev/sdd1 /mnt/mybtrfs mount: block device /dev/sdd1 is write-protected, mounting read-only |
同理可以通过命令取消文件系统的只读属性
btrfstune -S 0 /dev/sdd1
2.2.13 Debug功能
Btrfs 提供了一定的 debug 功能,对于想了解 Btrfs 内部实现原理的读者,debug 将是您最喜欢的工具。这里简单介绍一下 debug 功能的命令使用。
下面的命令将设备 sda5 上的 btrfs 文件系统中的元数据打印到屏幕上。
#btrfs-debug-tree /dev/sdd1 |
#btrfs-debug-tree /dev/sdd1 … … leaf 33574912 items 2 free space 3773 generation 3 owner 18446744073709551607 fs uuid 1d61c350-be9a-48e5-90b6-623bf34fe27e chunk uuid 75de6f43-0d68-43c5-9112-88d892a6d1ce item 0 key (FIRST_CHUNK_TREE INODE_ITEM 0) itemoff 3835 itemsize 160 inode generation 3 size 0 block group 0 mode 40555 links 1 item 1 key (FIRST_CHUNK_TREE INODE_REF 256) itemoff 3823 itemsize 12 inode ref index 0 namelen 2 name: .. total bytes 8580476928 bytes used 288096256 uuid 1d61c350-be9a-48e5-90b6-623bf34fe27e Btrfs Btrfs v0.19 |
通过对打印信息的分析,您将能了解 btrfs 内部各个 BTree 的变化情况,从而进一步理解每一个文件系统功能的内部实现细节。
比如您可以在创建一个文件之前将 BTree 的内容打印出来,创建文件后再次打印。通过比较两次的不同来了解 btrfs 创建一个文件需要修改哪些元数据。进而理解 btrfs 内部的工作原理。
3 附录
3.1快照原理(附录)
3.1.1 COW 事务
理解 COW 事务,必须首先理解 COW 和事务这两个术语。
什么是 COW?
所谓 COW,即每次写磁盘数据时,先将更新数据写入一个新的 block,当新数据写入成功之后,再更新相关的数据结构指向新 block 。
什么是事务?
COW 只能保证单一数据更新的原子性。但文件系统中很多操作需要更新多个不同的元数据,比如创建文件需要修改以下这些元数据:
- 修改 extent tree,分配一段磁盘空间
- 创建一个新的 inode,并插入 FS Tree 中
- 增加一个目录项,插入到 FS Tree 中
任何一个步骤出错,文件便不能创建成功,因此可以定义为一个事务。
下面将演示一个 COW 事务。
A 是 FS Tree 的根节点,新的 inode 的信息将被插入节点 C 。首先,btrfs 将 inode 插入一个新分配的 block C ’中,并修改上层节点 B,使其指向新的 block C ’;修改 B 也将引发 COW,以此类推,引发一个连锁反应,直到最顶层的 Root A 。当整个过程结束后,新节点 A ’变成了 FS Tree 的根。但此时事务并未结束,superblock 依然指向 A 。
接下来,修改目录项(E 节点),同样引发这一过程,从而生成新的根节点 A ’’。
此时,inode 和目录项都已经写入磁盘,可以认为事务已经结束。 btrfs 修改 superblock,使其指向 A ’’,如下图所示:
COW 事务能够保证文件系统的一致性,并且系统 Reboot 之后不需要执行 fsck 。因为 superblock 要么指向新的 A ’’,要么指向 A,无论哪个都是一致的数据。
3.1.2 快照和克隆
快照是对文件系统某一时刻的完全备份。建立快照之后,对文件系统的修改不会影响快照中的内容。这是非常有用的一种技术。如前所述 Btrfs 采用 COW 事务技术,从图 1-10 可以看到,COW 事务结束后,如果不删除原来的节点 A,C,E,那么 A,C,E,D,F 依然完整的表示着事务开始之前的文件系统。这就是 snapshot 实现的基本原理。
Btrfs 采用引用计数决定是否在事务 commit 之后删除原有节点。对每一个节点,btrfs 维护一个引用计数。当该节点被别的节点引用时,该计数加一,当该节点不再被别的节点引用时,该计数减一。当引用计数归零时,该节点被删除。对于普通的 Tree Root, 引用计数在创建时被加一,因为 Superblock 会引用这个 Root block 。很明显,初始情况下这棵树中的所有其他节点的引用计数都为一。当 COW 事务 commit 时,superblock 被修改指向新的 Root A ’’,原来 Root block A 的引用计数被减一,变为零,因此 A 节点被删除。 A 节点的删除会引发其子孙节点的引用计数也减一,图 1-10 中的 B,C 节点的引用计数因此也变成了 0,从而被删除。 D,E 节点在 COW 时,因为被 A ’’所引用,计数器加一,因此计数器这时并未归零,从而没有被删除。
创建 Snapshot 时,btrfs 将的 Root A 节点复制到 sA,并将 sA 的引用计数设置为 2 。在事务 commit 的时候,sA 节点的引用计数不会归零,从而不会被删除,因此用户可以继续通过 Root sA 访问 snapshot 中的文件。
3.2 Btrfs工具的安装(附录)
如果当要将一个磁盘格式化为btrfs格式时发现mkfs.后并没有btrfs选项,那么可能你需要安装btrfs-tools,安装方法如下:
在下面的地址下载这个包:
ftp://ftp.li.kernel.org/pub/.3/ubuntu/pool/universe/b/btrfs-tools/
这个包安装起来还是比较简单的,直接解压缩,然后接着执行make进行编译,之后执行make install进行安装。
如果在make install时发现有如下问题:
[root@ipshot btrfs-progs-0.19]# make install ls btrfsck.c btrfsck.c gcc -Wp,-MMD,./.btrfsck.o.d,-MT,btrfsck.o -Wall -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 -g -Werror -Os -c btrfsck.c cc1: warnings being treated as errors btrfsck.c: In function ‘maybe_free_inode_rec’: btrfsck.c:287: error: implicit declaration of function ‘S_ISDIR’ btrfsck.c:292: error: implicit declaration of function ‘S_ISREG’ btrfsck.c:292: error: implicit declaration of function ‘S_ISLNK’ make: *** [btrfsck.o] Error 1 |