summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Zak2011-11-15 12:35:23 +0100
committerKarel Zak2012-01-09 23:28:43 +0100
commit59d749c33136b85fc4a51a0af6c48cc97e3d1b31 (patch)
treebaed45bc190086fc3351684d35dce1eeae770416
parentsfdisk: use is_blkdev (diff)
downloadkernel-qcow2-util-linux-59d749c33136b85fc4a51a0af6c48cc97e3d1b31.tar.gz
kernel-qcow2-util-linux-59d749c33136b85fc4a51a0af6c48cc97e3d1b31.tar.xz
kernel-qcow2-util-linux-59d749c33136b85fc4a51a0af6c48cc97e3d1b31.zip
loopdev: support LO_FLAGS_PARTSCAN flag (kernel 3.2)
Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r--include/loopdev.h3
-rw-r--r--lib/loopdev.c64
-rw-r--r--partx/partx.c28
3 files changed, 72 insertions, 23 deletions
diff --git a/include/loopdev.h b/include/loopdev.h
index 7c7880e1b..238b308fe 100644
--- a/include/loopdev.h
+++ b/include/loopdev.h
@@ -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);
diff --git a/lib/loopdev.c b/lib/loopdev.c
index e0467abaa..d83124032 100644
--- a/lib/loopdev.c
+++ b/lib/loopdev.c
@@ -735,9 +735,63 @@ int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino)
}
/*
+ * 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;
diff --git a/partx/partx.c b/partx/partx.c
index b4a3af7a2..befc0d027 100644
--- a/partx/partx.c
+++ b/partx/partx.c
@@ -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);