web-dev-qa-db-ja.com

ループデバイスはマウント時に自動デタッチしません

Squashfsファイルをアンマウントするバックアップスクリプトがあります。バックアップを実行してから、再度マウントします。スクリプトの簡略版は次のとおりです。

umount /home/backup/auto/mnt/os
mksquashfs /src-dir /home/backup/auto/os.sqfs.img
mount -t squashfs -o loop /home/backup/auto/os.sqfs.img /home/backup/auto/mnt/os

アイデアは、バックアップされたデータに常にアクセスできるようにすることです。

そして、これは長い間機能しました。しかし、十分なループバックデバイスがないというエラーが発生し、umountがmountでマウントされたループデバイスをデタッチしなくなったことがわかりました。

最近、2つの大きな変更がありました。

  1. カーネルを2.6.32-754.11.1.el6.i686に更新しました
  2. OSをSSDに移動しました。

新しいカーネルアップデート2.6.32-754.12.1.el6があることに気付いたので、アップデートしましたが、問題は修正されませんでした。

OS:CentOS 6.10 i686

更新:これは障害のあるシステムにあります:

# strace -e trace=ioctl,mount mount -t squashfs -o loop os.sqfs.img mnt/os
ioctl(3, LOOP_GET_STATUS, {number=0, offset=0, flags=0, name="/home/squash/web.img", ...}) = 0
ioctl(3, LOOP_GET_STATUS, {number=0, offset=0, flags=0, name="/home/squash/web.img", ...}) = -1 ENXIO (No such device or address)
ioctl(4, LOOP_SET_FD, 0x3)              = 0
ioctl(4, LOOP_SET_STATUS64, {offset=0, number=0, flags=0, file_name="/home/backup/auto/os.sqfs.img", ...}) = 0
mount("/dev/loop1", "mnt/os", "squashfs", MS_MGC_VAL, NULL) = 0
+++ exited with 0 +++

# cat /etc/mtab|grep 'mnt/os'
/dev/loop1 /home/backup/auto/mnt/os squashfs ro,relatime 0 0

# ls -la /etc/mtab
lrwxrwxrwx. 1 root root 12 Apr 17 02:53 /etc/mtab -> /proc/mounts

# notice that here there is no even the umount call. Am I missing something?
# strace -e trace=ioctl,umount,mount umount mnt/os
+++ exited with 0 +++

そして、これはすべての同じバージョンを持つ別のシステム上にありますが、64ビットです:

# strace -e trace=ioctl,mount mount -t squashfs -o loop os.sqfs.img mnt/os
ioctl(3, LOOP_GET_STATUS, {number=0, offset=0, flags=0, name="/storage/backup/auto/home.sqfs.img", ...}) = 0
ioctl(3, LOOP_GET_STATUS, {number=1, offset=0, flags=0, name="/storage/backup/auto/mail.sqfs.img", ...}) = 0
ioctl(3, LOOP_GET_STATUS, {number=1, offset=0, flags=0, name="/storage/backup/auto/mail.sqfs.img", ...}) = -1 ENXIO (No such device or address)
ioctl(4, LOOP_SET_FD, 0x3)              = 0
ioctl(4, LOOP_SET_STATUS64, {offset=0, number=0, flags=0, file_name="/storage/backup/auto/os.sqfs.img", ...}) = 0
mount("/dev/loop2", "mnt/os", "squashfs", MS_MGC_VAL, NULL) = 0
+++ exited with 0 +++

# strace -e trace=ioctl,umount,mount umount mnt/os
umount("/storage/backup/auto/mnt/os", 0) = 0
ioctl(3, LOOP_CLR_FD)                   = 0
+++ exited with 0 +++

# losetup -a
/dev/loop0: [0904]:35656625 (/storage/backup/auto/home.sqfs.img)
/dev/loop1: [0904]:35656626 (/storage/backup/auto/mail.sqfs.img)

良いシステムでもLO_FLAGS_AUTOCLEARが表示されません。しかし、私はumountの違いを見ます。

再インストールしましたutil-linux-ng-それは役に立たなかった。このパッケージの更新はなく、更新されたことはありません。多分それはカーネルに関連しています。 64ビットOSで問題なく動作する理由を迷います。 32ビットVMをインストールして、同じことができるかどうかをテストする場合があります。

-修正-

問題は、CentOS7のライブCDを使用してシステムコピー中に/ etc/mtabを/ proc/mountsにリンクさせたのですが、それを忘れていました。 grubを再インストールする必要があったので、grub-installが機能していなかったため、OSにchrootしてリンクを作成しました。復元するのを忘れました。私はこれを次のように修正しました:

rm -f/etc/mtab && cat/proc/mounts | grep -v rootfs>/etc/mtab

だから今それは動作します:

root@home auto# smount os.sqfs.img mnt/os
root@home auto# losetup -a
/dev/loop0: [0816]:7090072 (/home/squash/web.img)
/dev/loop1: [0816]:7864675 (/home/backup/auto/os.sqfs.img)
/dev/loop4: [0816]:7864569 (/home/backup/auto/web.sqfs.img)
root@home auto# umount mnt/os
root@home auto# losetup -a
/dev/loop0: [0816]:7090072 (/home/squash/web.img)
/dev/loop4: [0816]:7864569 (/home/backup/auto/web.sqfs.img)
1
NickSoft

