summaryrefslogtreecommitdiffstats
path: root/lib/loopdev.c
diff options
context:
space:
mode:
authorStanislav Brabec2017-09-26 16:14:51 +0200
committerKarel Zak2017-09-27 14:30:02 +0200
commita1a41597bfd55e709024bd91aaf024159362679c (patch)
treeee740d8df1db5485c5886ff3f753927707752f1a /lib/loopdev.c
parentdocs: add exec() exit codes to TODO (diff)
downloadkernel-qcow2-util-linux-a1a41597bfd55e709024bd91aaf024159362679c.tar.gz
kernel-qcow2-util-linux-a1a41597bfd55e709024bd91aaf024159362679c.tar.xz
kernel-qcow2-util-linux-a1a41597bfd55e709024bd91aaf024159362679c.zip
losetup: Add support for logical block size
Kernel since 4.14 supports setting of logical block size[1]. It allows to create loop devices that report logical block size different from 512. Add support for this feature to losetup. References: [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/block/loop.c?id=89e4fdecb51cf5535867026274bc97de9480ade5 [kzak@redhat.com: - fix loopcxt_get_blocksize() - remove lo_blocksize from loop_info64] Signed-off-by: Stanislav Brabec <sbrabec@suse.cz> Cc: Ming Lei <ming.lei@redhat.com> Cc: Hannes Reinecke <hare@suse.com> Cc: Omar Sandoval <osandov@fb.com> Cc: Jens Axboe <axboe@kernel.dk> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'lib/loopdev.c')
-rw-r--r--lib/loopdev.c50
1 files changed, 50 insertions, 0 deletions
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);