[PATCH RFC] umount: allow unmounting loopdev specified by associated file

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

 



Make it possible to unmount a filesystem on a loop device if it is
specified by associated backing file. It does not attempt to unmount
anything if there are more than one loop device associated with the
given file.

Umount looks for associated loopdevice(s) only if umount is called
with the regular file as an argument.

Before:
mount -o loop -t ext2 img mnt
umount -v img
> Could not find /home/puzel/upstream/util-linux/img in mtab
> umount: img: not mounted

After:
mount -o loop -t ext2 img mnt
umount -v img
> img is associated with /dev/loop0, trying to unmount it
> /dev/loop0 has been unmounted

Addresses: https://bugzilla.novell.com/show_bug.cgi?id=666161

Signed-off-by: Petr Uzel <petr.uzel@xxxxxxx>
---
 mount/lomount.c |   58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 mount/lomount.h |    1 +
 mount/umount.c  |   22 ++++++++++++++++++++
 3 files changed, 81 insertions(+), 0 deletions(-)

diff --git a/mount/lomount.c b/mount/lomount.c
index 4d23a61..c99b7d3 100644
--- a/mount/lomount.c
+++ b/mount/lomount.c
@@ -403,6 +403,56 @@ done:
 	return -1;
 }
 
+/* Find loop device associated with given @filename. Used for unmounting loop
+ * device specified by associated backing file.
+ *
+ * returns: 1 no such device/error
+ *          2 more than one loop device associated with @filename
+ *          0 exactly one loop device associated with @filename
+ *            (@loopdev points to string containing full device name)
+ */
+int
+find_loopdev_by_backing_file(const char *filename, char **loopdev)
+{
+	struct looplist ll;
+	struct stat filestat;
+	int fd;
+	int devs_n = 0;		/* number of loop devices found */
+	char* devname;
+
+	if (stat(filename, &filestat) == -1) {
+		perror(filename);
+		return 1;
+	}
+
+	if (looplist_open(&ll, LLFLG_USEDONLY) == -1) {
+		error(_("%s: /dev directory does not exist."), progname);
+		return 1;
+	}
+
+	while((devs_n < 2) && (fd = looplist_next(&ll)) != -1) {
+		if (is_associated(fd, &filestat, 0, 0) == 1) {
+			devname = xstrdup(ll.name);
+			devs_n++;
+		}
+		close(fd);
+	}
+	looplist_close(&ll);
+
+	switch (devs_n) {
+	case 0:
+		return 1;
+	case 1:
+		*loopdev = devname;
+		return 0;
+	case 2:
+		return 2;
+	default:
+		/* should not happen */
+		return 1;
+	}
+}
+
 #ifdef MAIN
 
 static int
@@ -565,6 +615,7 @@ show_associated_loop_devices(char *filename, unsigned long long offset, int isof
 	return 0;
 }
 
+
 #endif /* MAIN */
 
 /* check if the loopfile is already associated with the same given
@@ -946,6 +997,13 @@ find_unused_loop_device (void) {
 	return 0;
 }
 
+int
+find_loopdev_by_backing_file(const char *filename, char **loopdev)
+{
+	mutter();
+	return 1;
+}
+
 #endif /* !LOOP_SET_FD */
 
 #ifdef MAIN
diff --git a/mount/lomount.h b/mount/lomount.h
index de8b76b..4acc371 100644
--- a/mount/lomount.h
+++ b/mount/lomount.h
@@ -11,6 +11,7 @@ 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);
 extern char *loopdev_get_loopfile(const char *device);
+extern int find_loopdev_by_backing_file(const char *filename, char **loopdev);
 
 
 #define SETLOOP_RDONLY     (1<<0)  /* Open loop read-only */
diff --git a/mount/umount.c b/mount/umount.c
index 468fb60..e6d7483 100644
--- a/mount/umount.c
+++ b/mount/umount.c
@@ -509,6 +509,28 @@ umount_file (char *arg) {
 	}
 
 	file = canonicalize(arg); /* mtab paths are canonicalized */
+
+	/* if file is a regular file, check if it is associated
+	 * with some loop device
+	 */
+	struct stat statbuf;
+	if (!stat(file, &statbuf) && S_ISREG(statbuf.st_mode)) {
+		char *loopdev = NULL;
+		switch (find_loopdev_by_backing_file(file, &loopdev)) {
+		case 0:
+			if (verbose)
+				printf(_("%s is associated with %s, trying to unmount it\n"),
+				       arg, loopdev);
+			file = loopdev;
+			break;
+		case 2:
+			if (verbose)
+				printf(_("%s is associated with more than one loop device: not unmounting\n"),
+				       arg);
+			break;
+		}
+	}
+
 	if (verbose > 1)
 		printf(_("Trying to unmount %s\n"), file);
 
-- 
1.7.1


Petr

--
Petr Uzel
IRC: ptr_uzl @ freenode

Attachment: pgpaIOAgzImq7.pgp
Description: PGP signature


[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