2015-12-04 9 views
1

У меня есть 5 петлевых устройств с резервными файлами в виде сырых 40 МБ файлов в папке/tmp.losetup -d не работает

$ losetup -l 
NAME  SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE 
/dev/loop1   0  0   1 0 /tmp/1 
/dev/loop2   0  0   0 0 /tmp/2 
/dev/loop3   0  0   0 0 /tmp/3 
/dev/loop4   0  0   0 0 /tmp/4 
/dev/loop5   0  0   0 0 /tmp/5 

Я создаю массив рейдов для первых 4 устройств, использующих lvm. Следовательно, первые 4 устройств становятся все заняты следующим образом:

$ lsblk 
NAME     MAJ:MIN RM SIZE RO TYPE MOUNTPOINT 
sda      8:0 0 931.5G 0 disk 
├─sda1     8:1 0 100M 0 part /boot/efi 
├─sda2     8:2 0 900M 0 part 
├─sda3     8:3 0 128M 0 part 
├─sda4     8:4 0 372.6G 0 part 
├─sda5     8:5 0 140.5G 0 part/
├─sda6     8:6 0 15G 0 part 
├─sda7     8:7 0 186.3G 0 part 
├─sda8     8:8 0 37.3G 0 part [SWAP] 
├─sda9     8:9 0 93.1G 0 part 
└─sda10     8:10 0 40.8G 0 part 
loop1      7:1 0 78.1M 0 loop 
├─vol_vg-raid4_rmeta_0 252:0 0  4M 0 lvm 
│ └─vol_vg-raid4  252:8 0 48M 0 lvm 
└─vol_vg-raid4_rimage_0 252:1 0 16M 0 lvm 
    └─vol_vg-raid4  252:8 0 48M 0 lvm 
loop2      7:2 0 78.1M 0 loop 
├─vol_vg-raid4_rmeta_1 252:2 0  4M 0 lvm 
│ └─vol_vg-raid4  252:8 0 48M 0 lvm 
└─vol_vg-raid4_rimage_1 252:3 0 16M 0 lvm 
    └─vol_vg-raid4  252:8 0 48M 0 lvm 
loop3      7:3 0 78.1M 0 loop 
├─vol_vg-raid4_rmeta_2 252:4 0  4M 0 lvm 
│ └─vol_vg-raid4  252:8 0 48M 0 lvm 
└─vol_vg-raid4_rimage_2 252:5 0 16M 0 lvm 
    └─vol_vg-raid4  252:8 0 48M 0 lvm 
loop4      7:4 0 78.1M 0 loop 
├─vol_vg-raid4_rmeta_3 252:6 0  4M 0 lvm 
│ └─vol_vg-raid4  252:8 0 48M 0 lvm 
└─vol_vg-raid4_rimage_3 252:7 0 16M 0 lvm 
    └─vol_vg-raid4  252:8 0 48M 0 lvm 

теперь попробуйте удалить устройство обратной связи 1. Я не получаю никаких предупреждений/ошибок на консоли или в dmseg:

$ sudo losetup -d /dev/loop1 
[email protected]:~$ 

Теперь я перечислите все устройства в следующем порядке:

$ losetup -l 
NAME  SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE 
/dev/loop1   0  0   1 0 /tmp/1 
/dev/loop2   0  0   0 0 /tmp/2 
/dev/loop3   0  0   0 0 /tmp/3 
/dev/loop4   0  0   0 0 /tmp/4 
/dev/loop5   0  0   0 0 /tmp/5 
[email protected]:~$ 

Я также вижу вывод lsblk, как я указал выше.

Я попробуйте запустить Трассирование по команде, что я пытался раньше (чтобы увидеть, если есть разрешение отказано или какой-либо другой вид ошибки, которая не сообщается), я получаю следующий результат:

