Btrfs CoW 확인, NoCoW 설정. (압축은 덤)

Btrfs 파일시스템은 COW(Copy On Write)가 기본값이다.
그런데, 자주 변경사항이 발생하는 곳에는 이 CoW 를 쓰지 않는 편이 좋다고 한다.
Btrfs SysadminGuide 에 이런 내용이 나와있다.

This leads to fragmentation in heavily updated-in-place files like VM images and database stores.

Btrfs 를 주 파일시스템으로 사용하는 OpenSuse 를 보면, var 서브볼륨(@/var) 에 NoCoW 를 설정해놓고 있다. (설치 시에 이 부분을 명시하고 있다.)

그럼, CoW 를 사용하고 있는지 아닌지 여부는 어떻게 알 수가 있나?
lsattr 을 사용하면 이 정보를 얻을 수 있다.

sudo lsattr /mnt/@
---------------C---- /mnt/@/var
-------------------- /mnt/@/usr
-------------------- /mnt/@/tmp
-------------------- /mnt/@/srv
-------------------- /mnt/@/root
-------------------- /mnt/@/opt
-------------------- /mnt/@/home
-------------------- /mnt/@/boot
-------------------- /mnt/@/etc

위 내용은 OpenSuse 에서 확인한 사항인데, 대문자 C가 표시된 파일/디렉토리는 CoW 가 해제되어 있음을 뜻한다고 한다.

그렇다면, CoW 를 사용하지 않게 설정하려면 어떻게 해야 하나?
이론으로는 두가지 방법이 있는데, 실전에선 딱 하나만 쓰인다. 적어도 현재까지는.

  • 첫번째 : mount 시에 nodatacow 를 붙인다. (그러나 실효성 없음)
  • 두번째 : 서브볼륨/디렉토리를 생성하고, chattr +C /dir/file 명령을 내린다.

첫번째 방법이 무의미한 이유는, fstab 에서 마운트 옵션을 줄 때, 각각 서브볼륨에 따라 달리 줄 수 없기 때문이다. All or Nothing 이랄까.
이 내용은 Btrfs Wiki 에 나와있다.

Note: most mount options apply to the whole filesystem and only options in the first mounted subvolume will take effect. This is due to lack of implementation and may change in the future. This means that (for example) you can’t set per-subvolume nodatacownodatasum, or compress using mount options. This should eventually be fixed, but it has proved to be difficult to implement correctly within the Linux VFS framework.

Btrfs Manpage/btrfs(5)

정리하자면, 맨 처음에 준 옵션이 아래에 그대로 적용되고, 아래에서 달리 적용해도 아무 소용이 없다.

예를 들어, 이렇게 설정해도 아무 소용이 없다.

$ cat /etc/fstab 
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /                       btrfs  defaults,compress                      0  0
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /.snapshots             btrfs  subvol=/@/.snapshots          0  0
UUID=886124d9-e0b8-400a-9400-7dec061093f4  swap                    swap   defaults                      0  0
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /var                    btrfs  subvol=/@/var                 0  0
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /usr/local              btrfs  subvol=/@/usr/local           0  0
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /tmp                    btrfs  subvol=/@/tmp                 0  0
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /srv                    btrfs  subvol=/@/srv                 0  0
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /root                   btrfs  subvol=/@/root                0  0
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /opt                    btrfs  subvol=/@/opt                 0  0
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /home                   btrfs,nodatacow  subvol=/@/home                0  0
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /boot/grub2/x86_64-efi  btrfs  subvol=/@/boot/grub2/x86_64-efi  0  0
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /boot/grub2/i386-pc     btrfs  subvol=/@/boot/grub2/i386-pc  0  0
UUID=F226-2D5C                             /boot/efi               vfat   codepage=949                  0  2

위처럼, /home 에 nodatacow 를 설정해도 인정되지 않고, 맨 위의 / 에 설정한 defaults,compress 가 나머지 서브볼륨에 모두 적용된다.
따라서 OpenSuse 에서는 / 를 제외한 나머지 서브볼륨 마운트 항목에서는 subvol=xx 옵션만 넣어놓고 defaults 라는 문구도 제외해놓았다.
이런 걸 볼 때마다, OpenSuse 가 굉장히 잘 만들어진(세심한?) 배포판이란 느낌이 든다.

실제 NoCow 설정

이론은 그만. 실제로는 chattr +C /dir/file 명령을 써야 한다.
서브볼륨이든, 디렉토리든, 파일이든 모두 동일하다.

