btrfs是一个先进的文件系统, 由Oracle研发, 在2014年推出了稳定版,支持很多EXT系列文件系统不支持的特性.
概述 Btrfs的最大特性就是支持Cow(Copy on write 写时复制)
.
下面简单介绍一下Btrfs的核心特性:
多物理卷支持, 支持RAID
, 联机”添加”, “移除”, “修改”
写时复制(CoW)
, 复制 更新 替换指针, 而非就地更新(备份)
数据和元数据校验码 checksum,
快速检测文件是否损毁
子卷 sub_volume
快照, 支持快照的快照, 也是基于CoW
透明压缩: 文件存储时进行压缩,读取时自动解压缩
Btrfs的使用 BTreeFS的命令有两种语法风格的, 一种是单独的一个个小命令, 一个是子命令的形式(较新).
较新的Linux命令都是以子命令的形式编写的, 就像mkfs -t
和mkfs.ext4/mkfs.btrfs
, 严格的说,前者也不能说是子命令, 像ip
系列的命令才叫子命令的形式.
使用前先来说一下Btrfs的构建 创建Btrfs
的命令仍然是mkfs
, 只不过原理不一样了, 所以参数和ext
系列是不一样的.
先来看一下常用的参数有哪些吧:
1 2 3 4 5 6 [root@WWW ~]$ man mkfs.brtfs -m| --metadata <profile> 指定元数据如何跨越物理卷, 合法的值有:raid0, raid1, raid5, raid6, raid10, single[默认值], dup(冗余, duplicate,仅仅是复制一份罢了). -d| --data <type > 指定数据如何跨越物理卷, 和上面的是基本一样的值(没有dup选项). -L| --label <name> 声明一个小于256Bytes的字符串来当做文件系统的卷标(标签) -O| --feature <f1>,[<f2>...] 查看和指定文件系统和内核支持的特性 可以使用 -O list-all
接下来就要改变思路了, Btree文件系统在同一个磁盘的不同分区的意义就不大了,因为这样就失去了冗余能力,但是这样比较简单,虽然失去了意义. 所以,选取多个磁盘共同组成一个B树文件系统.
下面来创建一个Btrfs的文件系统, 事实上过程是很简单的, 我新分配了3块虚拟磁盘, 每一个的大小是10.00GB
, 这样现在的系统状态是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [root@WWW ~]$ fdisk -l Disk /dev/sdb: 10 GiB, 10737418240 bytes, 20971520 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/sdd: 10 GiB, 10737418240 bytes, 20971520 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes
还有一个已经都挂载的用于系统和swap
的磁盘sda
.
那么现在把sdb
和sdc
进行格式化,构成一个文件系统.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [root@WWW ~]$ mkfs.btrfs -L "mydata" /dev/sd{b,c} Label: mydata `UUID`: Node size: 16384 Sector size: 4096 Filesystem size: 20.00GiB Block group profiles: Data: RAID0 2.00GiB Metadata: RAID1 1.00GiB System: RAID1 8.00MiB SSD detected: no Incompat features: extref, skinny-metadata Number of devices: 2 Devices: ID SIZE PATH 1 10.00GiB /dev/sdb 2 10.00GiB /dev/sdc
很快就创建成功了, 整个文件系统的大小是20.00GB
Btrfs文件系统的使用 文件系统 btrfs支持很多子命令, 每一个子命令有包含很多的二级子命令. 其中一个是filesystem
, 他有一个子命令可以擦看当前的btrfs的状态.
1 2 3 4 5 [root@WWW ~]$ btrfs filesystem show Label: 'mydata' UUID: acc64201-b842-41ed-b651-b41c84839d63 Total devices 2 FS bytes used 112.00KiB devid 1 size 10.00GiB used 2.01GiB path /dev/sdb devid 2 size 10.00GiB used 2.01GiB path /dev/sdc
很快就可以发现文件系统mydata拥有一个UUID
, 可是大家都知道,每一个磁盘应该都有一个UUID
才对, 但是这样搞我不就无法定位到单个硬盘了吗, 别急.使用我们之前查看UUID
的命令来试一下:
1 2 3 4 5 [root@WWW ~]$ blkid /dev/sda1: UUID="62e883b5-6150-4294-a6d2-a387b5cec8b8" TYPE="ext4" PARTUUID="8b164ce4-01" /dev/sdb: LABEL="mydata" UUID="acc64201-b842-41ed-b651-b41c84839d63" UUID_SUB="90475d97-7147-4d75-99a0-a9e2841dcd87" TYPE="btrfs" /dev/sdc: LABEL="mydata" UUID="acc64201-b842-41ed-b651-b41c84839d63" UUID_SUB="93d9ad4c-47f0-41ed-a387-7adaee0268c0" TYPE="btrfs" /dev/sda5: UUID="8f65d150-3b30-40e5-8f9e-cae947a8321f" TYPE="swap" PARTUUID="8b164ce4-05"
从输出结果我们发现, 两个共同组成btrfs
的磁盘共有一个UUID
, 但是却多了一个叫UUID_SUB
的属性, 这个属性就是上面说的每一个磁盘的UUID
, 因为这些个磁盘叫做这个FS
的子卷,因此就取名字叫UUID_SUB
了.
上面的filesystem
的子命令show
可以来筛选输出的内容:
1 2 3 4 [root@WWW ~]$ brtfs filesystem show [OPTIONS] --mounted 仅显示挂载的btrfs文件系统 --all-devices 显示所有的btrfs文件系统 后面也可以直接跟上设备路径, UUID, 卷标等等
至此, 我们就可以创建和查看btrfs
文件系统了
再介绍一下filesystem
其他的一些子命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 [root@WWW ~]$ btrfs filesystem usage: btrfs filesystem [<group>] <command > [<args>] btrfs filesystem sync <path> Force a sync on a filesystem 强制写入磁盘 btrfs filesystem defragment [options] <file>|<dir > [<file>|<dir >...] Defragment a file or a directory 清理磁盘碎片 btrfs filesystem resize [devid:][+/-]<newsize>[kKmMgGtTpPeE]|[devid:]max <path> Resize a filesystem 改变文件系统的大小 btrfs filesystem label [<device>|<mount_point>] [<newlabel>] Get or change the label of a filesystem 查看文件系统的卷标或者进行重命名 btrfs filesystem usage [options] <path> [<path>..] Show detailed information about internal filesystem usage . 显示详细的文件系统使用情况 overall filesystem tasks and information
其中很多命令都需要在我们进行挂载后才可以使用, 现在就来把他加入到目录树上吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [root@WWW ~]$ mkdir /mydata [root@WWW ~]$ mount -t btrfs /dev/sdb /mydata [root@WWW ~]$ mount /dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered) ... /dev/sdb on /mydata type btrfs (rw,relatime,space_cache,subvolid=5,subvol=/) [root@WWW ~]$ umount /mydata [root@WWW ~]$ mount -t btrfs /dev/sdc /mydata [root@WWW ~]$ mount /dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered) ... /dev/sdb on /mydata type btrfs (rw,relatime,space_cache,subvolid=5,subvol=/)
现在我们就可以使用一些filesystem
的命令了.
1 2 3 4 5 [root@WWW ~]$ btrfs filesystem {df ,du ,label,usage...}
之前说过btrfs
是支持透明压缩的 只要在挂载的时候 加上 -o
添加参数compress={lzo|zlib}
这样之后, 文件就会得到自动的压缩和解压缩, 这个过程对用户是透明的.
Btrfs
支持在线调整大小, 就像LVM
那样, 使用resize
命令.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 [root@WWW ~]$ btrfs filesystem resize -4G /mydata Resize '/mydata/' of '4G' [root@WWW ~]$ btrfs filesystem show Label: 'mydata' uuid: 51136d0b-5bfb-4c0b-8d88-bb05f40455eb Total devices 2 FS bytes used 808.00KiB devid 1 size 4.00GiB used 1.81GiB path /dev/sdb devid 2 size 8.00GiB used 1.81GiB path /dev/sdc [root@WWW ~]$ df -hl Filesystem Size Used Avail Use% Mounted on udev 2.0G 0 2.0G 0% /dev tmpfs 396M 6.1M 390M 2% /run /dev/sda1 16G 9.2G 5.7G 63% / tmpfs 2.0G 0 2.0G 0% /dev/shm tmpfs 5.0M 0 5.0M 0% /run/lock tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup tmpfs 396M 16K 396M 1% /run/user/132 tmpfs 396M 32K 396M 1% /run/user/0 /dev/sdb 12G 17M 6.0G 1% /mydata [root@WWW ~]$ btrfs filesystem resize max /mydata Resize '/mydata/' of 'max' [root@WWW ~]$ df -hl Filesystem Size Used Avail Use% Mounted on udev 2.0G 0 2.0G 0% /dev tmpfs 396M 6.1M 390M 2% /run /dev/sda1 16G 9.2G 5.7G 63% / tmpfs 2.0G 0 2.0G 0% /dev/shm tmpfs 5.0M 0 5.0M 0% /run/lock tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup tmpfs 396M 16K 396M 1% /run/user/132 tmpfs 396M 32K 396M 1% /run/user/0 /dev/sdb 16G 17M 6.0G 1% /mydata
物理磁盘管理 如果我还想让这个空间更大呢?那就需要增加新的磁盘进来.就像LVM
那样, btrfs
进行底层设备的管理的命令是device
子命令.
1 2 3 4 5 [root@WWW ~]$ btrfs device <COMMAND>
现在我们先试试为我们的文件系统增加一个磁盘来扩充空间.
1 2 3 4 5 6 7 8 9 10 11 12 [root@WWW ~]$ btrfs device add /dev/sdd /mydata root@kali:/mydata Filesystem Size Used Avail Use% Mounted on udev 2.0G 0 2.0G 0% /dev tmpfs 396M 6.1M 390M 2% /run /dev/sda1 16G 9.2G 5.7G 63% / tmpfs 2.0G 0 2.0G 0% /dev/shm tmpfs 5.0M 0 5.0M 0% /run/lock tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup tmpfs 396M 16K 396M 1% /run/user/132 tmpfs 396M 24K 396M 1% /run/user/0 /dev/sdb 24G 17M 21G 1% /mydata
删除一个设备也是很简单的, 直接将add
换成remove
就行了.在移除的前, btrfs
会自动将数据迁移出去, 因此,要保证在移除后整个文件系统剩余的磁盘数量仍然能够将数据完整的保留下来.
数据重分配 接下来再来看一下btrfs
中的balance
.这个balance
就好像是磁盘阵列的修复, 他会将数据进行一次重新的分配.
直接启动balance
会收到警告:
1 2 3 4 5 6 7 8 9 [root@WWW ~]$ btrfs balance start /mydata/ WARNING: Full balance without filters requested. This operation is very intense and takes potentially very long. It is recommended to use the balance filters to narrow down the balanced data. Use 'btrfs balance start --full-balance' option to skip this warning. The operation will start in 10 seconds. Use Ctrl-C to stop it.
这是因为如果数据量很大, balance
会成为一个很耗时的过程. 因此建议加上过滤.
在balance
的过程中, 可以随时进行pause
, cancel
, resume
的操作, 也可以随时查看状态, 使用status
.
balance
里常用的过滤器, 我其实就只用过convert . 将对应的section
转换为指定的格式(single,dup,raid{0,1,5,6}
)
使用起来就像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 [root@WWW ~]$ btrfs filesystem show Label: 'myNewData' uuid: 8de2ca1c-75ea-4573-ad80-4ef1768d1a6b Total devices 1 FS bytes used 448.00KiB devid 1 size 8.00GiB used 1.12GiB path /dev/sdb oot@kali:/mydata/backup ERROR: error during balancing '/mydata/' : Invalid argument There may be more info in syslog - try dmesg | tail [root@WWW ~]$ btrfs balance start -dconvert=single -sconvert=single -mconvert=single /mydata/ -f Done, had to relocate 4 out of 4 chunks [root@WWW ~]$ btrfs device add /dev/sd{c,d,e} /mydata/ [root@WWW ~]$ btrfs filesystem show Label: 'myNewData' uuid: 8de2ca1c-75ea-4573-ad80-4ef1768d1a6b Total devices 4 FS bytes used 384.00KiB devid 1 size 8.00GiB used 1.09GiB path /dev/sdb devid 2 size 8.00GiB used 0.00B path /dev/sdc devid 3 size 8.00GiB used 0.00B path /dev/sdd devid 4 size 8.00GiB used 0.00B path /dev/sde [root@WWW ~]$ btrfs filesystem usage /mydata/ Overall: Device size: 32.00GiB Device allocated: 1.09GiB Device unallocated: 30.91GiB Device missing: 0.00B Used: 384.00KiB Free (estimated): 31.72GiB (min: 31.72GiB) Data ratio: 1.00 Metadata ratio: 1.00 Global reserve: 16.00MiB (used: 0.00B) Data,single: Size:832.00MiB, Used:256.00KiB /dev/sdb 832.00MiB Metadata,single: Size:256.00MiB, Used:112.00KiB /dev/sdb 256.00MiB System,single: Size:32.00MiB, Used:16.00KiB /dev/sdb 32.00MiB Unallocated: /dev/sdb 6.91GiB /dev/sdc 8.00GiB /dev/sdd 8.00GiB /dev/sde 8.00GiB [root@WWW ~]$ btrfs balance start -dconvert=raid5 -mconvert=raid5 -sconvert=raid5 /mydata/ -f Done, had to relocate 3 out of 3 chunks [root@WWW ~]$ btrfs filesystem df /mydata/ Data, RAID5: total=3.00GiB, used=832.00KiB System, RAID5: total=96.00MiB, used=16.00KiB Metadata, RAID5: total=288.00MiB, used=112.00KiB GlobalReserve, single: total=16.00MiB, used=0.00B
子卷使用 前面还说过了, btrfs
支持子卷(subvolume
). 来看一下如何创建和管理子卷吧.
子卷就是文件系统中一个拥有自己的文件目录结构的部分, 快照也是基于此创建的. 你可以直挂载一个子卷.
需要注意的是,子卷的原理和LVM的实现时有区别,尽管表现起来看起来是一样的,btrfs的子卷是基于文件实现的,而不像LVM是基于block的.
btrfs
的子卷管理是使用的subvolume
子命令.
1 2 3 [root@WWW ~]$ btrfs subvolume [COMMAND]
先来创建一个子卷:
1 2 3 4 [root@WWW ~]$ btrfs subvolume create /mydata/logs Create subvolume '/mydata/logs' [root@WWW ~]$ btrfs subvolume list /mydata/ ID 275 gen 161 top level 5 path logs
上面的ID
就是卷ID
.
子卷是可以被单独挂载的.现在我们来做个试验吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [root@WWW ~]$ umount /mydata [root@WWW ~]$ mount -o subvol=logs /dev/sdb /mnt [root@WWW ~]$ btrfs subvolume show /mnt /mnt Name: logs UUID: 5d29a288-22b1-4044-a420-6d9c0073b565 Parent UUID: - Received UUID: - Creation time: 2017-06-21 02:22:34 -0700 Subvolume ID: 275 Generation: 163 Gen at creation: 161 Parent ID: 5 Top level ID: 5 Flags: - Snapshot(s):
接下来再把父卷给挂回来:
1 2 3 4 5 [root@WWW ~]$ umount /mnt [root@WWW ~]$ mount /dev/sdb /mydata [root@WWW ~]$ ls /mydata/logs/ messages
看,我们的文件还在里面, 这就说明当父卷挂载时,所有的子卷也都会被挂载.
接下来把他删除了吧.
1 2 3 4 [root@WWW ~]$ btrfs subvolume delete /mydata/logs/ Delete subvolume (no-commit): '/mydata/logs' [root@WWW ~]$ btrfs subvolume list /mydata/
之前说过,快照是基于子卷来构建的, 体验一下btrfs
的快照:
1 2 3 4 5 6 7 8 9 [root@WWW ~]$ btrfs subvolume create /mydata/logs [root@WWW ~]$ cp -rp /etc/grub.d /mydata/logs/ [root@WWW ~]$ btrfs subvolume snapshot /mydata/logs /mydata/logs_snapshot Create a snapshot of '/mydata/logs/' in '/mydata/logs_snapshot' [root@WWW ~]$ btrfs subvolume list /mydata ID 276 gen 170 top level 5 path logs ID 277 gen 170 top level 5 path logs_snapshot
接着的使用方法就和LVM的快照差不多了.
删除快照的方法和删除子卷的方法一样( 因为就是子卷嘛 ).
除了这种文件系统的快照, btrfs
还支持文件级别的快照. 方法很简单, 直接使用熟悉的cp
命令就可以了.
1 2 [root@WWW ~]$ cp --reflink README README.snap
最后再说一个小东西 如何将我们的ext
系统转变为btrfs
文件系统呢?
直接做演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 root@kali:/mydata/logs/grub.d Welcome to fdisk (util-linux 2.29.2). Changes will remain in memory only, until you decide to write them. Be careful before using the write command . Command (m for help ): p Disk /dev/sdf: 8 GiB, 8589934592 bytes, 16777216 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type : dos Disk identifier: 0x0e2e36eb Command (m for help ): n Partition type p primary (0 primary, 0 extended, 4 free) e extended (container for logical partitions) Select (default p): Using default response p. Partition number (1-4, default 1): First sector (2048-16777215, default 2048): Last sector, +sectors or +size{K,M,G,T,P} (2048-16777215, default 16777215): +2G Created a new partition 1 of type 'Linux' and of size 2 GiB. Command (m for help ): p Disk /dev/sdf: 8 GiB, 8589934592 bytes, 16777216 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type : dos Disk identifier: 0x0e2e36eb Device Boot Start End Sectors Size Id Type /dev/sdf1 2048 4196351 4194304 2G 83 Linux Command (m for help ): w The partition table has been altered. Calling ioctl() to re-read partition table. Syncing disks. root@kali:/mydata/logs/grub.d root@kali:/mydata/logs/grub.d mke2fs 1.43.4 (31-Jan-2017) Creating filesystem with 524288 4k blocks and 131072 inodes Filesystem UUID: 213ded53-11a5-4d7b-9d3b-b196c543261b Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912 Allocating group tables: done Writing inode tables: done Creating journal (16384 blocks): done Writing superblocks and filesystem accounting information: done root@kali:/mydata/logs/grub.d root@kali:/mydata/logs/grub.d root@kali:/mnt root@kali:/mnt UUID=62e883b5-6150-4294-a6d2-a387b5cec8b8 / ext4 errors=remount-ro 0 1 UUID=8f65d150-3b30-40e5-8f9e-cae947a8321f none swap sw 0 0 /dev/sr0 /media/cdrom0 udf,iso9660 user,noauto 0 0 root@kali:/ fsck from util-linux 2.29.2 e2fsck 1.43.4 (31-Jan-2017) Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information /dev/sdf1: 12/131072 files (0.0% non-contiguous), 26157/524288 blocks root@kali:/ create btrfs filesystem: blocksize: 4096 nodesize: 16384 features: extref, skinny-metadata (default) creating ext2 image file creating btrfs metadatacopy inodes [o] [ 3/ 12] conversion completeroot@kali:/ root@kali:/ Label: 'myNewData' uuid: 8de2ca1c-75ea-4573-ad80-4ef1768d1a6b Total devices 4 FS bytes used 1.01MiB devid 1 size 8.00GiB used 1.12GiB path /dev/sdb devid 2 size 8.00GiB used 1.12GiB path /dev/sdc devid 3 size 8.00GiB used 1.12GiB path /dev/sdd devid 4 size 8.00GiB used 1.12GiB path /dev/sde Label: none uuid: 823109e6-34dd-4efe-ad1d-a63424b4a820 Total devices 1 FS bytes used 102.43MiB devid 1 size 2.00GiB used 292.15MiB path /dev/sdf1
所以,其实是很简单的,直接进行一下btrfs-convert
就好了. 在生成的文件系统中会出现一个叫做ext2_saved
的镜像文件, 这个文件是用来进行回滚的, 就是重新恢复成EXT
文件系统.
其实还是btrfs
命令, 直接加上-r
参数 就好了
1 2 3 4 5 [root@WWW ~]$ umount /mnt/ [root@WWW ~]$ btrfs-convert -r /dev/sdf1 rollback complete [root@WWW ~]$ blkid /dev/sdf1 /dev/sdf1: UUID="213ded53-11a5-4d7b-9d3b-b196c543261b" TYPE="ext4" PARTUUID="0e2e36eb-01"