From: Karel Zak Date: Thu, 16 Mar 2023 12:41:36 +0000 (+0100) Subject: losetup: add --loop-ref and REF column X-Git-Tag: v2.40-rc1~325 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=db8f78151c075d25792b6b77b500c1c52a374fe0;p=thirdparty%2Futil-linux.git losetup: add --loop-ref and REF column The lo_file_name is nowhere used (kernel uses backing file descriptor, no path) and it was used to store limited info about the backing file path (64 bytes only!). For backward compatibility, we still fill lo_file_name with the path, but it's nowhere in the userspace used as the complete backing file path in sysfs. This commit introduces a new option to overwrite the default path in lo_file_name. The idea is to use the reference string by udevd in /dev/loop/by-ref to address loop devices independently on paths. Addresses: https://github.com/util-linux/util-linux/issues/2106 Suggested-by: Lennart Poettering Signed-off-by: Karel Zak --- diff --git a/include/loopdev.h b/include/loopdev.h index 903adc4912..49e38f2115 100644 --- a/include/loopdev.h +++ b/include/loopdev.h @@ -122,7 +122,7 @@ struct loopdev_cxt { unsigned int control_ok:1; /* /dev/loop-control success */ struct path_cxt *sysfs; /* pointer to /sys/dev/block// */ - struct loop_config config; /* for GET/SET ioctl */ + struct loop_config config; /* for GET/SET ioctl */ struct loopdev_iter iter; /* scans /sys or /dev for used/free devices */ }; @@ -195,8 +195,10 @@ 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_flags(struct loopdev_cxt *lc, uint32_t flags); int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename); +int loopcxt_set_refname(struct loopdev_cxt *lc, const char *refname); extern char *loopcxt_get_backing_file(struct loopdev_cxt *lc); +extern char *loopcxt_get_refname(struct loopdev_cxt *lc); extern int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno); extern int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino); extern int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset); diff --git a/lib/loopdev.c b/lib/loopdev.c index dd9ead3ee3..b3c537cd58 100644 --- a/lib/loopdev.c +++ b/lib/loopdev.c @@ -747,6 +747,26 @@ char *loopcxt_get_backing_file(struct loopdev_cxt *lc) return res; } +/* + * @lc: context + * + * Returns (allocated) string with loop reference. The same as backing file by + * default. + */ +char *loopcxt_get_refname(struct loopdev_cxt *lc) +{ + char *res = NULL; + struct loop_info64 *lo = loopcxt_get_info(lc); + + if (lo) { + lo->lo_file_name[LO_NAME_SIZE - 1] = '\0'; + res = strdup((char *) lo->lo_file_name); + } + + DBG(CXT, ul_debugobj(lc, "get_refname [%s]", res)); + return res; +} + /* * @lc: context * @offset: returns offset number for the given device @@ -1180,6 +1200,28 @@ int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags) return 0; } +/* + * @lc: context + * @refname: reference name (used to overwrite lo_file_name where is backing + * file by default) + * + * The setting is removed by loopcxt_set_device() loopcxt_next()! + * + * Returns: 0 on success, <0 on error. + */ +int loopcxt_set_refname(struct loopdev_cxt *lc, const char *refname) +{ + if (!lc) + return -EINVAL; + + memset(lc->config.info.lo_file_name, 0, sizeof(lc->config.info.lo_file_name)); + if (refname) + xstrncpy((char *)lc->config.info.lo_file_name, refname, LO_NAME_SIZE); + + DBG(CXT, ul_debugobj(lc, "set refname=%s", (char *)lc->config.info.lo_file_name)); + return 0; +} + /* * @lc: context * @filename: backing file path (the path will be canonicalized) @@ -1197,9 +1239,10 @@ int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename) if (!lc->filename) return -errno; - xstrncpy((char *)lc->config.info.lo_file_name, lc->filename, LO_NAME_SIZE); + if (!lc->config.info.lo_file_name[0]) + loopcxt_set_refname(lc, lc->filename); - DBG(CXT, ul_debugobj(lc, "set backing file=%s", lc->config.info.lo_file_name)); + DBG(CXT, ul_debugobj(lc, "set backing file=%s", lc->filename)); return 0; } diff --git a/sys-utils/losetup.8.adoc b/sys-utils/losetup.8.adoc index 94e8e7b94b..0d4ad74a98 100644 --- a/sys-utils/losetup.8.adoc +++ b/sys-utils/losetup.8.adoc @@ -30,7 +30,7 @@ Detach all associated loop devices: Set up a loop device: -*losetup* [*-o* _offset_] [*--sizelimit* _size_] [*--sector-size* _size_] [*-Pr*] [*--show*] *-f*|_loopdev file_ +*losetup* [*-o* _offset_] [*--sizelimit* _size_] [*--sector-size* _size_] [*--loop-ref* _name_] [*-Pr*] [*--show*] *-f*|_loopdev file_ Resize a loop device: @@ -74,6 +74,9 @@ Show the status of all loop devices associated with the given _file_. *-o*, *--offset* _offset_:: The data start is moved _offset_ bytes into the specified file or device. The _offset_ may be followed by the multiplicative suffixes; see above. +*--loop-ref* _string_:: +Set reference string. The backwardly compatible default is to use the backing filename as a reference in loop setup ioctl (aka lo_file_name). This option can overwrite this default behavior and set the reference to the _string_. The reference may be used by udevd in /dev/loop/by-ref. Linux kernel does not use the reference at all, but it could be used by some old utils that cannot read the backing file from sysfs. The reference is readable only for the root user (see *--output* +REF) and it is restricted to 64 bytes. + *--sizelimit* _size_:: The data end is set to no more than _size_ bytes after the data start. The _size_ may be followed by the multiplicative suffixes; see above. diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c index 9e8bd509ac..dfdfc58721 100644 --- a/sys-utils/losetup.c +++ b/sys-utils/losetup.c @@ -48,6 +48,7 @@ enum { COL_MAJMIN, COL_OFFSET, COL_PARTSCAN, + COL_REF, COL_RO, COL_SIZELIMIT, COL_DIO, @@ -76,6 +77,7 @@ static const struct colinfo infos[] = { [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_REF] = { "REF", 0.1, 0, N_("loop device reference string")}, [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")}, @@ -291,6 +293,9 @@ static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln) if (loopcxt_get_blocksize(lc, &x) == 0) xasprintf(&np, "%jd", x); break; + case COL_REF: + np = loopcxt_get_refname(lc); + break; default: return -EINVAL; } @@ -423,6 +428,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -P, --partscan create a partitioned loop device\n"), out); fputs(_(" -r, --read-only set up a read-only loop device\n"), out); fputs(_(" --direct-io[=] open backing file with O_DIRECT\n"), out); + fputs(_(" --loop-ref loop device reference\n"), out); fputs(_(" --show print device name after setup (with -f)\n"), out); fputs(_(" -v, --verbose verbose mode\n"), out); @@ -491,7 +497,8 @@ static int find_unused(struct loopdev_cxt *lc) static int create_loop(struct loopdev_cxt *lc, int nooverlap, int lo_flags, int flags, - const char *file, uint64_t offset, uint64_t sizelimit, + const char *file, const char *refname, + uint64_t offset, uint64_t sizelimit, uint64_t blocksize) { int hasdev = loopcxt_has_device(lc); @@ -580,7 +587,10 @@ static int create_loop(struct loopdev_cxt *lc, loopcxt_set_flags(lc, lo_flags); if (blocksize > 0) loopcxt_set_blocksize(lc, blocksize); - + if (refname && (rc = loopcxt_set_refname(lc, refname))) { + warnx(_("cannot set loop reference string")); + break; + } if ((rc = loopcxt_set_backing_file(lc, file))) { warn(_("%s: failed to use backing file"), file); break; @@ -610,7 +620,7 @@ int main(int argc, char **argv) { struct loopdev_cxt lc; int act = 0, flags = 0, no_overlap = 0, c; - char *file = NULL; + char *file = NULL, *refname = NULL; uint64_t offset = 0, sizelimit = 0, blocksize = 0; int res = 0, showdev = 0, lo_flags = 0; char *outarg = NULL; @@ -621,6 +631,7 @@ int main(int argc, char **argv) OPT_SIZELIMIT = CHAR_MAX + 1, OPT_SHOW, OPT_RAW, + OPT_REF, OPT_DIO, OPT_OUTPUT_ALL }; @@ -645,6 +656,7 @@ int main(int argc, char **argv) { "read-only", no_argument, NULL, 'r' }, { "direct-io", optional_argument, NULL, OPT_DIO }, { "raw", no_argument, NULL, OPT_RAW }, + { "loop-ref", required_argument, NULL, OPT_REF, }, { "show", no_argument, NULL, OPT_SHOW }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, @@ -691,6 +703,9 @@ int main(int argc, char **argv) case 'r': lo_flags |= LO_FLAGS_READ_ONLY; break; + case OPT_REF: + refname = optarg; + break; case 'd': act = A_DELETE; if (!is_loopdev(optarg) || @@ -862,7 +877,7 @@ int main(int argc, char **argv) switch (act) { case A_CREATE: - res = create_loop(&lc, no_overlap, lo_flags, flags, file, + res = create_loop(&lc, no_overlap, lo_flags, flags, file, refname, offset, sizelimit, blocksize); if (res == 0) { if (showdev)