From: wguanghao Date: Mon, 22 Sep 2025 14:58:49 +0000 (+0800) Subject: losetup: Add the --remove/-R parameter to remove loop devices X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ac42e0a8595c34e6da2778d5374f6cd7004f89a3;p=thirdparty%2Futil-linux.git losetup: Add the --remove/-R parameter to remove loop devices Signed-off-by: Wu Guanghao --- diff --git a/include/loopdev.h b/include/loopdev.h index 396ade264..d5ef85107 100644 --- a/include/loopdev.h +++ b/include/loopdev.h @@ -186,6 +186,7 @@ extern int loopcxt_next(struct loopdev_cxt *lc); extern int loopcxt_setup_device(struct loopdev_cxt *lc); extern int loopcxt_detach_device(struct loopdev_cxt *lc); +extern int loopcxt_remove_device(struct loopdev_cxt *lc); extern int loopcxt_ioctl_status(struct loopdev_cxt *lc); extern int loopcxt_ioctl_capacity(struct loopdev_cxt *lc); diff --git a/lib/loopdev.c b/lib/loopdev.c index 4836a3ab5..a32003d4b 100644 --- a/lib/loopdev.c +++ b/lib/loopdev.c @@ -1622,6 +1622,37 @@ int loopcxt_detach_device(struct loopdev_cxt *lc) return 0; } +int loopcxt_remove_device(struct loopdev_cxt *lc) +{ + int rc = -EINVAL; + int ctl, nr = -1; + const char *p, *dev = loopcxt_get_device(lc); + + if (!dev) + goto done; + + if (!(lc->flags & LOOPDEV_FL_CONTROL)) { + rc = -ENOSYS; + goto done; + } + + p = strrchr(dev, '/'); + if (!p || (sscanf(p, "/loop%d", &nr) != 1 && sscanf(p, "/%d", &nr) != 1) + || nr < 0) + goto done; + + ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC); + if (ctl >= 0) { + DBG(CXT, ul_debugobj(lc, "remove_device %d", nr)); + rc = ioctl(ctl, LOOP_CTL_REMOVE, nr); + close(ctl); + } + lc->control_ok = rc >= 0 ? 1 : 0; +done: + DBG(CXT, ul_debugobj(lc, "remove_device done [rc=%d]", rc)); + return rc; +} + int loopcxt_add_device(struct loopdev_cxt *lc) { int rc = -EINVAL; diff --git a/sys-utils/losetup.8.adoc b/sys-utils/losetup.8.adoc index 48d71ec18..4437088b8 100644 --- a/sys-utils/losetup.8.adoc +++ b/sys-utils/losetup.8.adoc @@ -36,6 +36,10 @@ Resize a loop device: *losetup* *-c* _loopdev_ +Remove a loop device: + +*losetup* *-R* _loopdev_ ... + == DESCRIPTION *losetup* is used to associate loop devices with regular files or block devices, to detach loop devices, and to query the status of a loop device. If only the _loopdev_ argument is given, the status of the corresponding loop device is shown. If no option is given, all loop devices are shown. @@ -123,6 +127,12 @@ Use the raw *--list* output format. *-J*, *--json*:: Use JSON format for *--list* output. +*-R*, *--remove* _loopdev_...:: +The parameter is not recommended for direct use. +*-d* or *-D* option to disconnect the file from the loop device, we can see a loop device +of size 0 by running 'lsblk -a'. At this point, the loop device will still in the system. +This parameter can truly remove the loop device, and there is no command or interface to view it. + include::man-common/help-version.adoc[] == ENCRYPTION diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c index efda75c03..faab3934b 100644 --- a/sys-utils/losetup.c +++ b/sys-utils/losetup.c @@ -46,6 +46,7 @@ enum { A_SET_CAPACITY, /* set device capacity */ A_SET_DIRECT_IO, /* set accessing backing file by direct io */ A_SET_BLOCKSIZE, /* set logical block size of the loop device */ + A_REMOVE, /* remove given device */ }; enum { @@ -259,6 +260,13 @@ static int detach_all_loops(struct loopdev_cxt *lc) return res; } +static int remove_loop(struct loopdev_cxt *lc) +{ + if (loopcxt_remove_device(lc)) + return -1; + return 0; +} + static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln) { size_t i; @@ -479,6 +487,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -c, --set-capacity resize the device\n"), out); fputs(_(" -j, --associated list all devices associated with \n"), out); fputs(_(" -L, --nooverlap avoid possible conflict between devices\n"), out); + fputs(_(" -R, --remove ... remove one or more devices\n"), out); /* commands options */ fputs(USAGE_SEPARATOR, out); @@ -720,6 +729,7 @@ int main(int argc, char **argv) { "show", no_argument, NULL, OPT_SHOW }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, + { "remove", required_argument, NULL, 'R' }, { NULL, 0, NULL, 0 } }; @@ -740,7 +750,7 @@ int main(int argc, char **argv) if (loopcxt_init(&lc, 0)) err(EXIT_FAILURE, _("failed to initialize loopcxt")); - while ((c = getopt_long(argc, argv, "ab:c:d:Dfhj:JlLno:O:PrvV", + while ((c = getopt_long(argc, argv, "ab:c:d:Dfhj:JlLno:O:PrvVR:", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); @@ -834,6 +844,13 @@ int main(int argc, char **argv) case 'V': print_version(EXIT_SUCCESS); + case 'R': + act = A_REMOVE; + if (loopcxt_set_device(&lc, optarg)) + err(EXIT_FAILURE, _("%s: failed to use device"), + optarg); + break; + default: errtryhelp(EXIT_FAILURE); } @@ -995,6 +1012,18 @@ int main(int argc, char **argv) warn(_("%s: set logical block size failed"), loopcxt_get_device(&lc)); break; + + case A_REMOVE: + res = remove_loop(&lc); + while (optind < argc) { + if (loopcxt_set_device(&lc, argv[optind])) + warn(_("%s: failed to use device"), + argv[optind]); + optind++; + res += remove_loop(&lc); + } + break; + default: warnx(_("bad usage")); errtryhelp(EXIT_FAILURE);