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