diff options
author | Hannes Reinecke <hare@suse.de> | 2017-06-08 07:46:45 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2017-06-08 10:40:00 -0400 |
commit | f2c6df7dbf9a60e1cd9941f9fb376d4d9ad1e8dd (patch) | |
tree | 79a9c0d9627fa253955532d6925e9606e1643f72 /drivers/block/loop.c | |
parent | 51001b7da364a24ed2464f3c22179efdc6b3a960 (diff) |
loop: support 4k physical blocksize
When generating bootable VM images certain systems (most notably
s390x) require devices with 4k blocksize. This patch implements
a new flag 'LO_FLAGS_BLOCKSIZE' which will set the physical
blocksize to that of the underlying device, and allow to change
the logical blocksize for up to the physical blocksize.
Signed-off-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/block/loop.c')
-rw-r--r-- | drivers/block/loop.c | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index fc706adff6a4..4d376c10a97a 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
@@ -221,7 +221,8 @@ static void __loop_update_dio(struct loop_device *lo, bool dio) | |||
221 | } | 221 | } |
222 | 222 | ||
223 | static int | 223 | static int |
224 | figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit) | 224 | figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit, |
225 | loff_t logical_blocksize) | ||
225 | { | 226 | { |
226 | loff_t size = get_size(offset, sizelimit, lo->lo_backing_file); | 227 | loff_t size = get_size(offset, sizelimit, lo->lo_backing_file); |
227 | sector_t x = (sector_t)size; | 228 | sector_t x = (sector_t)size; |
@@ -233,6 +234,12 @@ figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit) | |||
233 | lo->lo_offset = offset; | 234 | lo->lo_offset = offset; |
234 | if (lo->lo_sizelimit != sizelimit) | 235 | if (lo->lo_sizelimit != sizelimit) |
235 | lo->lo_sizelimit = sizelimit; | 236 | lo->lo_sizelimit = sizelimit; |
237 | if (lo->lo_flags & LO_FLAGS_BLOCKSIZE) { | ||
238 | lo->lo_logical_blocksize = logical_blocksize; | ||
239 | blk_queue_physical_block_size(lo->lo_queue, lo->lo_blocksize); | ||
240 | blk_queue_logical_block_size(lo->lo_queue, | ||
241 | lo->lo_logical_blocksize); | ||
242 | } | ||
236 | set_capacity(lo->lo_disk, x); | 243 | set_capacity(lo->lo_disk, x); |
237 | bd_set_size(bdev, (loff_t)get_capacity(bdev->bd_disk) << 9); | 244 | bd_set_size(bdev, (loff_t)get_capacity(bdev->bd_disk) << 9); |
238 | /* let user-space know about the new size */ | 245 | /* let user-space know about the new size */ |
@@ -810,6 +817,7 @@ static void loop_config_discard(struct loop_device *lo) | |||
810 | struct file *file = lo->lo_backing_file; | 817 | struct file *file = lo->lo_backing_file; |
811 | struct inode *inode = file->f_mapping->host; | 818 | struct inode *inode = file->f_mapping->host; |
812 | struct request_queue *q = lo->lo_queue; | 819 | struct request_queue *q = lo->lo_queue; |
820 | int lo_bits = 9; | ||
813 | 821 | ||
814 | /* | 822 | /* |
815 | * We use punch hole to reclaim the free space used by the | 823 | * We use punch hole to reclaim the free space used by the |
@@ -829,8 +837,11 @@ static void loop_config_discard(struct loop_device *lo) | |||
829 | 837 | ||
830 | q->limits.discard_granularity = inode->i_sb->s_blocksize; | 838 | q->limits.discard_granularity = inode->i_sb->s_blocksize; |
831 | q->limits.discard_alignment = 0; | 839 | q->limits.discard_alignment = 0; |
832 | blk_queue_max_discard_sectors(q, UINT_MAX >> 9); | 840 | if (lo->lo_flags & LO_FLAGS_BLOCKSIZE) |
833 | blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9); | 841 | lo_bits = blksize_bits(lo->lo_logical_blocksize); |
842 | |||
843 | blk_queue_max_discard_sectors(q, UINT_MAX >> lo_bits); | ||
844 | blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> lo_bits); | ||
834 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); | 845 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); |
835 | } | 846 | } |
836 | 847 | ||
@@ -918,6 +929,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, | |||
918 | 929 | ||
919 | lo->use_dio = false; | 930 | lo->use_dio = false; |
920 | lo->lo_blocksize = lo_blocksize; | 931 | lo->lo_blocksize = lo_blocksize; |
932 | lo->lo_logical_blocksize = 512; | ||
921 | lo->lo_device = bdev; | 933 | lo->lo_device = bdev; |
922 | lo->lo_flags = lo_flags; | 934 | lo->lo_flags = lo_flags; |
923 | lo->lo_backing_file = file; | 935 | lo->lo_backing_file = file; |
@@ -1083,6 +1095,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) | |||
1083 | int err; | 1095 | int err; |
1084 | struct loop_func_table *xfer; | 1096 | struct loop_func_table *xfer; |
1085 | kuid_t uid = current_uid(); | 1097 | kuid_t uid = current_uid(); |
1098 | int lo_flags = lo->lo_flags; | ||
1086 | 1099 | ||
1087 | if (lo->lo_encrypt_key_size && | 1100 | if (lo->lo_encrypt_key_size && |
1088 | !uid_eq(lo->lo_key_owner, uid) && | 1101 | !uid_eq(lo->lo_key_owner, uid) && |
@@ -1115,9 +1128,26 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) | |||
1115 | if (err) | 1128 | if (err) |
1116 | goto exit; | 1129 | goto exit; |
1117 | 1130 | ||
1131 | if (info->lo_flags & LO_FLAGS_BLOCKSIZE) { | ||
1132 | if (!(lo->lo_flags & LO_FLAGS_BLOCKSIZE)) | ||
1133 | lo->lo_logical_blocksize = 512; | ||
1134 | lo->lo_flags |= LO_FLAGS_BLOCKSIZE; | ||
1135 | if (LO_INFO_BLOCKSIZE(info) != 512 && | ||
1136 | LO_INFO_BLOCKSIZE(info) != 1024 && | ||
1137 | LO_INFO_BLOCKSIZE(info) != 2048 && | ||
1138 | LO_INFO_BLOCKSIZE(info) != 4096) | ||
1139 | return -EINVAL; | ||
1140 | if (LO_INFO_BLOCKSIZE(info) > lo->lo_blocksize) | ||
1141 | return -EINVAL; | ||
1142 | } | ||
1143 | |||
1118 | if (lo->lo_offset != info->lo_offset || | 1144 | if (lo->lo_offset != info->lo_offset || |
1119 | lo->lo_sizelimit != info->lo_sizelimit) | 1145 | lo->lo_sizelimit != info->lo_sizelimit || |
1120 | if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) { | 1146 | lo->lo_flags != lo_flags || |
1147 | ((lo->lo_flags & LO_FLAGS_BLOCKSIZE) && | ||
1148 | lo->lo_logical_blocksize != LO_INFO_BLOCKSIZE(info))) { | ||
1149 | if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit, | ||
1150 | LO_INFO_BLOCKSIZE(info))) | ||
1121 | err = -EFBIG; | 1151 | err = -EFBIG; |
1122 | goto exit; | 1152 | goto exit; |
1123 | } | 1153 | } |
@@ -1308,7 +1338,8 @@ static int loop_set_capacity(struct loop_device *lo) | |||
1308 | if (unlikely(lo->lo_state != Lo_bound)) | 1338 | if (unlikely(lo->lo_state != Lo_bound)) |
1309 | return -ENXIO; | 1339 | return -ENXIO; |
1310 | 1340 | ||
1311 | return figure_loop_size(lo, lo->lo_offset, lo->lo_sizelimit); | 1341 | return figure_loop_size(lo, lo->lo_offset, lo->lo_sizelimit, |
1342 | lo->lo_logical_blocksize); | ||
1312 | } | 1343 | } |
1313 | 1344 | ||
1314 | static int loop_set_dio(struct loop_device *lo, unsigned long arg) | 1345 | static int loop_set_dio(struct loop_device *lo, unsigned long arg) |