これは、CentOS6に含まれているutil-linux-ng2.17.2のソースを調べて集めたものです。

2.6.37未満のカーネルでは、Linuxでは、後でループデバイスを自動クリアするために、ループマウントされたファイルシステムのエントリを/etc/mtabに書き込む必要があります。マウント時に/etc/mtabが書き込み可能でない場合、またはエントリが/etc/mtabから削除された場合、ループデバイスは自動クリアされません。 2.6.37以上のカーネルでは、カーネルはループデバイスのバッキングストアパスを記憶しており、/etc/mtabにある必要はありません。

/etc/mtabchattr +i /etc/mtabで不変にすることで、CentOS6.10でこれを再現することができました。単に削除するだけでは不十分でした。少なくとも部分的なマウントテーブルを使用して再作成されます。これは通常の操作では発生しないはずなので、このファイルが不変に設定されている場合は、管理者のミスまたはセキュリティの侵害を探す必要があります。

古いLinuxシステムに/etc/mtabが存在しないか不完全な場合は、/proc/mountsからコピーを作成できます。ただし、最近のLinuxシステムではこれを行わないでください。代わりに、/etc/mtab/proc/self/mountsへのシンボリックリンクであり、その場所にマウントテーブルが必要な古いコードとの下位互換性のために残されています。

3
Michael Hampton

TL; DR:カーネルの問題ではないようですが、ループデバイスのLO_FLAGS_AUTOCLEARフラグを設定しないため、mountコマンドが期待どおりに動作しません。最近のoutof-distributionmountコマンドを使用すると、おそらくそれを解決できるはずです。


(最近のシステムの)コマンドマウントを階層化すると、 loop(4) のフラグLO_FLAGS_AUTOCLEARにつながりました:

LO_FLAGS_AUTOCLEAR (since Linux 2.6.25)
    The loopback device will autodestruct on last close.

したがって、私の「モダン」マウントコマンドは、次のようにこのioctlを正常に発行します。

# strace -e trace=ioctl,mount mount -o loop /tmp/block.img /mnt/
ioctl(3, LOOP_CTL_GET_FREE)             = 0
ioctl(4, LOOP_SET_FD, 3)                = 0
ioctl(4, LOOP_SET_STATUS64, {lo_offset=0, lo_number=0, lo_flags=LO_FLAGS_AUTOCLEAR, lo_file_name="/tmp/block.img", ...}) = 0
ioctl(3, BLKGETSIZE64, [1073741824])    = 0
ioctl(3, CDROM_GET_CAPABILITY, 0)       = -1 EINVAL (Invalid argument)
ioctl(3, BLKSSZGET, [512])              = 0
mount("/dev/loop0", "/mnt", "ext4", MS_MGC_VAL, NULL) = 0
+++ exited with 0 +++
# umount /mnt
# losetup -l
#

(ここでのlosetup構文はCentOS6とは異なります)。

問題がカーネルにない場合(OPの2.6.32> 2.6.25以降)、mountコマンドが原因である可能性があると思いました。確認するために、centos6-i686 LXCコンテナーをインストールし、straceをインストールし、不足している/ dev/loop *ファイルを作成し、マウント操作の実行を許可された完全に特権のあるシェルを内部で実行しました(lxc-attach-eオプションを使用) :

# lxc-attach -e -n centos6-i686
[root@centos6-i686 ~]# cat /etc/centos-release 
CentOS release 6.10 (Final)
# dd if=/dev/zero of=/tmp/block.img bs=1 count=1 seek=$((2**30-1))
[...]
# ls -lh /tmp/block.img 
-rw-r--r--. 1 root root 1.0G Apr 22 19:06 /tmp/block.img
# mkfs.ext4 /tmp/block.img 
[...]
# strace -e trace=ioctl,mount mount -o loop /tmp/block.img /mnt/
ioctl(3, LOOP_GET_STATUS, {number=0, offset=0, flags=0, name="", ...}) = -1 ENXIO (No such device or address)
ioctl(4, LOOP_SET_FD, 0x3)              = 0
ioctl(4, LOOP_SET_STATUS64, {offset=0, number=0, flags=0, file_name="/tmp/block.img", ...}) = 0
ioctl(3, BLKGETSIZE64, 1073741824)      = 0
ioctl(3, CDROM_GET_CAPABILITY or SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, 0) = -1 EINVAL (Invalid argument)
mount("/dev/loop0", "/mnt/", "ext4", MS_MGC_VAL, NULL) = 0
+++ exited with 0 +++
# umount /mnt
# losetup --show /dev/loop0
/dev/loop0: [003f]:1756539 (/tmp/block.img)
# losetup -d /dev/loop0
#

明らかに、ioctlはクリアフラグで発行されておらず、これがループデバイスのリークを引き起こしていました。ソースを見ると、この機能は長い間存在しており、util-linux 2.17.2(CentOS6のバージョン)に存在しているようです。 CentOS6のman mountは、次のようにさえ伝えています。

Linux 2.6.25はループデバイスの自動破壊をサポートしているため、mountによって割り当てられたループデバイスは、/ etc/mtab上でumountによって個別に解放されます。

そのため、なぜ機能しなかったのかわかりません。バグのようです(または、これは私の環境に関連している可能性があります:64ビットカーネル5.0.xなど)。

2
A.B