高级文件系统-btrfs
2016年04月29日

概述

btrfs(通常念成Butter FS),由Oracle于2007年宣布并进行中的COW(copy-on-write式)文件系统。目标是取代Linux目前的ext3文件系统,改善ext3的限制,特别是单一文件大小的限制,总文件系统大小限制以及加入文件校验和特性。加入目前ext3/4未支持的一些功能,例如可写的磁盘快照(snapshots),以及支持递归的快照(snapshots of snapshots),内建磁盘阵列(RAID)支持,支持子卷(Subvolumes)的概念,允许在线调整文件系统大小。

编译安装

内核支持

File systems --->
    <*> Btrfs filesystem support
    [*]     Btrfs POSIX Access Control Lists
cd /usr/src/linux
make nconfig
make && make modules_install
make install
genkernel --lvm initramfs
grub-mkconfig -o /boot/grub/grub.cfg

安装btrfs的配置工具

emerge btrfs-progs

重启,应用新内核

配置

分配磁盘分区

fdisk /dev/sda
# or
parted /dev/sda

创建btrfs文件系统

mkfs.btrfs /dev/sdax

挂载文件系统

mount -o noatime,nodiratime,autodefrag,noacl,compress=lzo /dev/sdxx /mnt/path

根据上面的参考信息,子卷与文件夹的区别对于使用来说,只是子卷可以使用btrfs的快照,挂载等功能,而文件夹不同.
直观的来看,文件夹和子卷的文件属性相同(子卷无法用rmdir删除).
在btrfs分区内,可以子卷和文件、文件夹混合存在.子卷嵌套,文件夹嵌套子卷.
但为了明确的分辨子卷和文件夹,建议还是不用混合使用.子卷统一存放

子卷操作

cd /mnt/path
#创建子卷
btrfs subvolume create sub1 

#删除子卷
btrfs subvolume delete sub1

#查看子卷列表
btrfs subvolume list /mnt/path

由于btrfs支持子卷空间动态平衡,以及类似LVM的动态磁盘扩容的功能.
所以尽量将目录都使用子卷进行管理
例如:
假设sdb1 sdb2都是btrfs分区

mount /dev/sdb1 /mnt/dir1
df -h
/dev/sdb1 8.0G 224K 7.2G 1% /mnt/dir1
btrfs device add -f /dev/sdb2 /mnt/dir1
df -h
/dev/sdb1 16.0G 224K 7.2G 1% /mnt/dir1

创建 /,home,/usr/portage/distfiles对应的子卷

btrfs subvolume create root
btrfs subvolume create home
btrfs subvolume create distfiles

注意:boot子卷需要gpt分区,以及initram支持才可以
注意:不能创建swap子卷,这会破坏btrfs文件系统!!

创建目录并挂载目录

   mkdir -p /mnt/path/rootfs/home 
   mkdir -p /mnt/path/rootfs/usr/portage/distfiles
   mount /dev/sdax -o subvol=home,noatime,nodiratime,autodefrag,noacl,compress=lzo /mnt/path/rootfs/home
   mount /dev/sdax -o subvol=distfiles,noatime,nodiratime,autodefrag,noacl /mnt/path/rootfs/usr/portage/distfiles

由于distfiles目录本身就是存放压缩包的,所以没有添加compress=lzo参数

修改/etc/fstab

  • sda1 /boot ext4
  • sda6 / btrfs 包括 / home distfiles子卷
  • sda5 swap
vim /etc/fstab
    /dev/sda6	/	                    btrfs	subvol=root,noatime,nodiratime,autodefrag,noacl,compress=lzo  0 1
    /dev/sda1	/boot	                ext4	noauto,noatime                                                                          1 2	
    /dev/sda6	/home	                btrfs	subvol=home,noatime,nodiratime,autodefrag,noacl,compress=lzo  0 1
    /dev/sda6	/usr/portage/distfiles	btrfs	subvol=distfiles,noatime,nodiratime,autodefrag,noacl          0 1
    /dev/sda5	none		            swap	sw		                                                                                0 0

修改grub.cfg引导信息

添加(修改)这两个参数就可以了rootflags=subvol=rootfs rootfstype=btrfs
如果使用grub2-mkconfig生成的grub.cfg文件,可以修改/etc/default/grub文件
GRUB_CMDLINE_LINUX_DEFAULT="rootflags=subvol=rootfs rootfstype=btrfs"

以上所有用subvol的地方可以用subvolid替代
id 可以用btrfs subvolume list /mnt/path查看

raid 配置

以sdb sdc组raid1(0,1,5,6,10) sdb sdc 各5g

    btrfs.mkfs -d raid1 /dev/sdb /dev/sdc

