はじめに
今まで何となく使っていたmount
コマンドについて、理解している部分やよくわかっていない部分を整理したいなと思い書きました。作業環境はMac上のVirtualBoxで動かしているCentOS8です。
ファイルシステム
Unixシステムでは全てのファイルは/
をルートとしたツリー構造になっています。
$ tree -L 1 / / ├── bin -> usr/bin ├── boot ├── dev ├── etc ├── home ├── lib -> usr/lib ├── lib64 -> usr/lib64 ├── media ├── mnt ├── opt ├── proc ├── root ├── run ├── sbin -> usr/sbin ├── srv ├── swapfile ├── sys ├── tmp ├── usr ├── vagrant └── var
データが保存できるSSDやHDDなどのストレージデバイスにファイルシステムを作って/
にマウントしています。以下のように確認できます。
$ findmnt / TARGET SOURCE FSTYPE OPTIONS / /dev/sda1 xfs rw,relatime,attr2,inode64,noquota
VirtualBoxではストレージデバイスの容量を増やせます。30GiBから1GiB増やしました。*1
$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 31G 0 disk └─sda1 8:1 0 30G 0 part /
増えた1GiBの部分にパーティションを新たに作ります。
$ sudo fdisk /dev/sda Welcome to fdisk (util-linux 2.32.1). 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/sda: 31 GiB, 33285996544 bytes, 65011712 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: 0x615169d8 Device Boot Start End Sectors Size Id Type /dev/sda1 * 2048 62914526 62912479 30G 83 Linux Command (m for help): n Partition type p primary (1 primary, 0 extended, 3 free) e extended (container for logical partitions) Select (default p): p Partition number (2-4, default 2): First sector (62914527-65011711, default 62914560): Last sector, +sectors or +size{K,M,G,T,P} (62914560-65011711, default 65011711): Created a new partition 2 of type 'Linux' and of size 1 GiB. Command (m for help): p Disk /dev/sda: 31 GiB, 33285996544 bytes, 65011712 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: 0x615169d8 Device Boot Start End Sectors Size Id Type /dev/sda1 * 2048 62914526 62912479 30G 83 Linux /dev/sda2 62914560 65011711 2097152 1G 83 Linux Command (m for help): w The partition table has been altered. Syncing disks.
パーティションが作成されました。
$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 31G 0 disk ├─sda1 8:1 0 30G 0 part / └─sda2 8:2 0 1G 0 part
新しく作ったパーティションにファイルシステムを作ります。ファイルシステムの種類にext4を指定しました。
$ sudo mkfs -t ext4 /dev/sda2 mke2fs 1.44.3 (10-July-2018) Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: fd1c3d2f-633c-45b6-a0b1-32b156544e8d Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done
直接ストレージデバイスへの書き込み
既にファイルシステムが作られていると以下のように確認されます。
$ sudo mkfs -t ext4 /dev/sda2 mke2fs 1.44.3 (10-July-2018) /dev/sda2 contains a ext4 file system last mounted on Mon Mar 9 01:17:11 2020 Proceed anyway? (y,N)
mkfsコマンドがext4のディスクレイアウトを検知しているのかもしれません*2。ストレージデバイスには直接書き込むこともできるので以下のようにしてランダムな値を書き込んだらmkfs
時の確認がされなくなりました。
$ sudo dd bs=1024 count=1024 if=/dev/urandom of='/dev/sda2'
仮想ファイルシステムとmount
mountコマンドはmount -t type device dir
というような書式で、デバイスをファイルシステム上の指定の場所にアタッチします。先程作ったファイルシステムを/mnt
にマウントします。*3
$ sudo mount -t ext4 /dev/sda2 /mnt
$ findmnt /mnt
TARGET SOURCE FSTYPE OPTIONS
/mnt /dev/sda2 ext4 rw,relatime
今マウントした/mnt
の中にRAMをストレージとしたtmpfsを作ってみます。
$ sudo mkdir /mnt/tmp $ sudo mount -t tmpfs tmpfs /mnt/tmp $ findmnt /mnt/tmp TARGET SOURCE FSTYPE OPTIONS /mnt/tmp tmpfs tmpfs rw,relatime
tmpfsは電源を落とすと消えるので、一時的なデータを保存するのに使います。
ちなみに/
はxfs
というファイルシステムになっていました。
$ findmnt / TARGET SOURCE FSTYPE OPTIONS / /dev/sda1 xfs rw,relatime,attr2,inode64,noquota
このように様々な種類のファイルシステム/
をルートとしたツリー構造のどこかにマウントできます。そしてファイルシステムの違いを意識せずにファイルという概念でデータを扱えます。これはカーネルの仮想ファイルシステムという仕組みによるものです*4。
関連コマンドなど
mount
に引数がなければ、現在マウントされているものがリストされます。
$ mount sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime) proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) devtmpfs on /dev type devtmpfs (rw,nosuid,size=231496k,nr_inodes=57874,mode=755) securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime) tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev) devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000) ...
devpts
などの仮想的なファイルシステム*5やBindマウントを除いたものはdf
コマンドでも一覧が見れます。
$ df Filesystem Size Used Avail Use% Mounted on devtmpfs 227M 0 227M 0% /dev tmpfs 239M 0 239M 0% /dev/shm tmpfs 239M 6.5M 233M 3% /run tmpfs 239M 0 239M 0% /sys/fs/cgroup /dev/sda1 30G 24G 6.3G 80% / tmpfs 48M 0 48M 0% /run/user/1000 /dev/sda2 976M 2.6M 907M 1% /mnt tmpfs 239M 0 239M 0% /mnt/tmp
起動時に自動でマウントするには/etc/fstab
に書き込みます。
$ cat /etc/fstab # # /etc/fstab # Created by anaconda on Fri Oct 25 18:37:15 2019 # # Accessible filesystems, by reference, are maintained under '/dev/disk/'. # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info. # # After editing this file, run 'systemctl daemon-reload' to update systemd # units generated from this file. # UUID=d5f5b677-6350-416d-b1d3-47d723d94d88 / xfs defaults 0 0 /swapfile none swap defaults 0 0
ストレージデバイスのUUIDなどはblkid
で調べられます。
$ sudo blkid /dev/sda1: UUID="d5f5b677-6350-416d-b1d3-47d723d94d88" TYPE="xfs" PARTUUID="615169d8-01" /dev/sda2: UUID="fd1c3d2f-633c-45b6-a0b1-32b156544e8d" TYPE="ext4" PARTUUID="615169d8-02"
Bindマウント
mount --bind olddir newdir
というような書式でディレクトリもマウントできます。
$ tree . . ├── A │ └── a └── B └── b 2 directories, 2 files $ sudo mount --bind A B $ tree . . ├── A │ └── a └── B └── a 2 directories, 2 files
デバイスをマウントするのとは違い、既にマウントされているファイルシステムのツリー構造上のどこか一部(例ではAディレクトリ)を既にマウントされている別の部分(例ではBディレクトリ)に再度マウントしています。結果的にBの中身がAになっています。
rbind
--bind
では以下のように再帰的にマウントがされません。
$ tree . . ├── A │ └── a ├── B │ └── b └── C ├── c └── D └── d 4 directories, 4 files $ sudo mount --bind A C/D $ sudo mount --bind C B $ tree . . ├── A │ └── a ├── B │ ├── c │ └── D │ └── d └── C ├── c └── D └── a 5 directories, 5 files
A
をC/D
にマウントして、C
をB
にマウントしたのですが、B/D
の内容が元のD
のままになっています。
--rbind
で再帰的にマウントされるようになります。
$ sudo umount B $ sudo mount --rbind C B $ tree . . ├── A │ └── a ├── B │ ├── c │ └── D │ └── a └── C ├── c └── D └── a 5 directories, 5 files
umount
コマンドでマウントの取り消し(アンマウント)をしています。B
にC
ディレクトリをマウントすると、C/D
のマウントもされています。
Mount propagation
Bindマウントによってファイルシステムの一部が複数のディレクトリ間で共有された状態になったといえます。共有されたディレクトリの中でさらにマウントをするとどうなるでしょうか?その時の挙動について細かい設定ができます。
先程のままA/F
ディレクトリを作ります。
$ mkdir A/F $ tree . . ├── A │ ├── a │ └── F ├── B │ ├── c │ └── D │ ├── a │ └── F └── C ├── c └── D ├── a └── F 8 directories, 5 files
さらにG
とG/g
を作ります。
$ mkdir G $ touch G/g $ tree . . ├── A │ ├── a │ └── F ├── B │ ├── c │ └── D │ ├── a │ └── F ├── C │ ├── c │ └── D │ ├── a │ └── F └── G └── g 9 directories, 6 files
そして、A/F
に今作ったG
をマウントします。
$ sudo mount --bind G A/F $ tree . . ├── A │ ├── a │ └── F │ └── g ├── B │ ├── c │ └── D │ ├── a │ └── F │ └── g ├── C │ ├── c │ └── D │ ├── a │ └── F │ └── g └── G └── g 9 directories, 9 files
A
ディレクトリの中身はC/D
ディレクトリやB/D
ディレクトリに共有されている状態でした。上記のようにG
ディレクトリのマウントも共有されました。これは/
ディレクトリがshared
というマウントの設定になっていたからです。
$ findmnt -o TARGET,PROPAGATION /
TARGET PROPAGATION
/ shared
この影響をなくすにはslaveという設定をします。
$ sudo umount A/F $ sudo umount A $ sudo mount --bind A A $ sudo mount --make-slave A $ findmnt -o TARGET,PROPAGATION A TARGET PROPAGATION /home/vagrant/mount-test/A private,slave
一度sudo mount --bind A A
によりマウントポイントを作る必要があります。sudo mount --make-slave A
によりslave
という属性が設定されました。これでA
ディレクトリ以下のマウントの影響が共有されないようになります。
$ sudo mount --bind G A/F $ tree . . ├── A │ ├── a │ └── F │ └── g ├── B │ ├── c │ └── D │ ├── a │ └── F ├── C │ ├── c │ └── D │ ├── a │ └── F └── G └── g 9 directories, 7 files
今回はG
ディレクトリのマウントがC/D
ディレクトリやB/D
ディレクトリに反映されていません。
A
にマウントポイントを作らずにB/D
にslave
の設定をし、G
をB/D/F
にマウントすると次のようになります。
$ sudo mount --make-slave B/D $ findmnt -o TARGET,PROPAGATION B/D TARGET PROPAGATION /home/vagrant/mount-test/B/D private,slave $ sudo mount --bind G B/D/F $ tree . . ├── A │ ├── a │ └── F ├── B │ ├── c │ └── D │ ├── a │ └── F │ └── g ├── C │ ├── c │ └── D │ ├── a │ └── F └── G └── g 9 directories, 7 files
上の例で、private
という設定もされていますが、これは--bind
した時のデフォルトの設定のようです。shared
なマウントポイントのサブディレクトリでのマウントはslave
にしていても反映されてしまいます。反映させたくない時は上の例ならばsudo mount --make-private B/D
によりprivate
にします。private,slave
ではだめなようで、先程のコマンドでprivate
だけにする必要があるようです。
結果private
にすればそのマウントポイント以下でのマウントも他でのマウントも反映されません。
だんだん混乱してきますね。表にすると次のようになります。Bindマウントであるディレクトリを2つのマウントポイントで共有しているとします。マウントポイントのうち1つを自分のディレクトリ、もう1つを相手のディレクトリとします。自分のディレクトリでのマウントが相手に影響する場合はセルの左側を○に、相手マウントが自分のディレクトリ影響する時はセルの右側を○に、そうでない時は✗にしています。*6
おわりに
mount
コマンドでは他にマウントポイントの移動やBindマウントの禁止などができます。詳しくはmount --help
やman mount
を参照ください。