From ec03ee091f931125f3bbeb3628b0c5aaa4709930 Mon Sep 17 00:00:00 2001 From: Xinliang Liu Date: Tue, 19 Oct 2021 08:15:59 +0000 Subject: [PATCH 1/1] LU-15122 osd-ldiskfs: Fix ASSERTION( iobuf->dr_rw == 0 ) with 64KB PAGE_SIZE During a writing, if there is a page can not be mapped to blocks at once, it will cause "ASSERTION( iobuf->dr_rw == 0 )" crash which leads by the overflow access of mapped blocks array. This will happen on Arm platforms easily with 64KB PAGE_SIZE. And will not happen on x86_64 platforms with 4KB PAGE_SIZE. Because for 4KB block size, if PAGE_SIZE is 4KB, then i == 0 and blocks_left_page == 1. Which makes the inner loop each time handle one block. Thus the outer loop condition "block_idx < block_idx_end;" insures blocks[] array access not overflow. Check the actual mapped count so that mapped blocks array access will not overflow. Fixes: 0271b17b80a8 ("LU-14134 osd-ldiskfs: reduce credits for new writing") Change-Id: Icd46c04bea2d7930456840694d422758eebb4186 Signed-off-by: Xinliang Liu Reviewed-on: https://review.whamcloud.com/45288 Tested-by: jenkins Reviewed-by: Andreas Dilger Reviewed-by: James Simmons Tested-by: Maloo Reviewed-by: Li Dongyang Reviewed-by: Oleg Drokin --- lustre/osd-ldiskfs/osd_io.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lustre/osd-ldiskfs/osd_io.c b/lustre/osd-ldiskfs/osd_io.c index dc4208a..a41799b 100644 --- a/lustre/osd-ldiskfs/osd_io.c +++ b/lustre/osd-ldiskfs/osd_io.c @@ -520,12 +520,24 @@ static int osd_do_bio(struct osd_device *osd, struct inode *inode, for (page_idx = page_idx_start, block_idx = start_blocks; block_idx < block_idx_end; page_idx++, block_idx += blocks_left_page) { + /* For cases where the filesystems blocksize is not the + * same as PAGE_SIZE (e.g. ARM with PAGE_SIZE=64KB and + * blocksize=4KB), there will be multiple blocks to + * read/write per page. Also, the start and end block may + * not be aligned to the start and end of the page, so the + * first page may skip some blocks at the start ("i != 0", + * "blocks_left_page" is reduced), and the last page may + * skip some blocks at the end (limited by "count"). + */ page = pages[page_idx]; LASSERT(page_idx < iobuf->dr_npages); i = block_idx % blocks_per_page; blocks_left_page = blocks_per_page - i; - for (page_offset = i * blocksize; i < blocks_left_page; + if (block_idx + blocks_left_page > block_idx_end) + blocks_left_page = block_idx_end - block_idx; + page_offset = i * blocksize; + for (i = 0; i < blocks_left_page; i += nblocks, page_offset += blocksize * nblocks) { nblocks = 1; -- 1.8.3.1