可以挂载到一个目录上,fstab也添加自动挂载

    mount /dev/sdb /mnt/path

也可以用sdc

假设错误情况,err1:sdc挂了
启动的时候,如果fstab有自动挂载,会提示文件系统错误

查看文件系统

btrfs filesystem show /dev/sdb

Label:none uuid: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Total devices 2 FS bytes used xxx.xxKiB
devid   1 size 5.00GiB used 2.01GiB path /dev/sdb
*** Some devices missing

这时,如果手头没有硬盘可以修复raid,可以暂时把raid降级,先把数据恢复出来

mount -o degraded /dev/sdb /mnt/path
# 复制数据,备份出来

如果有新硬盘,并且已经接入到电脑

btrfs device add /dev/sdc /mnt/path
btrfs device delete missing /mnt/path

如果组的像是raid1这种raid,raid必须时刻保持至少有两个设备,所以必须先add再delete

删除坏设备以后,btrfs会自动恢复raid数据

err2:sdb挂了
理论上说,如果硬盘是突然挂掉的,sdb无法识别,那么系统会无法识别sdb.
而之前sdc会替代之前sdb的编号,剩下的操作沿用之前的err1的方式就可以了.

如果设备可以识别,但是无法读取或者已经将新硬盘替换到sdb的位置
同样启动的时候会提示文件系统错误

btrfs filesystem show /dev/sdb 

这次由于是sdb坏了,但raid信息是读取raid里的第一个设备,所以显示的raid信息会有错误

Label:none uuid: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Total devices 2 FS bytes used xxx.xxKiB
devid   2 size 5.00GiB used 288.00MiB path /dev/sdb
*** Some devices missing

完全不符合raid1分担的信息,而且devid 后边的序号是2,代表他是raid中的第二个设备.
另外可以通过降级挂载测试是否是sdb挂了

mount -t degraded /dev/sdb

这时候由于sdb损坏或者sdb是新硬盘没有raid的super block内容.所以仍然无法挂载

这就需要调整下硬盘的启动顺序,把正常的硬盘有限启动(bios里设置或者开机箱重新接线),之后重复err1的修复方法

快照

    mount /dev/sdax /mnt/btr
    cd /mnt/btr
    # 创建子卷
    btrfs subvolume create sub1
    touch sub1/aa
    # 创建子卷的快照
    btrfs subvolume snapshot sub1 sub1_snapshot

完成后如下

  • /mnt/btr
    • sub1
      • aa
    • sub1_snapshot
      • aa

快照和子卷的区别只在创建的命令上.以后的操作可以完全视为是一个子卷
删除快照或者删除子卷的方法都是一样的

btrfs subvolume delete sub1_snapshot
btrfs subvolume delete sub1

这样如果想用某个快照回滚之前的操作就变得容易很多
比如系统误操作chmod 777 /etc/*之后,可以简单改变挂载的子卷名称,达到回滚的效果
或者可以直接删除子卷,把快照重命名为以前的子卷,连fstab的修改都省了

btrfs subvolume delete sub1
mv sub1_snapshot sub1

btrfs可以为子卷创建快照,同样可以为整个文件系统创建快照

btrfs subvolume snapshot /mnt/btr btr_snapshot

但由于文件系统本身是不能用btrfs subvolume delete的方式删除的,所以还是建议针对子卷进行快照的设置
btrfs在为嵌套的子卷做快照时,内部子卷内容不会被复制
例如:

  • sub1
    • file1
  • root_snapshot
    • sub1
      root_snapshot是btrfs subvolume snapshot /mnt/path root_snapshot命令创建的.
      root_snapshot/sub1会退化为一个空目录,起初有些不理解.但结果确实正确.
      一般应用的时候,嵌套子卷多半类似于 rootfs/homefs这样形式的存在,如果连homefs的内容也进了rootfs的快照,就显得多余了

总结

btrfs作为一种新兴的操作系统,有着众多的新特性,感觉有点类似zfs.但是作为数据的最底层,感觉仍然需要更多的时间去积累、沉淀,才能应用到生产环境中.
毕竟:子卷、快照、raid并不是新概念,对应的lvm以及raid命令乃至raid卡已经相当成熟。相比btrfs的子卷,lvm还支持对每个逻辑卷自定义文件系统。

相关链接

btrfs介绍已经arch btrfs部署
http://zhumeng8337797.blog.163.com/blog/static/100768914201322211268894/

ibm 有关btrfs的介绍(命令已过时)
https://www.ibm.com/developerworks/cn/linux/l-cn-btrfs/

btrfs wiki
https://btrfs.wiki.kernel.org/index.php/Main_Page