Há uma série de postagens sobre losetup -d /dev/loop0
não remover um dispositivo lookback, mesmo que ele tenha retornado um código de retorno bem-sucedido. Acredito que a causa raiz dessas postagens é que o dispositivo de bloco tem o autoclear
sinalizador definido, então losetup
apenas chama , LOOP_CLR_FD
mas não LOOP_CTL_REMOVE
. Algum outro processo ainda deve estar segurando um descritor de arquivo, então o dispositivo de loop não é desanexado nem removido. Isso é confirmado via strace
:
$ sudo losetup -J -l | jq '.'
{
"loopdevices": [
{
"name": "/dev/loop0",
"sizelimit": 0,
"offset": 0,
"autoclear": true,
"ro": false,
"back-file": "/example/backing_file",
"dio": false,
"log-sec": 512
}
]
}
$ sudo strace -ff losetup -d /dev/loop0
...
newfstatat(AT_FDCWD, "/dev/loop-control", {st_mode=S_IFCHR|0660, st_rdev=makedev(0xa, 0xed), ...}, 0) = 0
openat(AT_FDCWD, "/dev/loop0", O_RDONLY|O_CLOEXEC) = 3
ioctl(3, LOOP_CLR_FD) = 0
close(3) = 0
...
A resposta comum é (a) procurar por todos os arquivos abertos em qualquer sistema de arquivos montado a partir do dispositivo de loop e, então, (b) desmontar o dispositivo de loop. Normalmente lsof
e /proc/**/fd
são recomendados.
Meu problema é que estou tendo esse problema para dispositivos de bloco que nunca foram montados em primeiro lugar. Não consigo, nem que a minha vida dependesse disso, descobrir qual processo está segurando um descritor de arquivo para esse dispositivo de loop e, portanto, não consigo fazê-lo fechar.
Um teste rápido do programa C mostra que posso remover o sinalizador de limpeza automática do dispositivo de bloco:
$ sudo strace -ff --verbose=ioctl /tmp/remove-autoclear
...
openat(AT_FDCWD, "/dev/loop0", O_RDONLY|O_CLOEXEC) = 3
ioctl(3, LOOP_CLR_FD) = 0
close(3) = 0
write(1, "INFO: Result of sending LOOP_CLR"..., 57) = 57
INFO: Result of sending LOOP_CLR_FD to /dev/loop0 was: 0
openat(AT_FDCWD, "/dev/loop-control", O_RDONLY|O_CLOEXEC) = 3
ioctl(3, LOOP_CTL_REMOVE, 0) = -1 EBUSY (Device or resource busy)
write(2, "ERROR(16): Sending LOOP_CTL_REMO"..., 94) = 94
ERROR(16): Sending LOOP_CTL_REMOVE to /dev/loop-control for device 0: Device or resource busy
openat(AT_FDCWD, "/dev/loop0", O_RDONLY|O_CLOEXEC) = 4
ioctl(4, LOOP_GET_STATUS, {lo_number=0, lo_offset=0, lo_flags=LO_FLAGS_AUTOCLEAR, lo_name="/example/backing_file", ...}) = 0
write(1, "INFO: Autoclear bit for /dev/loo"..., 40) = 40
INFO: Autoclear bit for /dev/loop0 is 1
ioctl(4, LOOP_SET_STATUS, {lo_number=0, lo_offset=0, lo_flags=0, lo_name="/example/backing_file", ...}) = 0
ioctl(4, LOOP_GET_STATUS, {lo_number=0, lo_offset=0, lo_flags=0, lo_name="/example/backing_file", ...}) = 0
write(1, "INFO: Successfully removed autoc"..., 56) = 56
INFO: Successfully removed autoclear bit for /dev/loop0
close(4) = 0
ioctl(3, LOOP_CTL_REMOVE, 0) = -1 EBUSY (Device or resource busy)
write(2, "ERROR(16): Sending LOOP_CTL_REMO"..., 94) = 94
ERROR(16): Sending LOOP_CTL_REMOVE to /dev/loop-control for device 0: Device or resource busy
exit_group(16) = ?
+++ exited with 16 +++
INFO: Result of sending LOOP_CLR_FD to /dev/loop0 was: 0
ERROR(16): Sending LOOP_CTL_REMOVE to /dev/loop-control for device 0: Device or resource busy
INFO: Autoclear bit for /dev/loop0 is 1
INFO: Successfully removed autoclear bit for /dev/loop0
ERROR(16): Sending LOOP_CTL_REMOVE to /dev/loop-control for device 0: Device or resource busy
$ sudo cat /sys/dev/block/7:0/loop/autoclear
0
Mas, curiosamente, isso não faz com que losetup -d /dev/loop0
falhe com um erro grave. Isso parece ser porque LOOP_CLR_FD
define o sinalizador de limpeza automática novamente. Isso não é relevante para encontrar o processo que mantém o descritor de arquivo aberto, eu apenas observei porque é "ação assustadora à distância" e explica por que losetup
nunca tenta chamar LOOP_CTL_REMOVE
.
Alguma dica sobre como encontrar o processo que contém um descritor de arquivo para /dev/loop0
que eu possa limpá-lo corretamente sem reinicializar?
$ sudo ls -l /proc/**/fd | grep loop0
$ sudo ls -l /proc/**/fd | grep backing_file
$ sudo lsof | grep loop0
$ sudo lsof | grep backing_file
$ sudo mount | grep loop
Dispositivos de bloco geralmente não são abertos com um descritor de arquivo, mas pelo kernel.
Você pode ver alguns dos acessos (não montagens) pelo in
Uma verificação muito simples é
lsblk
.Como se livrar do dispositivo de retenção
dmsetup ls
mostra qual nome pertence a qual número. Um dispositivo LVM regular é melhor removido com as ferramentas LVM. Mas como medida de último recurso, você sempre pode usar