summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/loopdev.h3
-rw-r--r--lib/loopdev.c50
-rw-r--r--sys-utils/losetup.83
-rw-r--r--sys-utils/losetup.c51
4 files changed, 94 insertions, 13 deletions
diff --git a/include/loopdev.h b/include/loopdev.h
index 953d2db89..121fb846b 100644
--- a/include/loopdev.h
+++ b/include/loopdev.h
@@ -24,6 +24,7 @@
/* #define LOOP_CHANGE_FD 0x4C06 */
#define LOOP_SET_CAPACITY 0x4C07
#define LOOP_SET_DIRECT_IO 0x4C08
+#define LOOP_SET_BLOCK_SIZE 0x4C09
/* /dev/loop-control interface */
#ifndef LOOP_CTL_ADD
@@ -173,11 +174,13 @@ 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_flags(struct loopdev_cxt *lc, uint32_t flags);
int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename);
+int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize);
extern char *loopcxt_get_backing_file(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);
+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 const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc);
diff --git a/lib/loopdev.c b/lib/loopdev.c
index 8c653a361..66fa4f669 100644
--- a/lib/loopdev.c
+++ b/lib/loopdev.c
@@ -737,6 +737,38 @@ int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset)
/*
* @lc: context
+ * @blocksize: returns logical blocksize for the given device
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int loopcxt_get_blocksize(struct loopdev_cxt *lc, uint64_t *blocksize)
+{
+ struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc);
+ int rc = -EINVAL;
+
+ if (sysfs)
+ rc = sysfs_read_u64(sysfs, "queue/logical_block_size", blocksize);
+
+ /* Fallback based on BLKSSZGET ioctl */
+ if (rc) {
+ int fd = loopcxt_get_fd(lc);
+ int sz = 0;
+
+ if (fd < 0)
+ return -EINVAL;
+ rc = blkdev_get_sector_size(fd, &sz);
+ if (rc)
+ return rc;
+
+ *blocksize = sz;
+ }
+
+ DBG(CXT, ul_debugobj(lc, "get_blocksize [rc=%d]", rc));
+ return rc;
+}
+
+/*
+ * @lc: context
* @sizelimit: returns size limit for the given device
*
* Returns: <0 on error, 0 on success
@@ -1398,6 +1430,24 @@ int loopcxt_set_dio(struct loopdev_cxt *lc, unsigned long use_dio)
return 0;
}
+int loopcxt_set_blocksize(struct loopdev_cxt *lc, unsigned long blocksize)
+{
+ int fd = loopcxt_get_fd(lc);
+
+ if (fd < 0)
+ return -EINVAL;
+
+ /* Kernels prior to v4.14 don't support this ioctl */
+ if (ioctl(fd, LOOP_SET_BLOCK_SIZE, blocksize) < 0) {
+ int rc = -errno;
+ DBG(CXT, ul_debugobj(lc, "LOOP_SET_BLOCK_SIZE failed: %m"));
+ return rc;
+ }
+
+ DBG(CXT, ul_debugobj(lc, "logical block size set"));
+ return 0;
+}
+
int loopcxt_delete_device(struct loopdev_cxt *lc)
{
int fd = loopcxt_get_fd(lc);
diff --git a/sys-utils/losetup.8 b/sys-utils/losetup.8
index 98a8e70d6..570704d72 100644
--- a/sys-utils/losetup.8
+++ b/sys-utils/losetup.8
@@ -116,6 +116,9 @@ The data start is moved \fIoffset\fP bytes into the specified file or device.
.IP "\fB\-\-sizelimit \fIsize\fP"
The data end is set to no more than \fIsize\fP bytes after the data start.
.TP
+.BR \-b , " \-\-logical-blocksize " \fIsize
+Set the logical block size of the loop device in bytes (since Linux 4.14).
+.TP
.BR \-c , " \-\-set\-capacity " \fIloopdev
Force the loop driver to reread the size of the file associated with the
specified loop device.
diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c
index bbff98389..368a0b90a 100644
--- a/sys-utils/losetup.c
+++ b/sys-utils/losetup.c
@@ -36,6 +36,7 @@ enum {
A_FIND_FREE, /* find first unused */
A_SET_CAPACITY, /* set device capacity */
A_SET_DIRECT_IO, /* set accessing backing file by direct io */
+ A_SET_BLOCKSIZE, /* set logical block size of the loop device */
};
enum {
@@ -50,6 +51,7 @@ enum {
COL_RO,
COL_SIZELIMIT,
COL_DIO,
+ COL_BLOCKSIZE,
};
/* basic output flags */
@@ -76,6 +78,7 @@ static struct colinfo infos[] = {
[COL_SIZELIMIT] = { "SIZELIMIT", 5, SCOLS_FL_RIGHT, N_("size limit of the file in bytes")},
[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")},
+ [COL_BLOCKSIZE] = { "BLOCKSIZE", 4, SCOLS_FL_RIGHT, N_("logical block size in bytes")},
};
static int columns[ARRAY_SIZE(infos) * 2] = {-1};
@@ -280,6 +283,10 @@ static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln)
case COL_PARTSCAN:
p = loopcxt_is_partscan(lc) ? "1" : "0";
break;
+ case COL_BLOCKSIZE:
+ if (loopcxt_get_blocksize(lc, &x) == 0)
+ xasprintf(&np, "%jd", x);
+ break;
default:
return -EINVAL;
}
@@ -404,6 +411,7 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(USAGE_SEPARATOR, out);
fputs(_(" -o, --offset <num> start at offset <num> into file\n"), out);
fputs(_(" --sizelimit <num> device is limited to <num> bytes of the file\n"), out);
+ fputs(_(" -b --logical-blocksize <num> set the logical block size to <num>\n"), out);
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[=<on|off>] open backing file with O_DIRECT\n"), out);
@@ -566,11 +574,11 @@ int main(int argc, char **argv)
struct loopdev_cxt lc;
int act = 0, flags = 0, no_overlap = 0, c;
char *file = NULL;
- uint64_t offset = 0, sizelimit = 0;
+ uint64_t offset = 0, sizelimit = 0, blocksize = 0;
int res = 0, showdev = 0, lo_flags = 0;
char *outarg = NULL;
int list = 0;
- unsigned long use_dio = 0, set_dio = 0;
+ unsigned long use_dio = 0, set_dio = 0, set_blocksize = 0;
enum {
OPT_SIZELIMIT = CHAR_MAX + 1,
@@ -589,6 +597,7 @@ int main(int argc, char **argv)
{ "associated", required_argument, NULL, 'j' },
{ "json", no_argument, NULL, 'J' },
{ "list", no_argument, NULL, 'l' },
+ { "logical-blocksize", required_argument, NULL, 'b' },
{ "noheadings", no_argument, NULL, 'n' },
{ "offset", required_argument, NULL, 'o' },
{ "output", required_argument, NULL, 'O' },
@@ -620,7 +629,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, "ac:d:Dfhj:JlLno:O:PrvV",
+ while ((c = getopt_long(argc, argv, "ab:c:d:Dfhj:JlLno:O:PrvV",
longopts, NULL)) != -1) {
err_exclusive_options(c, longopts, excl, excl_st);
@@ -629,6 +638,10 @@ int main(int argc, char **argv)
case 'a':
act = A_SHOW;
break;
+ case 'b':
+ set_blocksize = 1;
+ blocksize = strtosize_or_err(optarg, _("failed to parse logical block size"));
+ break;
case 'c':
act = A_SET_CAPACITY;
if (!is_loopdev(optarg) ||
@@ -727,6 +740,7 @@ int main(int argc, char **argv)
columns[ncolumns++] = COL_RO;
columns[ncolumns++] = COL_BACK_FILE;
columns[ncolumns++] = COL_DIO;
+ columns[ncolumns++] = COL_BLOCKSIZE;
}
if (act == A_FIND_FREE && optind < argc) {
@@ -747,12 +761,14 @@ int main(int argc, char **argv)
/*
* losetup [--list] <device>
* OR
- * losetup --direct-io[=off] <device>
+ * losetup {--direct-io[=off]|--logical-blocksize=size}... <device>
*/
- if (!set_dio)
+ if (!(set_dio || set_blocksize))
act = A_SHOW_ONE;
- else
+ if (set_dio)
act = A_SET_DIRECT_IO;
+ if (set_blocksize)
+ act = A_SET_BLOCKSIZE;
if (!is_loopdev(argv[optind]) ||
loopcxt_set_device(&lc, argv[optind]))
err(EXIT_FAILURE, _("%s: failed to use device"),
@@ -799,8 +815,8 @@ int main(int argc, char **argv)
if (showdev)
printf("%s\n", loopcxt_get_device(&lc));
warn_size(file, sizelimit);
- if (set_dio)
- goto lo_set_dio;
+ if (set_dio || set_blocksize)
+ goto lo_set_post;
}
break;
case A_DELETE:
@@ -853,11 +869,20 @@ int main(int argc, char **argv)
loopcxt_get_device(&lc));
break;
case A_SET_DIRECT_IO:
- lo_set_dio:
- res = loopcxt_set_dio(&lc, use_dio);
- if (res)
- warn(_("%s: set direct io failed"),
- loopcxt_get_device(&lc));
+ case A_SET_BLOCKSIZE:
+ lo_set_post:
+ if (set_dio) {
+ res = loopcxt_set_dio(&lc, use_dio);
+ if (res)
+ warn(_("%s: set direct io failed"),
+ loopcxt_get_device(&lc));
+ }
+ if (set_blocksize) {
+ res = loopcxt_set_blocksize(&lc, blocksize);
+ if (res)
+ warn(_("%s: set logical block size failed"),
+ loopcxt_get_device(&lc));
+ }
break;
default:
warnx(_("bad usage"));