디렉터리 마운트는 디스크를 포맷하는 일이 아니다. 이미 있는 디렉터리 트리를 다른 경로에도 보이게 하거나, 마운트된 나무를 다른 자리로 옮기는 일이다. 파일은 한 벌이고 입구만 둘이다. 복사와 다르다. 디스크에 파일시스템을 만드는 순서는 새 하드디스크를 리눅스에 달기 글에 있다.

이 글의 명령은 우분투 22.04의 util-linux 2.37과 systemd 249 기준이다.

붙일 자리는 미리 만든다

마운트의 대상은 이미 있는 디렉터리다. `mount`가 그 디렉터리를 만들어 주지는 않는다.

Bash
sudo mkdir -p /mnt/photos

대상 안에 파일이 있어도 지워지지 않는다. 마운트하는 동안만 가려지고, `umount`하면 다시 보인다. 비어 있는 디렉터리를 대상으로 쓰는 편이 헷갈리지 않는다. 가려진 파일이 있는지는 마운트 전에 `ls`로 확인한다.

원본과 대상의 권한은 마운트 후에도 원본 것을 따른다. 대상 디렉터리에 잡아 둔 권한은 마운트 중에는 보이지 않는다.

같은 내용을 다른 경로에 보이기

`mount --bind`는 원본 디렉터리를 대상 디렉터리에도 붙인다. 어느쪽에 쓴 파일이든 같은 파일이다.

Bash
sudo mount --bind /data/photos /mnt/photos
findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS /mnt/photos
df -hT /mnt/photos

`df`의 용량은 원본이 놓인 파일시스템의 용량이다. 두 번째 디스크가 생긴 것이 아니다.

bind는 그 디렉터리가 속한 파일시스템 하나만 붙인다. 원본 아래에 또 다른 마운트가 있으면 대상 쪽에는 따라오지 않는다. 예를 들어 `/data/extra`가 따로 마운트된 상태에서 `/data`를 bind하면, `/mnt/data/extra`는 그 마운트에 가려지기 전의 빈 디렉터리로 보인다.

아래의 마운트까지 같이 붙이려면 `--rbind`를 쓴다.

Bash
sudo mount --rbind /data /mnt/data

원본 마운트를 해제해도 bind로 붙인 쪽은 바로 사라지지 않는다. 같은 파일시스템을 붙인 자리가 둘이고, 둘 다 해제해야 그 파일시스템을 놓을 수 있다.

읽기 전용과 실행 금지

대상만 읽기 전용으로 만들 수 있다. 원본 경로는 그대로 쓸 수 있다. 이 시스템의 `mount`는 `bind,ro`를 한 번에 받지만, 커널은 붙이기와 옵션 변경을 한 호출로 처리하지 않는다. `mount`가 두 단계로 실행한다.

Bash
sudo mount -o bind,ro /data/photos /mnt/photos

이미 붙여 둔 뒤에 옵션만 바꿀 때는 `remount,bind`를 쓴다.

Bash
sudo mount -o remount,bind,ro /mnt/photos

이 방법으로 바꿀 수 있는 것은 `ro`, `nosuid`, `nodev`, `noexec`, `noatime`, `nodiratime`, `relatime`이다. 파일시스템 전용 옵션은 무시된다. `noexec`를 주면 그 경로에서는 파일을 실행하지 못한다. 원본 경로의 실행은 막히지 않는다.

`rbind`에 `ro`를 한꺼번에 재귀로 입히는 것은 되지 않는다. 아래 마운트마다 따로 지정한다.

파일 하나

디렉터리만이 아니라 파일도 파일에 bind할 수 있다. 대상은 디렉터리가 아니라 이미 있는 파일이어야 한다.

Bash
sudo touch /mnt/hostname
sudo mount --bind /etc/hostname /mnt/hostname

부팅 뒤에 유지하기

한 줄로 `/etc/fstab`에 적는다. 종류 칸은 `none`이고, 옵션에 `bind` 또는 `rbind`를 넣는다. 덤프와 검사 칸은 0이다. 고치기 전에 복사해 둔다.

Bash
sudo cp /etc/fstab /etc/fstab.bak
Bash
/data/photos  /mnt/photos  none  bind,x-systemd.requires-mounts-for=/data  0  0

`x-systemd.requires-mounts-for=`는 그 경로의 마운트가 끝난 뒤에 이 bind를 실행하게 한다. `/data`가 다른 디스크라면 그 디스크가 먼저 붙어야 `/data/photos`가 있다. 이 옵션이 없으면 부팅 순서에 따라 빈 디렉터리를 붙이거나 실패할 수 있다.

아래 마운트까지 포함하면 `bind` 자리에 `rbind`를 적는다. 읽기 전용은 `bind,ro`다.

