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