]> err.no Git - util-linux/commitdiff
mount: allow auto-destruction of loop devices
authorBernardo Innocenti <bernie@codewiz.org>
Mon, 29 Oct 2007 02:47:33 +0000 (22:47 -0400)
committerKarel Zak <kzak@redhat.com>
Tue, 19 Feb 2008 00:05:55 +0000 (01:05 +0100)
This allows a flag to be set on loop devices so that when they are closed
for the last time, they'll self-destruct.

The kernel part has been submitted to lkml by David Woodhouse.

Signed-off-by: Bernardo Innocenti <bernie@codewiz.org>
Signed-off-by: Karel Zak <kzak@redhat.com>
mount/lomount.c
mount/lomount.h
mount/loop.h
mount/mount.c

index c5d03c48b72609950913c5663ab28e32cbe2c889..ac379c0db52982742dc3cd4df9b40102bc3056f8 100644 (file)
@@ -609,7 +609,7 @@ digits_only(const char *s) {
 
 int
 set_loop(const char *device, const char *file, unsigned long long offset,
-        const char *encryption, int pfd, int *loopro) {
+        const char *encryption, int pfd, int *options) {
        struct loop_info64 loopinfo64;
        int fd, ffd, mode, i;
        char *pass;
@@ -625,22 +625,21 @@ set_loop(const char *device, const char *file, unsigned long long offset,
                }
        }
 
-       mode = (*loopro ? O_RDONLY : O_RDWR);
+       mode = (*options & SETLOOP_RDONLY) ? O_RDONLY : O_RDWR;
        if ((ffd = open(file, mode)) < 0) {
-               if (!*loopro && errno == EROFS)
+               if (!(*options & SETLOOP_RDONLY) && errno == EROFS)
                        ffd = open(file, mode = O_RDONLY);
                if (ffd < 0) {
                        perror(file);
                        return 1;
                }
+               *options |= SETLOOP_RDONLY;
        }
        if ((fd = open(device, mode)) < 0) {
                perror (device);
                close(ffd);
                return 1;
        }
-       *loopro = (mode == O_RDONLY);
-
        memset(&loopinfo64, 0, sizeof(loopinfo64));
 
        if (!(filename = canonicalize(file)))
@@ -708,6 +707,9 @@ set_loop(const char *device, const char *file, unsigned long long offset,
        }
        close (ffd);
 
+       if (*options & SETLOOP_AUTOCLEAR)
+               loopinfo64.lo_flags = LO_FLAGS_AUTOCLEAR;
+
        i = ioctl(fd, LOOP_SET_STATUS64, &loopinfo64);
        if (i) {
                struct loop_info loopinfo;
@@ -716,16 +718,30 @@ set_loop(const char *device, const char *file, unsigned long long offset,
                i = loop_info64_to_old(&loopinfo64, &loopinfo);
                if (i) {
                        errno = errsv;
+                       *options &= ~SETLOOP_AUTOCLEAR;
                        perror("ioctl: LOOP_SET_STATUS64");
                } else {
                        i = ioctl(fd, LOOP_SET_STATUS, &loopinfo);
                        if (i)
                                perror("ioctl: LOOP_SET_STATUS");
+                       else if (*options & SETLOOP_AUTOCLEAR)
+                       {
+                               i = ioctl(fd, LOOP_GET_STATUS, &loopinfo);
+                               if (i || !(loopinfo.lo_flags & LO_FLAGS_AUTOCLEAR))
+                                       *options &= ~SETLOOP_AUTOCLEAR;
+                       }
                }
                memset(&loopinfo, 0, sizeof(loopinfo));
        }
+       else if (*options & SETLOOP_AUTOCLEAR)
+       {
+               i = ioctl(fd, LOOP_GET_STATUS64, &loopinfo64);
+               if (i || !(loopinfo64.lo_flags & LO_FLAGS_AUTOCLEAR))
+                       *options &= ~SETLOOP_AUTOCLEAR;
+       }
        memset(&loopinfo64, 0, sizeof(loopinfo64));
 
+
        if (i) {
                ioctl (fd, LOOP_CLR_FD, 0);
                close (fd);
@@ -733,7 +749,13 @@ set_loop(const char *device, const char *file, unsigned long long offset,
                        free(filename);
                return 1;
        }
-       close (fd);
+
+       /*
+        * HACK: here we're leeking a file descriptor,
+        * but mount is a short-lived process anyway.
+        */
+       if (!(*options & SETLOOP_AUTOCLEAR))
+               close (fd);
 
        if (verbose > 1)
                printf(_("set_loop(%s,%s,%llu): success\n"),
index 38b3a483ade5e2e6ac173090eb19ebfeaddeaf07..a5c1ae8dbf40d3859d355c07a36ac4c68764cd42 100644 (file)
@@ -6,3 +6,6 @@ extern char * find_unused_loop_device(void);
 
 extern int loopfile_used_with(char *devname, const char *filename, unsigned long long offset);
 extern char *loopfile_used (const char *filename, unsigned long long offset);
+
+#define SETLOOP_RDONLY     (1<<0)  /* Open loop read-only */
+#define SETLOOP_AUTOCLEAR  (1<<1)  /* Automatically detach loop on close (2.6.25?) */
index 415f74798398d1e8081ab9b5fc1842045fb15e34..606885297aa487ed0bff26077d73915d8da80d48 100644 (file)
 #define LOOP_SET_STATUS64      0x4C04
 #define LOOP_GET_STATUS64      0x4C05
 
+/* Flags for loop_into{64,}->lo_flags */
+enum {
+       LO_FLAGS_READ_ONLY  = 1,
+       LO_FLAGS_USE_AOPS   = 2,
+       LO_FLAGS_AUTOCLEAR  = 4, /* New in 2.6.25 */
+};
+
 #define LO_NAME_SIZE   64
 #define LO_KEY_SIZE    32
 
index e6e733db4731a60f054c841948624b6ff67b2d5d..ccdcba531b48213d539211dd1a17f35239908a47 100644 (file)
@@ -912,9 +912,12 @@ loop_check(const char **spec, const char **type, int *flags,
       if (verbose)
        printf(_("mount: skipping the setup of a loop device\n"));
     } else {
-      int loopro = (*flags & MS_RDONLY);
+      int loop_opts = SETLOOP_AUTOCLEAR; /* always attempt autoclear */
       int res;
 
+      if (*flags & MS_RDONLY)
+        loop_opts |= SETLOOP_RDONLY;
+
       offset = opt_offset ? strtoull(opt_offset, NULL, 0) : 0;
 
       if (is_mounted_same_loopfile(node, *loopfile, offset)) {
@@ -931,7 +934,7 @@ loop_check(const char **spec, const char **type, int *flags,
          printf(_("mount: going to use the loop device %s\n"), *loopdev);
 
        if ((res = set_loop(*loopdev, *loopfile, offset,
-                           opt_encryption, pfd, &loopro))) {
+                           opt_encryption, pfd, &loop_opts))) {
          if (res == 2) {
             /* loop dev has been grabbed by some other process,
                try again, if not given explicitly */
@@ -960,8 +963,13 @@ loop_check(const char **spec, const char **type, int *flags,
       if (verbose > 1)
        printf(_("mount: setup loop device successfully\n"));
       *spec = *loopdev;
-      if (loopro)
-       *flags |= MS_RDONLY;
+
+      if (loop_opts & SETLOOP_RDONLY)
+        *flags |= MS_RDONLY;
+
+      if (loop_opts & SETLOOP_AUTOCLEAR)
+        /* Prevent recording loop dev in mtab for cleanup on umount */
+        *loop = 0;
     }
   }