다만!
이미 만들어져있는 파일엔 저 명령이 적용되지 않는다. 새로 생성되는 파일에만 NoCow 가 적용된다.
따라서, 기존 파일에 적용시키려면, 원래 있던 파일은 이름을 바꾼 뒤, 새로 chattr +C 를 하여 파일/디렉토리를 생성하고, 그 이름으로 파일을 복사해줘야 한다.

Archlinux 에선 이런 방식을 제안하고 있다.

$ mv /path/to/dir /path/to/dir_old
$ mkdir /path/to/dir
$ chattr +C /path/to/dir
$ cp -a /path/to/dir_old/* /path/to/dir
$ rm -rf /path/to/dir_old

압축은..?

압축도 nodatacow 와 같다. fstab 최초에 설정하면, 아래 모두에 적용된다.
다만, 설정 이전에 존재하던 파일에는 적용되지 않는다. 설정 이후 새로 만들어지는 파일부터 압축이 적용된다.

압축 여부는 mount 상황(fstab, 또는 mount 명령)으로 알 수 있다.

$ cat /etc/fstab
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /                       btrfs  defaults,compress                      0  0
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /var                    btrfs  subvol=/@/var                 0  0
UUID=c5f0f9b8-e8ca-420b-bed7-c1dc82695cdc  /usr/local              btrfs  subvol=/@/usr/local           0  0
.... 생략

$ mount
/dev/sda2 on /.snapshots type btrfs (rw,relatime,compress=zlib:3,space_cache,subvolid=267,subvol=/@/.snapshots)
/dev/sda2 on /boot/grub2/x86_64-efi type btrfs (rw,relatime,compress=zlib:3,space_cache,subvolid=265,subvol=/@/boot/grub2/x86_64-efi)
/dev/sda2 on /boot/grub2/i386-pc type btrfs (rw,relatime,compress=zlib:3,space_cache,subvolid=266,subvol=/@/boot/grub2/i386-pc)
/dev/sda2 on /usr/local type btrfs (rw,relatime,compress=zlib:3,space_cache,subvolid=259,subvol=/@/usr/local)
/dev/sda2 on /root type btrfs (rw,relatime,compress=zlib:3,space_cache,subvolid=262,subvol=/@/root)
/dev/sda2 on /tmp type btrfs (rw,relatime,compress=zlib:3,space_cache,subvolid=260,subvol=/@/tmp)
/dev/sda2 on /home type btrfs (rw,relatime,compress=zlib:3,space_cache,subvolid=264,subvol=/@/home)
/dev/sda2 on /srv type btrfs (rw,relatime,compress=zlib:3,space_cache,subvolid=261,subvol=/@/srv)
/dev/sda2 on /opt type btrfs (rw,relatime,compress=zlib:3,space_cache,subvolid=263,subvol=/@/opt)
/dev/sda2 on /var type btrfs (rw,relatime,compress=zlib:3,space_cache,subvolid=258,subvol=/@/var)
/dev/sda1 on /boot/efi type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=949,iocharset=iso8859-1,shortname=mixed,errors=remount-ro)
tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,size=400980k,mode=700,uid=1000,gid=100)
fusectl on /sys/fs/fuse/connections type fusectl (rw,nosuid,nodev,noexec,relatime)
gvfsd-fuse on /run/user/1000/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,relatime,user_id=1000,group_id=100)
tracefs on /sys/kernel/debug/tracing type tracefs (rw,nosuid,nodev,noexec,relatime)
/dev/sda2 on /mnt type btrfs (rw,relatime,compress=zlib:3,space_cache,subvolid=5,subvol=/)

이처럼, fstab 에는 / 에만 compress 를 줬지만, 나머지 서브볼륨에 모두 compress 가 적용되었음을 볼 수 있다.

아니면, compsize(apt install btrfs-compsize) 를 사용하여 직접 확인할 수도 있다.

$ sudo compsize .
Processed 13 files, 5 regular extents (5 refs), 7 inline.
Type       Perc     Disk Usage   Uncompressed Referenced  
TOTAL      100%       33K          33K          29K       
none       100%       33K          33K          29K

compress 가 사용되지 않은 서브볼륨이라서 그냥 100% 로 나온다.
(아직 compress 를 적용하질 않아서 이런데, 나중에 적용해보고 결과를 바꿔 기록하자.)

만약, 특정 디렉토리에 한해 압축을 사용하지 않게 하려면 다음 명령을 사용한다.

sudo btrfs property set <DIR> compression none

이 내용에 대해선 다른 글에 자세한 사항 및 실험 결과를 정리했다.

….
꽃삽질은 언제까지 계속되려나..

안녕하세요. 글 남겨주셔서 고맙습니다.