On Fri, Dec 20, 2019 at 07:49:53PM +0100, glider@xxxxxxxxxx wrote: > KMSAN doesn't allow treating adjacent memory pages as such, if they were > allocated by different alloc_pages() calls. > ext4_mpage_readpages() however does so: adjacent pages end up being passed > together to dma_direct_map_sg(). > To prevent this, jump directly to the buffer_head-based read function in > KMSAN builds. > > Signed-off-by: Alexander Potapenko <glider@xxxxxxxxxx> > Cc: "Theodore Ts'o" <tytso@xxxxxxx> > Cc: Andreas Dilger <adilger.kernel@xxxxxxxxx> > Cc: Vegard Nossum <vegard.nossum@xxxxxxxxxx> > Cc: Dmitry Vyukov <dvyukov@xxxxxxxxxx> > Cc: Marco Elver <elver@xxxxxxxxxx> > Cc: Andrey Konovalov <andreyknvl@xxxxxxxxxx> > Cc: linux-mm@xxxxxxxxx > --- > > v4: > - use IS_ENABLED, as requested by Marco Elver > > Change-Id: I54ae8af536626a988e6398ff18a06c179b0ce034 > --- > fs/ext4/readpage.c | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c > index fef7755300c3..1e46ddf7a854 100644 > --- a/fs/ext4/readpage.c > +++ b/fs/ext4/readpage.c > @@ -252,6 +252,16 @@ int ext4_mpage_readpages(struct address_space *mapping, > if (page_has_buffers(page)) > goto confused; > > + /* > + * The following code may treat adjacent pages allocated > + * separately as a bigger contiguous allocation. > + * KMSAN doesn't allow this, as the corresponding metadata > + * pages may be separated. > + * Skip this complex logic for KMSAN builds. > + */ > + if (IS_ENABLED(CONFIG_KMSAN)) > + goto confused; > + > block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits); > last_block = block_in_file + nr_pages * blocks_per_page; > last_block_in_file = (ext4_readpage_limit(inode) + > -- Why is ext4 special here? Wouldn't other filesystems need this too? Is it possible the problem is the page merging logic in bio_add_page()? Maybe we need something like: diff --git a/block/bio.c b/block/bio.c index a5d75f6bf4c7e..9449a1e571ee7 100644 --- a/block/bio.c +++ b/block/bio.c @@ -646,6 +646,8 @@ static inline bool page_is_mergeable(const struct bio_vec *bv, *same_page = ((vec_end_addr & PAGE_MASK) == page_addr); if (!*same_page && pfn_to_page(PFN_DOWN(vec_end_addr)) + 1 != page) return false; + if (!*same_page && IS_ENABLED(CONFIG_KMSAN)) + return false; return true; }