[PATCH] Allow auto-destruction of loop devices.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxx>
---
 mount/lomount.c |   33 ++++++++++++++++++++++++++++-----
 mount/lomount.h |    3 +++
 mount/loop.h    |    7 +++++++
 mount/mount.c   |   16 ++++++++++++----
 4 files changed, 50 insertions(+), 9 deletions(-)

diff --git a/mount/lomount.c b/mount/lomount.c
index 5bd8954..6aef652 100644
--- a/mount/lomount.c
+++ b/mount/lomount.c
@@ -369,7 +369,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;
@@ -385,20 +385,20 @@ 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);
 		return 1;
 	}
-	*loopro = (mode == O_RDONLY);
 
 	memset(&loopinfo64, 0, sizeof(loopinfo64));
 
@@ -467,6 +467,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;
@@ -475,16 +478,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);
@@ -492,7 +509,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"),
diff --git a/mount/lomount.h b/mount/lomount.h
index 38b3a48..a5c1ae8 100644
--- a/mount/lomount.h
+++ b/mount/lomount.h
@@ -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?) */
diff --git a/mount/loop.h b/mount/loop.h
index 951a5d1..c745209 100644
--- a/mount/loop.h
+++ b/mount/loop.h
@@ -10,6 +10,13 @@
 #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
 
diff --git a/mount/mount.c b/mount/mount.c
index 9d43e5f..6882afe 100644
--- a/mount/mount.c
+++ b/mount/mount.c
@@ -906,9 +906,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)) {
@@ -925,7 +928,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 */
@@ -954,8 +957,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;
     }
   }
 
-- 
1.5.3.4.206.g58ba4

-
To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux