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 <[EMAIL PROTECTED]>
---
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 [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html