]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: avoid duplicate loopdevs
authorKarel Zak <kzak@redhat.com>
Mon, 16 Jan 2012 10:28:05 +0000 (11:28 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 16 Jan 2012 10:28:05 +0000 (11:28 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
lib/loopdev.c
libmount/src/context_loopdev.c
sys-utils/mount.c

index 2035d23143076afdf78ed3f48c9a393274fc0ec6..0e22bca1cc7a38dac8be3be5e9f298458d185b15 100644 (file)
@@ -1225,7 +1225,7 @@ int loopdev_is_used(const char *device, const char *filename,
        struct stat st;
        int rc = 0;
 
-       if (!device)
+       if (!device || !filename)
                return 0;
 
        loopcxt_init(&lc, 0);
@@ -1243,6 +1243,9 @@ int loopdev_delete(const char *device)
        struct loopdev_cxt lc;
        int rc;
 
+       if (!device)
+               return -EINVAL;
+
        loopcxt_init(&lc, 0);
        rc = loopcxt_set_device(&lc, device);
        if (!rc)
index 226b562c4650615c6027decaa9e03dabffc08f65..8e9ed93aa5bb8d7ca74d31d2cd67029e2e270238 100644 (file)
@@ -69,6 +69,68 @@ int mnt_context_is_loopdev(struct libmnt_context *cxt)
        return 0;
 }
 
+
+/* Check, if there already exists a mounted loop device on the mountpoint node
+ * with the same parameters.
+ */
+static int is_mounted_same_loopfile(struct libmnt_context *cxt,
+                                   const char *target,
+                                   const char *backing_file,
+                                   uint64_t offset)
+{
+       struct libmnt_table *tb;
+       struct libmnt_iter itr;
+       struct libmnt_fs *fs;
+       struct libmnt_cache *cache;
+
+       assert(cxt);
+       assert(cxt->fs);
+       assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
+
+       if (!target || !backing_file || mnt_context_get_mtab(cxt, &tb))
+               return 0;
+
+       DBG(CXT, mnt_debug_h(cxt, "checking if %s mounted on %d",
+                               backing_file, target));
+
+       cache = mnt_context_get_cache(cxt);
+       mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
+
+       /* Search for mountpoint node in mtab, procceed if any of these has the
+        * loop option set or the device is a loop device
+        */
+       while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
+               const char *src = mnt_fs_get_source(fs);
+               const char *opts = mnt_fs_get_user_options(fs);
+               char *val;
+               size_t len;
+               int res = 0;
+
+               if (!src || !mnt_fs_match_target(fs, target, cache))
+                       continue;
+
+               if (strncmp(src, "/dev/loop", 9) == 0) {
+                       res = loopdev_is_used((char *) src, backing_file,
+                                       offset, LOOPDEV_FL_OFFSET);
+
+               } else if (opts && (cxt->user_mountflags & MNT_MS_LOOP) &&
+                   mnt_optstr_get_option(opts, "loop", &val, &len) == 0 && val) {
+
+                       val = strndup(val, len);
+                       res = loopdev_is_used((char *) val, backing_file,
+                                       offset, LOOPDEV_FL_OFFSET);
+                       free(val);
+               }
+
+               if (res) {
+                       DBG(CXT, mnt_debug_h(cxt, "%s already mounted", backing_file));
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
 int mnt_context_setup_loopdev(struct libmnt_context *cxt)
 {
        const char *backing_file, *optstr, *loopdev = NULL;
@@ -147,6 +209,11 @@ int mnt_context_setup_loopdev(struct libmnt_context *cxt)
                }
        }
 
+       if (rc == 0 && is_mounted_same_loopfile(cxt,
+                               mnt_context_get_target(cxt),
+                               backing_file, offset))
+               rc = -EBUSY;
+
        if (rc)
                goto done;
 
index de972a83dc423382f114b8f868ec6eb34c35ecb0..c81af1af917db7e0d4ad8b456e40f115018b049e 100644 (file)
@@ -286,11 +286,15 @@ try_readonly:
 
        if (!mnt_context_syscall_called(cxt)) {
                /*
-                * libmount errors
+                * libmount errors (extra library checks)
                 */
-               if (rc == -EPERM) {
+               switch (rc) {
+               case -EPERM:
                        warnx(_("only root can mount %s on %s"), src, tgt);
                        return EX_USAGE;
+               case -EBUSY:
+                       warnx(_("%s is already mounted"), src);
+                       return EX_USAGE;
                }
 
                if (src == NULL || tgt == NULL) {