diff options
author | Omar Sandoval <osandov@fb.com> | 2017-08-24 03:03:43 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2017-08-31 15:51:14 -0400 |
commit | 89e4fdecb51cf5535867026274bc97de9480ade5 (patch) | |
tree | e0cbe2e118ea5ac8ff05a3bb8323d4142545335c | |
parent | 6c6b6f28b3335fd85ec833ee0005d9c9dca6c003 (diff) |
loop: add ioctl for changing logical block size
This is a different approach from the first attempt in f2c6df7dbf9a
("loop: support 4k physical blocksize"). Rather than extending
LOOP_{GET,SET}_STATUS, add a separate ioctl just for setting the block
size.
Reviewed-by: Ming Lei <ming.lei@redhat.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | drivers/block/loop.c | 24 | ||||
-rw-r--r-- | include/uapi/linux/loop.h | 1 |
2 files changed, 25 insertions, 0 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index e3f190016d4f..ac106b287d75 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
@@ -1047,6 +1047,7 @@ static int loop_clr_fd(struct loop_device *lo) | |||
1047 | memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); | 1047 | memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); |
1048 | memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); | 1048 | memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); |
1049 | memset(lo->lo_file_name, 0, LO_NAME_SIZE); | 1049 | memset(lo->lo_file_name, 0, LO_NAME_SIZE); |
1050 | blk_queue_logical_block_size(lo->lo_queue, 512); | ||
1050 | if (bdev) { | 1051 | if (bdev) { |
1051 | bdput(bdev); | 1052 | bdput(bdev); |
1052 | invalidate_bdev(bdev); | 1053 | invalidate_bdev(bdev); |
@@ -1330,6 +1331,24 @@ static int loop_set_dio(struct loop_device *lo, unsigned long arg) | |||
1330 | return error; | 1331 | return error; |
1331 | } | 1332 | } |
1332 | 1333 | ||
1334 | static int loop_set_block_size(struct loop_device *lo, unsigned long arg) | ||
1335 | { | ||
1336 | if (lo->lo_state != Lo_bound) | ||
1337 | return -ENXIO; | ||
1338 | |||
1339 | if (arg < 512 || arg > PAGE_SIZE || !is_power_of_2(arg)) | ||
1340 | return -EINVAL; | ||
1341 | |||
1342 | blk_mq_freeze_queue(lo->lo_queue); | ||
1343 | |||
1344 | blk_queue_logical_block_size(lo->lo_queue, arg); | ||
1345 | loop_update_dio(lo); | ||
1346 | |||
1347 | blk_mq_unfreeze_queue(lo->lo_queue); | ||
1348 | |||
1349 | return 0; | ||
1350 | } | ||
1351 | |||
1333 | static int lo_ioctl(struct block_device *bdev, fmode_t mode, | 1352 | static int lo_ioctl(struct block_device *bdev, fmode_t mode, |
1334 | unsigned int cmd, unsigned long arg) | 1353 | unsigned int cmd, unsigned long arg) |
1335 | { | 1354 | { |
@@ -1378,6 +1397,11 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, | |||
1378 | if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) | 1397 | if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) |
1379 | err = loop_set_dio(lo, arg); | 1398 | err = loop_set_dio(lo, arg); |
1380 | break; | 1399 | break; |
1400 | case LOOP_SET_BLOCK_SIZE: | ||
1401 | err = -EPERM; | ||
1402 | if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) | ||
1403 | err = loop_set_block_size(lo, arg); | ||
1404 | break; | ||
1381 | default: | 1405 | default: |
1382 | err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL; | 1406 | err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL; |
1383 | } | 1407 | } |
diff --git a/include/uapi/linux/loop.h b/include/uapi/linux/loop.h index c8125ec1f4f2..23158dbe2424 100644 --- a/include/uapi/linux/loop.h +++ b/include/uapi/linux/loop.h | |||
@@ -88,6 +88,7 @@ struct loop_info64 { | |||
88 | #define LOOP_CHANGE_FD 0x4C06 | 88 | #define LOOP_CHANGE_FD 0x4C06 |
89 | #define LOOP_SET_CAPACITY 0x4C07 | 89 | #define LOOP_SET_CAPACITY 0x4C07 |
90 | #define LOOP_SET_DIRECT_IO 0x4C08 | 90 | #define LOOP_SET_DIRECT_IO 0x4C08 |
91 | #define LOOP_SET_BLOCK_SIZE 0x4C09 | ||
91 | 92 | ||
92 | /* /dev/loop-control interface */ | 93 | /* /dev/loop-control interface */ |
93 | #define LOOP_CTL_ADD 0x4C80 | 94 | #define LOOP_CTL_ADD 0x4C80 |