저장한 뒤 재부팅 전에 확인한다.

Bash
sudo findmnt --verify
sudo mount -a
findmnt /mnt/photos

`mount -a`는 표에 있는 것을 실제로 붙인다. 표가 맞는지 보는 용도로는 `findmnt --verify`가 맞다.

systemd 유닛으로 둘 때는 파일 이름이 대상 경로와 같아야 한다. `/mnt/photos`는 `mnt-photos.mount`다. 이름은 `systemd-escape -p --suffix=mount /mnt/photos`로 만든다.

`/etc/systemd/system/mnt-photos.mount`에 다음을 둔다.

Bash
[Unit]
Description=photos directory bind
RequiresMountsFor=/data/photos

[Mount]
What=/data/photos
Where=/mnt/photos
Type=none
Options=bind

[Install]
WantedBy=multi-user.target
Bash
sudo systemctl daemon-reload
sudo systemctl enable --now mnt-photos.mount

fstab에 같은 줄을 또 두면 두 번 붙이려 해서 꼬인다. 한쪽만 쓴다.

붙은 나무를 다른 자리로 옮기기

`mount --move`는 이미 마운트된 지점을 다른 디렉터리로 옮긴다. 파일의 디스크 위치는 바뀌지 않고, 트리에 보이는 자리만 바뀐다. 원본은 마운트 지점이어야 한다. 일반 디렉터리에는 실패한다.

Bash
sudo mkdir -p /data/photos
sudo mount --move /mnt/photos /data/photos

옮긴 뒤에는 `/mnt/photos`에는 마운트 전에 가려져 있던 내용이 다시 보인다. 공유 전파가 켜진 마운트는 이동이 거절될 수 있다. 전파 상태는 다음으로 본다.

Bash
findmnt -o TARGET,PROPAGATION /

다른 마운트와의 전파

마운트에는 전파 표시가 있다.

- `shared`는 이쪽에서 새로 마운트하면 짝이 되는 쪽에도 나타난다. - `private`는 이 마운트 안에서 일어난 마운트가 밖으로 나가지 않는다. - `slave`는 위쪽에서 내려온 마운트는 받고, 이쪽에서 만든 마운트는 위로 올리지 않는다. - `unbindable`은 private이면서 다른 곳으로 bind할 수 없다.

systemd를 쓰는 시스템에서 `/`는 보통 `shared`다. 컨테이너나 다른 마운트 네임스페이스로 디렉터리를 넘길 때, 이쪽의 마운트가 밖으로 복제되지 않게 하려면 그 지점을 private이나 slave로 둔다.

Bash
sudo mount --make-rprivate /mnt/data
sudo mount --make-rslave /mnt/data

`r`이 붙은 명령은 그 아래의 마운트까지 같은 표시로 바꾼다. 이 표시는 fstab 옵션 `private`, `slave`, `shared`, `rprivate`, `rslave`, `rshared`로도 적을 수 있다.

떼어 내기

bind를 해제해도 원본 파일은 삭제되지 않는다. 대상 경로에 붙어 있던 입구만 사라진다.

Bash
sudo umount /mnt/photos

대상이 사용 중이면 실패한다. 어느 프로세스가 잡고 있는지는 다음으로 본다.

Bash
sudo fuser -vm /mnt/photos
sudo lsof +f -- /mnt/photos

`umount -R`은 그 아래의 마운트까지 해제한다. 중간에 실패하면 거기서 멈춘다. `umount -l`은 당장 트리에서만 떼고, 사용이 끝날 때 나머지를 정리한다. 아직 파일을 연 프로세스는 예전 내용을 계속 볼 수 있으므로, 데이터 디스크를 빼기 전에 쓰는 방법이 아니다.

두 디렉터리를 겹쳐 보이기

overlay는 bind와 다르다. 아래 디렉터리와 위 디렉터리를 겹쳐 하나의 경로로 보여 준다. 읽기는 위쪽을 먼저 보고, 쓰기는 위 디렉터리로 복사한 뒤 수정한다. 아래 디렉터리의 파일은 그대로다.

위 디렉터리와 작업 디렉터리는 같은 파일시스템에 있어야 하고, 작업 디렉터리는 비어 있어야 한다.

Bash
sudo mkdir -p /lower /upper /work /merged
sudo mount -t overlay overlay \
  -o lowerdir=/lower,upperdir=/upper,workdir=/work \
  /merged

`upperdir`과 `workdir`을 생략하면 읽기 전용이다. 해제는 `sudo umount /merged`다. 같은 파일시스템의 다른 입구만 필요하면 bind가 맞고, 아래층은 유지한 채 수정본만 위에 쌓을 때 overlay를 쓴다.