$ sudo strace losetup -d /dev/loop1 
execve("/sbin/losetup", ["losetup", "-d", "/dev/loop1"], [/* 17 vars */]) = 0 
brk(0)         = 0x1985000 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc13f271000 
access("/etc/ld.so.preload", R_OK)  = -1 ENOENT (No such file or directory) 
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 
fstat(3, {st_mode=S_IFREG|0644, st_size=108331, ...}) = 0 
mmap(NULL, 108331, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fc13f256000 
close(3)        = 0 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
open("/lib/x86_64-linux-gnu/libsmartcols.so.1", O_RDONLY|O_CLOEXEC) = 3 
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260R\0\0\0\0\0\0"..., 832) = 832 
fstat(3, {st_mode=S_IFREG|0644, st_size=134536, ...}) = 0 
mmap(NULL, 2233952, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fc13ee2e000 
mprotect(0x7fc13ee4e000, 2093056, PROT_NONE) = 0 
mmap(0x7fc13f04d000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1f000) = 0x7fc13f04d000 
mmap(0x7fc13f04f000, 1632, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fc13f04f000 
close(3)        = 0 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\v\2\0\0\0\0\0"..., 832) = 832 
fstat(3, {st_mode=S_IFREG|0755, st_size=1869392, ...}) = 0 
mmap(NULL, 3972864, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fc13ea64000 
mprotect(0x7fc13ec24000, 2097152, PROT_NONE) = 0 
mmap(0x7fc13ee24000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c0000) = 0x7fc13ee24000 
mmap(0x7fc13ee2a000, 16128, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fc13ee2a000 
close(3)        = 0 
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc13f255000 
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc13f253000 
arch_prctl(ARCH_SET_FS, 0x7fc13f253740) = 0 
mprotect(0x7fc13ee24000, 16384, PROT_READ) = 0 
mprotect(0x7fc13f04d000, 4096, PROT_READ) = 0 
mprotect(0x60f000, 4096, PROT_READ)  = 0 
mprotect(0x7fc13f273000, 4096, PROT_READ) = 0 
munmap(0x7fc13f256000, 108331)   = 0 
brk(0)         = 0x1985000 
brk(0x19a6000)       = 0x19a6000 
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 
fstat(3, {st_mode=S_IFREG|0644, st_size=7216688, ...}) = 0 
mmap(NULL, 7216688, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fc13e382000 
close(3)        = 0 
stat("/sys/block", {st_mode=S_IFDIR|0755, st_size=0, ...}) = 0 
uname({sys="Linux", node="donjaffer", ...}) = 0 
stat("/dev/loop-control", {st_mode=S_IFCHR|0660, st_rdev=makedev(10, 237), ...}) = 0 
stat("/dev/loop1", {st_mode=S_IFBLK|0660, st_rdev=makedev(7, 1), ...}) = 0 
open("/dev/loop1", O_RDONLY|O_CLOEXEC) = 3 
ioctl(3, LOOP_CLR_FD)     = 0 
close(3)        = 0 
close(1)        = 0 
close(2)        = 0 
exit_group(0)       = ? 
+++ exited with 0 +++ 
[email protected]:~$ 

Я все еще вижу все устройства, использующие команду losetup. Опция -d не работает должным образом? Я также попытался размонтировать/dev/loop1, но он говорит мне, что/dev/loop1 не монтируется.

$ umount -l /dev/loop1 
umount: /dev/loop1: not mounted 
[email protected]:~$ 

Просьба помочь. Спасибо.

ответ

1

Я бы сказал, что драйвер сохраняет файл открытым до закрытия последнего дескриптора файла, который открывается на нем, поэтому файл остается в использовании и с использованием устройства цикла, пока вы его не закроете.

Это довольно распространено в Linux, фактически, если вы создаете файл и открываете его, пространство, которое он занимает в файловой системе, будет доступно только тогда, когда весь дескриптор файла, открытый на нем, будет закрыт.

Таким образом, здесь будет использоваться до тех пор, пока вы не остановите налет lvm, созданный на нем.

Как следствие, вы не можете повторно использовать loopX до его освобождения; Я думаю, вы получите сообщение об ошибке, если попытаетесь его использовать, и losetup -f не предлагает этого.

+0

-f опция - найти первое неиспользованное устройство. Кажется, losetup должен дать предупреждение/ошибку в описанном вами сценарии. Я хочу принудительно размонтировать устройство цикла, например, мы можем принудительно/лениво размонтировать другие устройства, даже если на нем есть открытые дескрипторы файлов. umount имеет параметры -f и -l. Кажется, у losetup нет этих вариантов. но он все равно должен давать некоторую форму предупреждения/ошибки. losetup -d получает выход с 0, кажется ошибкой, когда он не может успешно размонтировать устройство цикла. –

+0

Я согласен, что это может быть довольно удивительным и вводящим в заблуждение, не уверен, что это ошибка (может быть сделано специально); Кстати, в вашем случае, я бы ожидал, что драйвер рейда попросит освободить дескриптор, который он имеет на/dev/loopX; на самом деле при размонтировании драйвер файловой системы попросит освободить блок-устройство, если это не так, я не уверен, что umount -f будет работать в любом случае. – OznOg

0

Это похоже на процесс с рабочим каталогом на старой точке монтирования FS.

Неудивительно, что нет способа сообщить, какие процессы они после размонтирования.

Я поднял util-linux issue "losetup -d exits 0 when it doesn't succeed" #484, а его сопровождающий показывает, что это проблема ядра.

Я написал следующий код, чтобы напечатать предыдущее использование точки монтирования, если устройство loopback не будет автоматически удалено.

#!/bin/bash 

set -euo pipefail 
shopt -s failglob 

# Unmount the entries given in $1, (one per line) 
unmount() { 
    # https://unix.stackexchange.com/questions/9784/how-can-i-read-line-by-line-from-a-variable-in-bash 
    # You need printf '%s\n' "$var" here because if you use printf '%s' "$var" 
    # on a variable that doesn't end with a newline then the while loop will 
    # completely miss the last line of the variable. 
    # printf '%s\n' "$1" | while IFS= read -r dir; do # each mount point 
    IFS= printf '%s\n' "$1" | while read -r dir; do # each mount point 
    ! /usr/bin/mountpoint -q -- "$dir" && continue 

    # Bug: can only find processes using mountpoint before unmount 
    # https://github.com/karelzak/util-linux/issues/484 
    open_files=$(sudo lsof "$dir" 2>/dev/null || true) 
    # Exits non-zero if object not in use 
    # Avoid "WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/1000/gvfs" 

    mountpoints=$(awk -v dir="$dir" 'BEGIN{dir="^" dir "$"} $2 ~ dir {print $1}' /etc/mtab) 

    while sudo "/bin/umount" -Rdl -- "$dir"; do # returns false when already unmounted 
     # -R Recursive unmount 
     # -d Remove the associated loop device 
     # -l Lazy remove filesystem references immediately 
     # -v Verbose 
     sleep 0.01; 
    done 

    if loop_dev=$(losetup -a --list | grep --fixed-strings "$mountpoints"); then 
     printf "WARNING: loop device remains after unmount:\n%s\n" "$loop_dev" 2>&1 
     printf "%s\n" "$open_files" 2>&1 
    fi 
    done 
} 

# # List of mount points to umount before checking /etc/mtab 
# # List any contained loopback files here 
# sub_mounts='/media/backup 
# /media/backup-NEW' 
# unmount "$sub_mounts" 

# sort -r to unmount subiretories before parents: 
mtab_mounts=$(/bin/awk '$2 ~ /^\/media/ {print $2}' /etc/mtab | sort -r) 
unmount "$mtab_mounts"