]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: one iteration to detect overlap and reuse loopdev
authorKarel Zak <kzak@redhat.com>
Thu, 4 Aug 2016 09:48:26 +0000 (11:48 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 4 Aug 2016 09:48:26 +0000 (11:48 +0200)
The current code scans loopdevs to detect already used loop device and
another scan to detect overlap.

Let's use one scan only, for this purpose loopcxt_find_overlap() has
been modified to return info (rc==2) about full size and offset match.

Signed-off-by: Karel Zak <kzak@redhat.com>
lib/loopdev.c
libmount/src/context_loopdev.c

index cb925ae8ea2b97970d0ddb40cd06991b814ea367..21c8f4366ae4473845b06329992c9c894a4c634c 100644 (file)
@@ -1566,7 +1566,7 @@ int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, const char *filename,
 }
 
 /*
- * Returns: 0 = success, < 0 error, 1 not found
+ * Returns: 0 = not found, < 0 error, 1 found, 2 found full size and offset match
  */
 int loopcxt_find_overlap(struct loopdev_cxt *lc, const char *filename,
                           uint64_t offset, uint64_t sizelimit)
@@ -1590,7 +1590,7 @@ int loopcxt_find_overlap(struct loopdev_cxt *lc, const char *filename,
                                     filename, offset, sizelimit, 0);
                if (!rc)
                        continue;       /* unused */
-               if (rc != 1)
+               if (rc < 0)
                        break;          /* error */
 
                DBG(CXT, ul_debugobj(lc, "found %s backed by %s",
@@ -1609,15 +1609,29 @@ int loopcxt_find_overlap(struct loopdev_cxt *lc, const char *filename,
                        break;
                }
 
+               /* full match */
+               if (lc_sizelimit == sizelimit && lc_offset == offset) {
+                       DBG(CXT, ul_debugobj(lc, "overlapping loop device %s (full match)",
+                                               loopcxt_get_device(lc)));
+                       rc = 2;
+                       goto found;
+               }
+
+               /* overlap */
                if (lc_sizelimit != 0 && offset >= lc_offset + lc_sizelimit)
                        continue;
                if (sizelimit != 0 && offset + sizelimit <= lc_offset)
                        continue;
+
                DBG(CXT, ul_debugobj(lc, "overlapping loop device %s",
                        loopcxt_get_device(lc)));
-                       rc = 0;
-                       break;
+                       rc = 1;
+                       goto found;
        }
+
+       if (rc == 1)
+               rc = 0; /* not found */
+found:
        loopcxt_deinit_iterator(lc);
        return rc;
 }
index aabb2dd20fbea1581895df3ee46ec2eed82d5580..8ef183107e2b9e7cd686efdcba0efd28dc602ba3 100644 (file)
@@ -220,58 +220,53 @@ int mnt_context_setup_loopdev(struct libmnt_context *cxt)
                if (rc)
                        goto done_no_deinit;
 
-               rc = loopcxt_find_by_backing_file(&lc,
-                               backing_file, offset, sizelimit,
-                               LOOPDEV_FL_OFFSET | LOOPDEV_FL_SIZELIMIT);
-               if (rc < 0)
+               rc = loopcxt_find_overlap(&lc, backing_file, offset, sizelimit);
+               switch (rc) {
+               case 0: /* not found */
+                       DBG(LOOP, ul_debugobj(cxt, "not found overlaping loopdev"));
+                       loopcxt_deinit(&lc);
+                       break;
+
+               case 1: /* overlap */
+                       DBG(LOOP, ul_debugobj(cxt, "overlaping %s detected",
+                                               loopcxt_get_device(&lc)));
+                       rc = -MNT_ERR_LOOPOVERLAP;
                        goto done;
-               if (rc == 0) {
+
+               case 2: /* overlap -- full size and offset match (reuse) */
+               {
                        uint32_t lc_encrypt_type;
 
-                       DBG(LOOP, ul_debugobj(cxt, "using existing loop device %s",
+                       DBG(LOOP, ul_debugobj(cxt, "re-using existing loop device %s",
                                loopcxt_get_device(&lc)));
 
                        /* Once a loop is initialized RO, there is no
-                          way to change its parameters. */
-                       if (loopcxt_is_readonly(&lc) && !(lo_flags & LO_FLAGS_READ_ONLY)) {
+                        * way to change its parameters. */
+                       if (loopcxt_is_readonly(&lc)
+                           && !(lo_flags & LO_FLAGS_READ_ONLY)) {
+                               DBG(LOOP, ul_debugobj(cxt, "%s is read-only",
+                                               loopcxt_get_device(&lc)));
                                rc = -EROFS;
                                goto done;
                        }
 
-                       /* This is no more supported, but check to be
-                        * safe. */
-                       if (loopcxt_get_encrypt_type(&lc, &lc_encrypt_type)) {
-                               DBG(LOOP, ul_debugobj(cxt, "failed to get crypt type for device %s",
-                                       loopcxt_get_device(&lc)));
-                               rc = -MNT_ERR_LOOPDEV;
-                               goto done;
-                       }
-                       if (lc_encrypt_type != LO_CRYPT_NONE) {
+                       /* This is no more supported, but check to be safe. */
+                       if (loopcxt_get_encrypt_type(&lc, &lc_encrypt_type) == 0
+                           && lc_encrypt_type != LO_CRYPT_NONE) {
                                DBG(LOOP, ul_debugobj(cxt, "encryption no longer supported for device %s",
                                        loopcxt_get_device(&lc)));
                                rc = -MNT_ERR_LOOPOVERLAP;
                                goto done;
                        }
+                       rc = 0;
                        goto success;
                }
-               loopcxt_deinit(&lc);
-               /* No existing loop device matches. Now we need to
-                * check that no loop device overlaps our target range
-                * inside the backing file. */
-               rc = loopcxt_init(&lc, 0);
-               if (rc)
-                       goto done_no_deinit;
-
-               rc = loopcxt_find_overlap(&lc, backing_file, offset, sizelimit);
-               if (rc < 0)
-                       goto done;
-               if (rc == 0) {
-                       rc = -MNT_ERR_LOOPOVERLAP;
+               default: /* error */
                        goto done;
                }
-               loopcxt_deinit(&lc);
        }
 
+       DBG(LOOP, ul_debugobj(cxt, "not found; create a new loop device"));
        rc = loopcxt_init(&lc, 0);
        if (rc)
                goto done_no_deinit;
@@ -362,7 +357,11 @@ success:
                 * otherwise it will be auto-cleared by kernel
                 */
                cxt->loopdev_fd = loopcxt_get_fd(&lc);
-               loopcxt_set_fd(&lc, -1, 0);
+               if (cxt->loopdev_fd < 0) {
+                       DBG(LOOP, ul_debugobj(cxt, "failed to get loopdev FD"));
+                       rc = -errno;
+               } else
+                       loopcxt_set_fd(&lc, -1, 0);
        }
 done:
        loopcxt_deinit(&lc);