Назад | Перейти на главную страницу

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

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

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

- ИСПРАВИТЬ -

Проблема заключалась в том, что я сделал / etc / mtab ссылкой на / proc / mounts во время копирования системы с помощью live CD CentOS 7 и забыл об этом. Мне пришлось переустановить grub, поэтому я перешел в ОС и сделал ссылку, потому что 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)

Вот что я собрал, копаясь в исходниках для 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 флаг. Вероятно, решение этой проблемы должно быть решено с помощью более свежей команды монтирования вне дистрибутива.


Осмотр командного монтирования (недавней системы) привел меня к петля (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
#

(Синтаксис losetup здесь отличается от CentOS6).

Я подумал, что если проблема не в ядре (поскольку OP 2.6.32> 2.6.25), это может быть из-за команды mount. Чтобы проверить, я установил контейнер centos6-i686 LXC, установил strace, создал отсутствующие файлы / dev / loop * и запустил внутри полностью привилегированную оболочку (используя lxc-attachс -e option) разрешено выполнять операции монтирования:

# 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's man mount даже говорит:

Так как Linux 2.6.25 поддерживает автоматическое уничтожение устройств цикла, то любое устройство цикла, выделенное при монтировании, будет освобождено командой umount независимо в / etc / mtab.

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