]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
loopdev: support LO_FLAGS_PARTSCAN flag (kernel 3.2)
authorKarel Zak <kzak@redhat.com>
Tue, 15 Nov 2011 11:35:23 +0000 (12:35 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 9 Jan 2012 22:28:43 +0000 (23:28 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
include/loopdev.h
lib/loopdev.c
partx/partx.c

index 7c7880e1b52785d54ec74d8faebd3eb63e0de9ec..238b308fefa1c01d130d3c77f6d986906c9b980d 100644 (file)
@@ -120,6 +120,8 @@ enum {
 /*
  * High-level
  */
+extern int loopmod_supports_partscan(void);
+
 extern int is_loopdev(const char *device);
 extern int loopdev_is_autoclear(const char *device);
 
@@ -173,6 +175,7 @@ extern int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type);
 extern const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc);
 extern int loopcxt_is_autoclear(struct loopdev_cxt *lc);
 extern int loopcxt_is_readonly(struct loopdev_cxt *lc);
+extern int loopcxt_is_partscan(struct loopdev_cxt *lc);
 extern int loopcxt_find_by_backing_file(struct loopdev_cxt *lc,
                                const char *filename,
                                 uint64_t offset, int flags);
index e0467abaa85d83d63e53f2ee19261e1c70ac29e9..d83124032689e9d47919810b3c2d65e78e14e4ed 100644 (file)
@@ -734,10 +734,64 @@ int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino)
        return rc;
 }
 
+/*
+ * Check if the kernel supports partitioned loop devices.
+ *
+ * Notes:
+ *   - kernels < 3.2 support partitioned loop devices and PT scanning
+ *     only if max_part= module paremeter is non-zero
+ *
+ *   - kernels >= 3.2 always support partitioned loop devices
+ *
+ *   - kernels >= 3.2 always support BLKPG_{ADD,DEL}_PARTITION ioctls
+ *
+ *   - kernels >= 3.2 enable PT scanner only if max_part= is non-zero or if the
+ *     LO_FLAGS_PARTSCAN flag is set for the device. The PT scanner is disabled
+ *     by default.
+ *
+ *  See kernel commit e03c8dd14915fabc101aa495828d58598dc5af98.
+ */
+int loopmod_supports_partscan(void)
+{
+       int rc, ret = 0;
+       FILE *f;
+
+       if (get_linux_version() >= KERNEL_VERSION(3,2,0))
+               return 1;
+
+       f = fopen("/sys/module/loop/parameters/max_part", "r");
+       if (!f)
+               return 0;
+       rc = fscanf(f, "%d", &ret);
+       fclose(f);
+       return rc = 1 ? ret : 0;
+}
+
 /*
  * @lc: context
  *
- * Returns: 1 of the autoclear flags is set.
+ * Returns: 1 if the partscan flags is set *or* (for old kernels) partitions
+ * scannig is enabled for all loop devices.
+ */
+int loopcxt_is_partscan(struct loopdev_cxt *lc)
+{
+       struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc);
+
+       if (sysfs) {
+               /* kernel >= 3.2 */
+               int fl;
+               if (sysfs_read_int(sysfs, "loop/partscan", &fl) == 0)
+                       return fl;
+       }
+
+       /* old kernels (including kernels without loopN/loop/<flags> directory */
+       return loopmod_supports_partscan();
+}
+
+/*
+ * @lc: context
+ *
+ * Returns: 1 if the autoclear flags is set.
  */
 int loopcxt_is_autoclear(struct loopdev_cxt *lc)
 {
@@ -760,7 +814,7 @@ int loopcxt_is_autoclear(struct loopdev_cxt *lc)
 /*
  * @lc: context
  *
- * Returns: 1 of the readonly flags is set.
+ * Returns: 1 if the readonly flags is set.
  */
 int loopcxt_is_readonly(struct loopdev_cxt *lc)
 {
@@ -1076,6 +1130,12 @@ int loopcxt_delete_device(struct loopdev_cxt *lc)
        return 0;
 }
 
+/*
+ * Note that LOOP_CTL_GET_FREE ioctl is supported since kernel 3.1. In older
+ * kernels we have to check all loop devices to found unused one.
+ *
+ * See kernel commit 770fe30a46a12b6fb6b63fbe1737654d28e8484.
+ */
 int loopcxt_find_unused(struct loopdev_cxt *lc)
 {
        int rc = -1;
index b4a3af7a2f4b05e4515e549ecea20ced98e2eaed..befc0d02736e33b07ce2dd0083b25f03ad17887d 100644 (file)
@@ -94,23 +94,6 @@ static int partx_flags;
 static struct loopdev_cxt lc;
 static int loopdev;
 
-/*
- * Check if the kernel supports partitioned loop devices.
- * In a near future (around linux 3.2, hopefully) this will come
- * always out of the box, until then we need to check.
- */
-static int loopmod_supports_parts(void)
-{
-       int rc, ret = 0;
-       FILE *f = fopen("/sys/module/loop/parameters/max_part", "r");
-
-       if (!f)
-               return 0;
-       rc = fscanf(f, "%d", &ret);
-       fclose(f);
-       return rc = 1 ? ret : 0;
-}
-
 static void assoc_loopdev(const char *fname)
 {
        int rc;
@@ -392,9 +375,12 @@ static int add_parts(int fd, const char *device,
        if (errfirst)
                add_parts_warnx(device, errfirst, errlast);
 
-       /* the kernel adds *all* loopdev partitions, so we should delete
-          any extra, unwanted ones, when the -n option is passed */
-       if (loopdev && (lower || upper)) {
+       /*
+        * The kernel with enabled partitions scanner for loop devices add *all*
+        * partitions, so we should delete any extra, unwanted ones, when the -n
+        * option is passed.
+        */
+       if (loopdev && loopcxt_is_partscan(&lc) && (lower || upper)) {
                for (i = 0; i < nparts; i++) {
                        blkid_partition par = blkid_partlist_get_partition(ls, i);
                        int n = blkid_partition_get_partno(par);
@@ -841,7 +827,7 @@ int main(int argc, char **argv)
                        if (what == ACT_DELETE)
                                errx(EXIT_FAILURE, _("%s: cannot delete partitions"),
                                     wholedisk);
-                       if (!loopmod_supports_parts())
+                       if (!loopmod_supports_partscan())
                                errx(EXIT_FAILURE, _("%s: partitioned loop devices unsupported"),
                                     wholedisk);
                        assoc_loopdev(wholedisk);