Вопрос или проблема
Я создал устройство с циклическим доступом, используя losetup /dev/loop90 /tmp/disk1
, где /tmp/disk1
— это файл размером 512M, который я создал.
Затем устройство было отсоединено с помощью losetup -d /dev/loop90
.
Оно было удалено из вывода losetup -a
, но запись в /dev
и /sys/devices/virtual/block
по-прежнему присутствует. Поскольку эта запись существует, каждый раз, когда выполняется сканирование udev, также перечисляются все удаленные устройства.
Как можно полностью удалить эти устройства с циклическим доступом и удалить все записи без перезагрузки?
Насколько я могу судить, экспериментально, это поведение является нормальным.
Программа на C, подобная этой:
#include <fcntl.h>
#include <linux/loop.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
int
main(int argc, char *argv[])
{
int loopctlfd;
long devnr;
char loopname[4096];
(void)argc;
(void)argv;
loopctlfd = open("/dev/loop-control", O_RDWR);
if (loopctlfd == -1)
errExit("open: /dev/loop-control");
devnr = ioctl(loopctlfd, LOOP_CTL_GET_FREE);
if (devnr == -1)
errExit("ioctl-LOOP_CTL_GET_FREE");
sprintf(loopname, "/dev/loop%ld", devnr);
printf("%s\n", loopname);
return 0;
}
по-прежнему будет выводить имя используемого устройства в случае необходимости, хотя оно не будет повторно использовать устройства, что может быть недостатком.
Если вы абсолютно хотите очистить без перезагрузки, вы можете сделать это с помощью этой другой программы на C:
#include <errno.h>
#include <linux/loop.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main(int argc, char** argv)
{
char *end;
if (argc < 2) {
printf("Необходим номер устройства в качестве первого аргумента\n");
return 0;
}
long int dev_to_remove = strtol(argv[1], &end, 10);
if (*end != '\0' || dev_to_remove < 0 || errno != 0) {
printf("Недопустимый номер устройства\n");
return 1;
}
const int fd = open("/dev/loop-control", O_RDWR);
if (ioctl(fd, LOOP_CTL_REMOVE, dev_to_remove) < 0)
{
perror("Удаление устройства не удалось");
return 1;
}
return 0;
}
Ответ или решение
Чтобы удалить запись о loop-устройстве, которая всё ещё присутствует в /dev
и /sys/devices/virtual/block
, после его отсоединения, можно использовать специальный подход, основанный на работе с контроллером loop-устройств Linux.
Понимание проблемы
Когда вы создаёте loop-устройство с помощью команды losetup
, эта операция создает виртуальный блок устройства, который будет доступен для использования как обычное блочное устройство. После отсоединения устройства с помощью losetup -d
, информация о loop-устройстве может оставаться в системе.
Причиной тому является то, что данные в /dev/loopX
и /sys/devices/virtual/block/loopX
могут не быть сразу удалены, даже если устройство уже отмонтировано и отключено. Это может привести к тому, что при следующем сканировании udev такие устройства будут по-прежнему отображаться.
Окончательная очистка
Если вам нужно полностью удалить эти записи без перезагрузки системы, вы можете воспользоваться включенным в ядро Linux управляющим интерфейсом для loop-устройств. Для этого необходимо использовать ioctl
с командой LOOP_CTL_REMOVE
.
Пример C-кода для удаления loop-устройства
Вот C-программа, которую вы можете использовать для удаления записи loop-устройства:
#include <errno.h>
#include <linux/loop.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main(int argc, char** argv) {
char *end;
if (argc < 2) {
printf("Необходимо указать номер устройства как аргумент\n");
return 0;
}
long int dev_to_remove = strtol(argv[1], &end, 10);
if (*end != '\0' || dev_to_remove < 0 || errno != 0) {
printf("Неверный номер устройства\n");
return 1;
}
const int fd = open("/dev/loop-control", O_RDWR);
if (fd < 0) {
perror("Не удалось открыть /dev/loop-control");
return 1;
}
if (ioctl(fd, LOOP_CTL_REMOVE, dev_to_remove) < 0) {
perror("Удаление устройства не удалось");
close(fd);
return 1;
}
close(fd);
return 0;
}
Как использовать программу
-
Компиляция программы: Сохраните код в файл, например,
remove_loop_device.c
, и скомпилируйте его с помощьюgcc
:gcc remove_loop_device.c -o remove_loop_device
-
Запуск программы: Запустите с передачей номера loop-устройства, которое вы хотите удалить. Например, для удаления устройства
/dev/loop90
:sudo ./remove_loop_device 90
Общие рекомендации
- Убедитесь, что loop-устройство не используется перед удалением.
- Тщательно проверяйте номера устройств, передаваемые в программу, чтобы избежать случайного удаления используемых устройств.
Используя вышеуказанные шаги, вы сможете полностью удалить записи о loop-устройствах из вашей системы без необходимости перезагрузки, что является важным для поддержки надёжности и доступности вашего серверного окружения.