]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
losetup: Add the --remove/-R parameter to remove loop devices
authorwguanghao <wuguanghao3@huawei.com>
Mon, 22 Sep 2025 14:58:49 +0000 (22:58 +0800)
committerwguanghao <wuguanghao3@huawei.com>
Wed, 24 Sep 2025 02:36:27 +0000 (10:36 +0800)
Signed-off-by: Wu Guanghao <wuguanghao3@huawei.com>
include/loopdev.h
lib/loopdev.c
sys-utils/losetup.8.adoc
sys-utils/losetup.c

index 396ade2640fd1dd375d365d5351ddbc2d42a0034..d5ef85107b15332fd8cd9973160c71e6d5dc2efd 100644 (file)
@@ -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);
index 4836a3ab5de2b0125f3ebdbc7ca4b40ffdaddca1..a32003d4b0ebc00bb7c18f32148a436ea8815c4c 100644 (file)
@@ -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;
index 48d71ec185990e18317d94df5327ed7b30649a0e..4437088b8afa7e1f9dc7517659f64fd5522ec51b 100644 (file)
@@ -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
index efda75c034ea54d229b98e2267f364faaad9cdef..faab3934be16a903a5719c97ddc2b96e6b7d7368 100644 (file)
@@ -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 <loopdev>  resize the device\n"), out);
        fputs(_(" -j, --associated <file>       list all devices associated with <file>\n"), out);
        fputs(_(" -L, --nooverlap               avoid possible conflict between devices\n"), out);
+       fputs(_(" -R, --remove <loopdev>...     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);