Шлейфовое устройство не отключается автоматически

У меня есть сценарий резервного копирования, в котором я отключаю файл 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.

В последнее время у меня было два основных изменения:

  1. Я обновил ядро ​​до 2.6.32-754.11.1.el6.i686
  2. Я переместил ОС на SSD.

Я только что заметил, что есть новое обновление ядра 2.6.32-754.12.1.el6, поэтому я обновил, но это не решило проблему.

ОС: 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 в хорошей системе тоже. но я вижу разницу в размерах.

Я переустанавливал util-linux-ng - это не помогло. Для этого пакета нет обновлений, и он никогда не обновлялся. Может быть, это связано с ядром. Я удивляюсь, почему на 64-битной ОС все работает нормально. Я мог бы установить 32-битную виртуальную машину, чтобы проверить, будет ли она делать то же самое.

- FIX -

Проблема заключалась в том, что я сделал /etc/mtab ссылку на /proc/mounts во время копирования системы, используя живой компакт-диск CentOS 7, и я забыл об этом. Мне пришлось переустановить grub, поэтому я сделал chroot для os и сделал ссылку, потому что grub-install не работал. Я забыл восстановить его. Я исправил это:

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)

2 ответа

Решение

Вот что я собрал, покопавшись в источнике для util-linux-ng 2.17.2, который был включен в CentOS 6:

В ядрах < 2.6.37 Linux требует записи в /etc/mtab для файловых систем, смонтированных в петле, чтобы позже автоматически очистить устройство петли. Если /etc/mtab недоступно для записи во время монтирования или запись была удалена из /etc/mtab тогда устройство петли не будет очищено автоматически. В ядрах>= 2.6.37 ядро ​​запоминает путь к хранилищу резервных копий устройства цикла и не обязательно находиться в /etc/mtab,

Я смог воспроизвести это на CentOS 6.10, сделав /etc/mtab неизменный, с chattr +i /etc/mtab, Простого удаления было недостаточно; это было бы воссоздано по крайней мере с частичной таблицей монтирования. Это не то, что должно происходить при нормальной работе, поэтому, если вы обнаружите, что этот файл установлен неизменяемым, вам следует искать ошибку администратора или компромисс в плане безопасности.

Если /etc/mtab не существует или неполна в вашей старой системе Linux, вы можете сделать копию из /proc/mounts, Не делайте этого в современных системах Linux, хотя, где /etc/mtab вместо этого является символической ссылкой на /proc/self/mounts оставлен на месте для обратной совместимости с древним кодом, который ожидает таблицу монтирования в этом месте.

TL;DR: похоже, проблема не в ядре, а в mount команда работает не так, как ожидалось, не устанавливая устройства цикла LO_FLAGS_AUTOCLEAR флаг. Использование более поздней команды монтирования вне дистрибутива, вероятно, должно решить эту проблему.


Использование команды mount (в недавней системе) привело меня к флагу loop(4)LO_FLAGS_AUTOCLEAR:

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

Так что моя "современная" команда mount успешно выдает этот 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
#

(Синтаксис проигрыша здесь отличается от CentOS6).

Я думал, что если проблема не в ядре (начиная с версии 2.6.32 > 2.6.25), это может быть из команды mount. Для проверки я установил LXC-контейнер centos6-i686, установил strace, создал отсутствующие файлы /dev/loop* и запустил полностью привилегированную оболочку внутри (используя lxc-attach"s -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, будет освобождено umount независимо в / etc / mtab.

Поэтому я не знаю, почему это не сработало, и похоже, что это ошибка (или это может быть связано с моей средой: 64-битное ядро ​​5.0.x и т. Д.).

Другие вопросы по тегам