summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManuel Bentele2019-06-23 15:23:45 +0200
committerManuel Bentele2019-06-23 15:23:45 +0200
commitb800dbf06bef3004aa37dc93ec6d2a311cc8ac23 (patch)
tree060505ba4fd2a3abe654dc8478ef174a9a94c5cf
parentbuild-sys: release++ (v2.34) (diff)
downloadkernel-qcow2-util-linux-b800dbf06bef3004aa37dc93ec6d2a311cc8ac23.tar.gz
kernel-qcow2-util-linux-b800dbf06bef3004aa37dc93ec6d2a311cc8ac23.tar.xz
kernel-qcow2-util-linux-b800dbf06bef3004aa37dc93ec6d2a311cc8ac23.zip
lib/losetup: added file format support
losetup can set the file format of each loop device during creation. Signed-off-by: Manuel Bentele <development@manuel-bentele.de>
-rw-r--r--include/loopdev.h14
-rw-r--r--lib/loopdev.c86
-rw-r--r--sys-utils/losetup.c68
3 files changed, 151 insertions, 17 deletions
diff --git a/include/loopdev.h b/include/loopdev.h
index 0e3a7517a..bc68e526b 100644
--- a/include/loopdev.h
+++ b/include/loopdev.h
@@ -11,6 +11,14 @@
#define LO_CRYPT_DES 2
#define LO_CRYPT_CRYPTOAPI 18
+/*
+ * loop_info.lo_file_fmt_type
+ */
+#define LO_FILE_FMT_RAW 0
+#define LO_FILE_FMT_QCOW 1
+#define LO_FILE_FMT_VDI 2
+#define LO_FILE_FMT_VMDK 3
+
#define LOOP_SET_FD 0x4C00
#define LOOP_CLR_FD 0x4C01
/*
@@ -64,6 +72,7 @@ struct loop_info64 {
uint8_t lo_crypt_name[LO_NAME_SIZE];
uint8_t lo_encrypt_key[LO_KEY_SIZE];
uint64_t lo_init[2];
+ uint32_t lo_file_fmt_type;
};
#define LOOPDEV_MAJOR 7 /* loop major number */
@@ -175,6 +184,7 @@ extern int loopcxt_ioctl_blocksize(struct loopdev_cxt *lc, uint64_t blocksize);
int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset);
int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit);
int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize);
+int loopcxt_set_file_fmt_type(struct loopdev_cxt *lc, uint32_t file_fmt_type);
int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags);
int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename);
@@ -185,6 +195,8 @@ extern int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset);
extern int loopcxt_get_blocksize(struct loopdev_cxt *lc, uint64_t *blocksize);
extern int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size);
extern int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type);
+extern int loopcxt_get_file_fmt_type(struct loopdev_cxt *lc, uint32_t* file_fmt_type);
+extern char *loopcxt_get_file_fmt_type_string(struct loopdev_cxt *lc);
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);
@@ -205,4 +217,6 @@ extern int loopcxt_is_used(struct loopdev_cxt *lc,
uint64_t sizelimit,
int flags);
+extern int parse_file_fmt_type(const char *file_fmt_type_str, uint32_t *file_fmt_type);
+
#endif /* UTIL_LINUX_LOOPDEV_H */
diff --git a/lib/loopdev.c b/lib/loopdev.c
index ede1b5cdc..676cc02f3 100644
--- a/lib/loopdev.c
+++ b/lib/loopdev.c
@@ -824,6 +824,75 @@ int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type)
}
/*
+ * @file_fmt_type_str: file format type string.
+ * @file_fmt_type: returns file format type from the given file format string.
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int parse_file_fmt_type(const char *file_fmt_type_str, uint32_t *file_fmt_type)
+{
+ int rc = 0;
+
+ if (!strcmp(file_fmt_type_str, "RAW"))
+ *file_fmt_type = LO_FILE_FMT_RAW;
+ else if (!strcmp(file_fmt_type_str, "QCOW"))
+ *file_fmt_type = LO_FILE_FMT_QCOW;
+ else if (!strcmp(file_fmt_type_str, "VDI"))
+ *file_fmt_type = LO_FILE_FMT_VDI;
+ else if (!strcmp(file_fmt_type_str, "VMDK"))
+ *file_fmt_type = LO_FILE_FMT_VMDK;
+ else
+ rc = -EINVAL;
+
+ return rc;
+}
+
+/*
+ * @lc: context
+ * @file_fmt_type: returns file format type of the given device
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int loopcxt_get_file_fmt_type(struct loopdev_cxt *lc, uint32_t* file_fmt_type)
+{
+ struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
+ int rc = 0;
+
+ if (sysfs) {
+ /* check if file_fmt_type is accessible and supported by the kernel module */
+ char* file_fmt_str = NULL;
+ if (ul_path_read_string(sysfs, &file_fmt_str, "loop/file_fmt_type") == 0)
+ rc = parse_file_fmt_type(file_fmt_str, file_fmt_type);
+ } else
+ rc = -errno;
+
+ if (rc != 0 && loopcxt_ioctl_enabled(lc)) {
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+ if (lo)
+ *file_fmt_type = lo->lo_file_fmt_type;
+ }
+
+ return 0;
+}
+
+/*
+ * @lc: context
+ *
+ * Returns (allocated) string with file format type of the current loop device.
+ */
+char *loopcxt_get_file_fmt_type_string(struct loopdev_cxt *lc)
+{
+ struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
+ char *res = NULL;
+
+ if (sysfs)
+ ul_path_read_string(sysfs, &res, "loop/file_fmt_type");
+
+ DBG(CXT, ul_debugobj(lc, "loopcxt_get_file_fmt_type_string [%s]", res));
+ return res;
+}
+
+/*
* @lc: context
* @devno: returns crypt name
*
@@ -1124,6 +1193,23 @@ int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize)
/*
* @lc: context
+ * @file_fmt_type: kernel LO_FILE_FMT_{RAW,QCOW,VDI,VMDK} flags
+ *
+ * The setting is removed by loopcxt_set_device() loopcxt_next()!
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int loopcxt_set_file_fmt_type(struct loopdev_cxt *lc, uint32_t file_fmt_type) {
+ if (!lc)
+ return -EINVAL;
+ lc->info.lo_file_fmt_type = file_fmt_type;
+
+ DBG(CXT, ul_debugobj(lc, "set file_fmt_type=%u", (unsigned) file_fmt_type));
+ return 0;
+}
+
+/*
+ * @lc: context
* @flags: kernel LO_FLAGS_{READ_ONLY,USE_AOPS,AUTOCLEAR} flags
*
* The setting is removed by loopcxt_set_device() loopcxt_next()!
diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c
index d862fd8e7..f455b49c3 100644
--- a/sys-utils/losetup.c
+++ b/sys-utils/losetup.c
@@ -43,6 +43,7 @@ enum {
COL_NAME = 0,
COL_AUTOCLR,
COL_BACK_FILE,
+ COL_FILE_FMT_TYPE,
COL_BACK_INO,
COL_BACK_MAJMIN,
COL_MAJMIN,
@@ -69,18 +70,19 @@ struct colinfo {
};
static struct colinfo infos[] = {
- [COL_AUTOCLR] = { "AUTOCLEAR", 1, SCOLS_FL_RIGHT, N_("autoclear flag set"), SCOLS_JSON_BOOLEAN},
- [COL_BACK_FILE] = { "BACK-FILE", 0.3, 0, N_("device backing file")},
- [COL_BACK_INO] = { "BACK-INO", 4, SCOLS_FL_RIGHT, N_("backing file inode number"), SCOLS_JSON_NUMBER},
- [COL_BACK_MAJMIN] = { "BACK-MAJ:MIN", 6, 0, N_("backing file major:minor device number")},
- [COL_NAME] = { "NAME", 0.25, 0, N_("loop device name")},
- [COL_OFFSET] = { "OFFSET", 5, SCOLS_FL_RIGHT, N_("offset from the beginning"), SCOLS_JSON_NUMBER},
- [COL_PARTSCAN] = { "PARTSCAN", 1, SCOLS_FL_RIGHT, N_("partscan flag set"), SCOLS_JSON_BOOLEAN},
- [COL_RO] = { "RO", 1, SCOLS_FL_RIGHT, N_("read-only device"), SCOLS_JSON_BOOLEAN},
- [COL_SIZELIMIT] = { "SIZELIMIT", 5, SCOLS_FL_RIGHT, N_("size limit of the file in bytes"), SCOLS_JSON_NUMBER},
- [COL_MAJMIN] = { "MAJ:MIN", 3, 0, N_("loop device major:minor number")},
- [COL_DIO] = { "DIO", 1, SCOLS_FL_RIGHT, N_("access backing file with direct-io"), SCOLS_JSON_BOOLEAN},
- [COL_LOGSEC] = { "LOG-SEC", 4, SCOLS_FL_RIGHT, N_("logical sector size in bytes"), SCOLS_JSON_NUMBER},
+ [COL_AUTOCLR] = { "AUTOCLEAR", 1, SCOLS_FL_RIGHT, N_("autoclear flag set"), SCOLS_JSON_BOOLEAN},
+ [COL_BACK_FILE] = { "BACK-FILE", 0.3, 0, N_("device backing file")},
+ [COL_FILE_FMT_TYPE] = { "FILE-FORMAT", 1, 0, N_("backing file format")},
+ [COL_BACK_INO] = { "BACK-INO", 4, SCOLS_FL_RIGHT, N_("backing file inode number"), SCOLS_JSON_NUMBER},
+ [COL_BACK_MAJMIN] = { "BACK-MAJ:MIN", 6, 0, N_("backing file major:minor device number")},
+ [COL_NAME] = { "NAME", 0.25, 0, N_("loop device name")},
+ [COL_OFFSET] = { "OFFSET", 5, SCOLS_FL_RIGHT, N_("offset from the beginning"), SCOLS_JSON_NUMBER},
+ [COL_PARTSCAN] = { "PARTSCAN", 1, SCOLS_FL_RIGHT, N_("partscan flag set"), SCOLS_JSON_BOOLEAN},
+ [COL_RO] = { "RO", 1, SCOLS_FL_RIGHT, N_("read-only device"), SCOLS_JSON_BOOLEAN},
+ [COL_SIZELIMIT] = { "SIZELIMIT", 5, SCOLS_FL_RIGHT, N_("size limit of the file in bytes"), SCOLS_JSON_NUMBER},
+ [COL_MAJMIN] = { "MAJ:MIN", 3, 0, N_("loop device major:minor number")},
+ [COL_DIO] = { "DIO", 1, SCOLS_FL_RIGHT, N_("access backing file with direct-io"), SCOLS_JSON_BOOLEAN},
+ [COL_LOGSEC] = { "LOG-SEC", 4, SCOLS_FL_RIGHT, N_("logical sector size in bytes"), SCOLS_JSON_NUMBER},
};
static int columns[ARRAY_SIZE(infos) * 2] = {-1};
@@ -120,11 +122,16 @@ static int printf_loopdev(struct loopdev_cxt *lc)
ino_t ino = 0;
char *fname;
uint32_t type;
+ char *file_fmt_str;
fname = loopcxt_get_backing_file(lc);
if (!fname)
return -EINVAL;
+ file_fmt_str = loopcxt_get_file_fmt_type_string(lc);
+ if (!file_fmt_str)
+ return -EINVAL;
+
if (loopcxt_get_backing_devno(lc, &dev) == 0)
loopcxt_get_backing_inode(lc, &ino);
@@ -141,6 +148,9 @@ static int printf_loopdev(struct loopdev_cxt *lc)
if (loopcxt_get_sizelimit(lc, &x) == 0 && x)
printf(_(", sizelimit %ju"), x);
+
+ printf(_(", file-format %s"), file_fmt_str);
+
goto done;
}
@@ -162,6 +172,8 @@ static int printf_loopdev(struct loopdev_cxt *lc)
printf(_(", encryption %s (type %u)"), e, type);
}
+ printf(_(", file-format %s"), file_fmt_str);
+
done:
free(fname);
printf("\n");
@@ -241,6 +253,9 @@ static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln)
case COL_BACK_FILE:
p = loopcxt_get_backing_file(lc);
break;
+ case COL_FILE_FMT_TYPE:
+ p = loopcxt_get_file_fmt_type_string(lc);
+ break;
case COL_OFFSET:
if (loopcxt_get_offset(lc, &x) == 0)
xasprintf(&np, "%jd", x);
@@ -424,6 +439,7 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_(" -r, --read-only set up a read-only loop device\n"), out);
fputs(_(" --direct-io[=<on|off>] open backing file with O_DIRECT\n"), out);
fputs(_(" --show print device name after setup (with -f)\n"), out);
+ fputs(_(" -t, --type set file format type of the loop device\n"), out);
fputs(_(" -v, --verbose verbose mode\n"), out);
/* output options */
@@ -473,7 +489,7 @@ static void warn_size(const char *filename, uint64_t size, uint64_t offset, int
static int create_loop(struct loopdev_cxt *lc,
int nooverlap, int lo_flags, int flags,
const char *file, uint64_t offset, uint64_t sizelimit,
- uint64_t blocksize)
+ uint64_t blocksize, uint32_t file_fmt_type)
{
int hasdev = loopcxt_has_device(lc);
int rc = 0;
@@ -568,6 +584,12 @@ static int create_loop(struct loopdev_cxt *lc,
warn(_("%s: failed to use backing file"), file);
break;
}
+
+ if ((rc = loopcxt_set_file_fmt_type(lc, file_fmt_type))) {
+ warn(_("failed to use backing file format type"));
+ break;
+ }
+
errno = 0;
rc = loopcxt_setup_device(lc);
if (rc == 0)
@@ -595,6 +617,8 @@ int main(int argc, char **argv)
char *outarg = NULL;
int list = 0;
unsigned long use_dio = 0, set_dio = 0, set_blocksize = 0;
+ int use_file_fmt_type = 0;
+ uint32_t file_fmt_type = 0;
enum {
OPT_SIZELIMIT = CHAR_MAX + 1,
@@ -625,6 +649,7 @@ int main(int argc, char **argv)
{ "direct-io", optional_argument, NULL, OPT_DIO },
{ "raw", no_argument, NULL, OPT_RAW },
{ "show", no_argument, NULL, OPT_SHOW },
+ { "type", required_argument, NULL, 't' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
@@ -647,7 +672,7 @@ int main(int argc, char **argv)
if (loopcxt_init(&lc, 0))
err(EXIT_FAILURE, _("failed to initialize loopcxt"));
- while ((c = getopt_long(argc, argv, "ab:c:d:Dfhj:JlLno:O:PrvV",
+ while ((c = getopt_long(argc, argv, "ab:c:d:Dfhj:JlLno:O:Prt:vV",
longopts, NULL)) != -1) {
err_exclusive_options(c, longopts, excl, excl_st);
@@ -725,6 +750,14 @@ int main(int argc, char **argv)
if (optarg)
use_dio = parse_switch(optarg, _("argument error"), "on", "off", NULL);
break;
+ case 't':
+ if (optarg) {
+ if (parse_file_fmt_type(optarg, &file_fmt_type) == 0)
+ use_file_fmt_type = 1;
+ else
+ errx(EXIT_FAILURE, _("failed to parse file format type"));
+ }
+ break;
case 'v':
break;
case OPT_SIZELIMIT: /* --sizelimit */
@@ -763,6 +796,7 @@ int main(int argc, char **argv)
columns[ncolumns++] = COL_AUTOCLR;
columns[ncolumns++] = COL_RO;
columns[ncolumns++] = COL_BACK_FILE;
+ columns[ncolumns++] = COL_FILE_FMT_TYPE;
columns[ncolumns++] = COL_DIO;
columns[ncolumns++] = COL_LOGSEC;
}
@@ -822,10 +856,10 @@ int main(int argc, char **argv)
}
if (act != A_CREATE &&
- (sizelimit || lo_flags || showdev))
+ (sizelimit || lo_flags || showdev || use_file_fmt_type))
errx(EXIT_FAILURE,
_("the options %s are allowed during loop device setup only"),
- "--{sizelimit,partscan,read-only,show}");
+ "--{sizelimit,partscan,read-only,show,type}");
if ((flags & LOOPDEV_FL_OFFSET) &&
act != A_CREATE && (act != A_SHOW || !file))
@@ -838,7 +872,7 @@ int main(int argc, char **argv)
switch (act) {
case A_CREATE:
res = create_loop(&lc, no_overlap, lo_flags, flags, file,
- offset, sizelimit, blocksize);
+ offset, sizelimit, blocksize, file_fmt_type);
if (res == 0) {
if (showdev)
printf("%s\n", loopcxt_get_device(&lc));