diff options
author | Minchan Kim <minchan@kernel.org> | 2017-05-03 17:55:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-03 18:52:11 -0400 |
commit | e86942c7b6c1e1dd5e539f3bf3cfb63799163048 (patch) | |
tree | 7c892e121156d00d89c92b9d7491acb10df4116c /drivers/block | |
parent | 0f7896f12b6a3dae3ffccbebe8c954d954350f3d (diff) |
zram: handle multiple pages attached bio's bvec
Patch series "zram clean up", v2.
This patchset aims to clean up zram .
[1] clean up multiple pages's bvec handling.
[2] clean up partial IO handling
[3-6] clean up zram via using accessor and removing pointless structure.
With [2-6] applied, we can get a few hundred bytes as well as huge
readibility enhance.
x86: 708 byte save
add/remove: 1/1 grow/shrink: 0/11 up/down: 478/-1186 (-708)
function old new delta
zram_special_page_read - 478 +478
zram_reset_device 317 314 -3
mem_used_max_store 131 128 -3
compact_store 96 93 -3
mm_stat_show 203 197 -6
zram_add 719 712 -7
zram_slot_free_notify 229 214 -15
zram_make_request 819 803 -16
zram_meta_free 128 111 -17
zram_free_page 180 151 -29
disksize_store 432 361 -71
zram_decompress_page.isra 504 - -504
zram_bvec_rw 2592 2080 -512
Total: Before=25350773, After=25350065, chg -0.00%
ppc64: 231 byte save
add/remove: 2/0 grow/shrink: 1/9 up/down: 681/-912 (-231)
function old new delta
zram_special_page_read - 480 +480
zram_slot_lock - 200 +200
vermagic 39 40 +1
mm_stat_show 256 248 -8
zram_meta_free 200 184 -16
zram_add 944 912 -32
zram_free_page 348 308 -40
disksize_store 572 492 -80
zram_decompress_page 664 564 -100
zram_slot_free_notify 292 160 -132
zram_make_request 1132 1000 -132
zram_bvec_rw 2768 2396 -372
Total: Before=17565825, After=17565594, chg -0.00%
This patch (of 6):
Johannes Thumshirn reported system goes the panic when using NVMe over
Fabrics loopback target with zram.
The reason is zram expects each bvec in bio contains a single page
but nvme can attach a huge bulk of pages attached to the bio's bvec
so that zram's index arithmetic could be wrong so that out-of-bound
access makes system panic.
[1] in mainline solved solved the problem by limiting max_sectors with
SECTORS_PER_PAGE but it makes zram slow because bio should split with
each pages so this patch makes zram aware of multiple pages in a bvec
so it could solve without any regression(ie, bio split).
[1] 0bc315381fe9, zram: set physical queue limits to avoid array out of
bounds accesses
Link: http://lkml.kernel.org/r/20170413134057.GA27499@bbox
Signed-off-by: Minchan Kim <minchan@kernel.org>
Reported-by: Johannes Thumshirn <jthumshirn@suse.de>
Tested-by: Johannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Hannes Reinecke <hare@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/zram/zram_drv.c | 40 |
1 files changed, 11 insertions, 29 deletions
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 6fac5fedd610..8a38ff0c16a3 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c | |||
@@ -137,8 +137,7 @@ static inline bool valid_io_request(struct zram *zram, | |||
137 | 137 | ||
138 | static void update_position(u32 *index, int *offset, struct bio_vec *bvec) | 138 | static void update_position(u32 *index, int *offset, struct bio_vec *bvec) |
139 | { | 139 | { |
140 | if (*offset + bvec->bv_len >= PAGE_SIZE) | 140 | *index += (*offset + bvec->bv_len) / PAGE_SIZE; |
141 | (*index)++; | ||
142 | *offset = (*offset + bvec->bv_len) % PAGE_SIZE; | 141 | *offset = (*offset + bvec->bv_len) % PAGE_SIZE; |
143 | } | 142 | } |
144 | 143 | ||
@@ -840,34 +839,21 @@ static void __zram_make_request(struct zram *zram, struct bio *bio) | |||
840 | } | 839 | } |
841 | 840 | ||
842 | bio_for_each_segment(bvec, bio, iter) { | 841 | bio_for_each_segment(bvec, bio, iter) { |
843 | int max_transfer_size = PAGE_SIZE - offset; | 842 | struct bio_vec bv = bvec; |
844 | 843 | unsigned int unwritten = bvec.bv_len; | |
845 | if (bvec.bv_len > max_transfer_size) { | ||
846 | /* | ||
847 | * zram_bvec_rw() can only make operation on a single | ||
848 | * zram page. Split the bio vector. | ||
849 | */ | ||
850 | struct bio_vec bv; | ||
851 | |||
852 | bv.bv_page = bvec.bv_page; | ||
853 | bv.bv_len = max_transfer_size; | ||
854 | bv.bv_offset = bvec.bv_offset; | ||
855 | 844 | ||
845 | do { | ||
846 | bv.bv_len = min_t(unsigned int, PAGE_SIZE - offset, | ||
847 | unwritten); | ||
856 | if (zram_bvec_rw(zram, &bv, index, offset, | 848 | if (zram_bvec_rw(zram, &bv, index, offset, |
857 | op_is_write(bio_op(bio))) < 0) | 849 | op_is_write(bio_op(bio))) < 0) |
858 | goto out; | 850 | goto out; |
859 | 851 | ||
860 | bv.bv_len = bvec.bv_len - max_transfer_size; | 852 | bv.bv_offset += bv.bv_len; |
861 | bv.bv_offset += max_transfer_size; | 853 | unwritten -= bv.bv_len; |
862 | if (zram_bvec_rw(zram, &bv, index + 1, 0, | ||
863 | op_is_write(bio_op(bio))) < 0) | ||
864 | goto out; | ||
865 | } else | ||
866 | if (zram_bvec_rw(zram, &bvec, index, offset, | ||
867 | op_is_write(bio_op(bio))) < 0) | ||
868 | goto out; | ||
869 | 854 | ||
870 | update_position(&index, &offset, &bvec); | 855 | update_position(&index, &offset, &bv); |
856 | } while (unwritten); | ||
871 | } | 857 | } |
872 | 858 | ||
873 | bio_endio(bio); | 859 | bio_endio(bio); |
@@ -884,8 +870,6 @@ static blk_qc_t zram_make_request(struct request_queue *queue, struct bio *bio) | |||
884 | { | 870 | { |
885 | struct zram *zram = queue->queuedata; | 871 | struct zram *zram = queue->queuedata; |
886 | 872 | ||
887 | blk_queue_split(queue, &bio, queue->bio_split); | ||
888 | |||
889 | if (!valid_io_request(zram, bio->bi_iter.bi_sector, | 873 | if (!valid_io_request(zram, bio->bi_iter.bi_sector, |
890 | bio->bi_iter.bi_size)) { | 874 | bio->bi_iter.bi_size)) { |
891 | atomic64_inc(&zram->stats.invalid_io); | 875 | atomic64_inc(&zram->stats.invalid_io); |
@@ -1193,8 +1177,6 @@ static int zram_add(void) | |||
1193 | blk_queue_io_min(zram->disk->queue, PAGE_SIZE); | 1177 | blk_queue_io_min(zram->disk->queue, PAGE_SIZE); |
1194 | blk_queue_io_opt(zram->disk->queue, PAGE_SIZE); | 1178 | blk_queue_io_opt(zram->disk->queue, PAGE_SIZE); |
1195 | zram->disk->queue->limits.discard_granularity = PAGE_SIZE; | 1179 | zram->disk->queue->limits.discard_granularity = PAGE_SIZE; |
1196 | zram->disk->queue->limits.max_sectors = SECTORS_PER_PAGE; | ||
1197 | zram->disk->queue->limits.chunk_sectors = 0; | ||
1198 | blk_queue_max_discard_sectors(zram->disk->queue, UINT_MAX); | 1180 | blk_queue_max_discard_sectors(zram->disk->queue, UINT_MAX); |
1199 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, zram->disk->queue); | 1181 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, zram->disk->queue); |
1200 | 1182 | ||