From: Omar Sandoval <[email protected]>

When I was writing a test for the new loop device block size
functionality, I realized that the interface is kind of dumb:

- lo_init[0] is never filled in with the logical block size we
  previously set
- lo_flags returned from LOOP_GET_STATUS will have LO_FLAGS_BLOCKSIZE
  set if we previously called LOOP_SET_STATUS with LO_FLAGS_BLOCKSIZE
  set, which doesn't really mean anything

Instead, for LOOP_GET_STATUS, let's always fill in lo_init[0] and set
the LO_FLAGS_BLOCKSIZE flag to indicate we support it.

Signed-off-by: Omar Sandoval <[email protected]>
---
 drivers/block/loop.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index ef8334949b42..39fa7f48e0c7 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -234,7 +234,7 @@ figure_loop_size(struct loop_device *lo, loff_t offset, 
loff_t sizelimit,
                lo->lo_offset = offset;
        if (lo->lo_sizelimit != sizelimit)
                lo->lo_sizelimit = sizelimit;
-       if (lo->lo_flags & LO_FLAGS_BLOCKSIZE) {
+       if (lo->lo_logical_blocksize != logical_blocksize) {
                lo->lo_logical_blocksize = logical_blocksize;
                blk_queue_physical_block_size(lo->lo_queue, lo->lo_blocksize);
                blk_queue_logical_block_size(lo->lo_queue,
@@ -820,7 +820,7 @@ static void loop_config_discard(struct loop_device *lo)
        struct file *file = lo->lo_backing_file;
        struct inode *inode = file->f_mapping->host;
        struct request_queue *q = lo->lo_queue;
-       int lo_bits = 9;
+       int lo_bits = blksize_bits(lo->lo_logical_blocksize);
 
        /*
         * We use punch hole to reclaim the free space used by the
@@ -840,8 +840,6 @@ static void loop_config_discard(struct loop_device *lo)
 
        q->limits.discard_granularity = inode->i_sb->s_blocksize;
        q->limits.discard_alignment = 0;
-       if (lo->lo_flags & LO_FLAGS_BLOCKSIZE)
-               lo_bits = blksize_bits(lo->lo_logical_blocksize);
 
        blk_queue_max_discard_sectors(q, UINT_MAX >> lo_bits);
        blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> lo_bits);
@@ -1061,6 +1059,7 @@ static int loop_clr_fd(struct loop_device *lo)
        lo->lo_offset = 0;
        lo->lo_sizelimit = 0;
        lo->lo_encrypt_key_size = 0;
+       lo->lo_logical_blocksize = 512;
        memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
        memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
        memset(lo->lo_file_name, 0, LO_NAME_SIZE);
@@ -1105,6 +1104,7 @@ loop_set_status(struct loop_device *lo, const struct 
loop_info64 *info)
        struct loop_func_table *xfer;
        kuid_t uid = current_uid();
        int lo_flags = lo->lo_flags;
+       unsigned lo_logical_blocksize;
 
        if (lo->lo_encrypt_key_size &&
            !uid_eq(lo->lo_key_owner, uid) &&
@@ -1138,25 +1138,24 @@ loop_set_status(struct loop_device *lo, const struct 
loop_info64 *info)
                goto exit;
 
        if (info->lo_flags & LO_FLAGS_BLOCKSIZE) {
-               if (!(lo->lo_flags & LO_FLAGS_BLOCKSIZE))
-                       lo->lo_logical_blocksize = 512;
-               lo->lo_flags |= LO_FLAGS_BLOCKSIZE;
-               if (LO_INFO_BLOCKSIZE(info) != 512 &&
-                   LO_INFO_BLOCKSIZE(info) != 1024 &&
-                   LO_INFO_BLOCKSIZE(info) != 2048 &&
-                   LO_INFO_BLOCKSIZE(info) != 4096)
+               lo_logical_blocksize = LO_INFO_BLOCKSIZE(info);
+               if (lo_logical_blocksize != 512 &&
+                   lo_logical_blocksize != 1024 &&
+                   lo_logical_blocksize != 2048 &&
+                   lo_logical_blocksize != 4096)
                        return -EINVAL;
-               if (LO_INFO_BLOCKSIZE(info) > lo->lo_blocksize)
+               if (lo_logical_blocksize > lo->lo_blocksize)
                        return -EINVAL;
+       } else {
+               lo_logical_blocksize = lo->lo_logical_blocksize;
        }
 
        if (lo->lo_offset != info->lo_offset ||
            lo->lo_sizelimit != info->lo_sizelimit ||
            lo->lo_flags != lo_flags ||
-           ((lo->lo_flags & LO_FLAGS_BLOCKSIZE) &&
-            lo->lo_logical_blocksize != LO_INFO_BLOCKSIZE(info))) {
+           lo->lo_logical_blocksize != lo_logical_blocksize) {
                if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit,
-                                    LO_INFO_BLOCKSIZE(info))) {
+                                    lo_logical_blocksize)) {
                        err = -EFBIG;
                        goto exit;
                }
@@ -1223,7 +1222,7 @@ loop_get_status(struct loop_device *lo, struct 
loop_info64 *info)
        info->lo_rdevice = huge_encode_dev(lo->lo_device ? stat.rdev : 
stat.dev);
        info->lo_offset = lo->lo_offset;
        info->lo_sizelimit = lo->lo_sizelimit;
-       info->lo_flags = lo->lo_flags;
+       info->lo_flags = lo->lo_flags | LO_FLAGS_BLOCKSIZE;
        memcpy(info->lo_file_name, lo->lo_file_name, LO_NAME_SIZE);
        memcpy(info->lo_crypt_name, lo->lo_crypt_name, LO_NAME_SIZE);
        info->lo_encrypt_type =
@@ -1233,6 +1232,7 @@ loop_get_status(struct loop_device *lo, struct 
loop_info64 *info)
                memcpy(info->lo_encrypt_key, lo->lo_encrypt_key,
                       lo->lo_encrypt_key_size);
        }
+       LO_INFO_BLOCKSIZE(info) = lo->lo_logical_blocksize;
        return 0;
 }
 
@@ -1835,6 +1835,7 @@ static int loop_add(struct loop_device **l, int i)
        mutex_init(&lo->lo_ctl_mutex);
        atomic_set(&lo->lo_refcnt, 0);
        lo->lo_number           = i;
+       lo->lo_logical_blocksize = 512;
        spin_lock_init(&lo->lo_lock);
        disk->major             = LOOP_MAJOR;
        disk->first_minor       = i << part_shift;
-- 
2.14.1

Reply via email to