Fix zero_user_segments() with start > end
Subsystems (2)
PATCH 1/1 Fix zero_user_segments() with start > end
zero_user_segments() is used from __block_write_begin_int(), for example like the following
zero_user_segments(page, 4096, 1024, 512, 918)
But new zero_user_segments() implements for HIGMEM + TRANSPARENT_HUGEPAGE doesn't handle "start > end" case correctly, and hits BUG_ON(). (we can fix __block_write_begin_int() instead though, it is the old and multiple usage)
Also it calls kmap_atomic() unnecessary while start == end == 0.
--- mm/highmem.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
mm/highmem.c +12 -5
@@ -368,20 +368,24 @@ void zero_user_segments(struct page *pagBUG_ON (end1 >page_size (page) || end2 >page_size (page)); +if (start1 >= end1) + start1 = end1 =0 ; +if (start2 >= end2) + start2 = end2 =0 ; +for (i =0 ; i <compound_nr (page); i++) {void *kaddr =NULL ; -if (start1 <PAGE_SIZE || start2 <PAGE_SIZE ) - kaddr =kmap_atomic (page + i); -if (start1 >=PAGE_SIZE ) { start1 -=PAGE_SIZE ; end1 -=PAGE_SIZE ; }else {unsigned this_end =min_t (unsigned, end1,PAGE_SIZE ); -if (end1 > start1) +if (end1 > start1) { + kaddr =kmap_atomic (page + i);memset (kaddr + start1,0 , this_end - start1); + } end1 -= this_end; start1 =0 ; }
@@ -392,8 +396,11 @@ void zero_user_segments(struct page *pag }else {unsigned this_end =min_t (unsigned, end2,PAGE_SIZE ); -if (end2 > start2) +if (end2 > start2) { +if (!kaddr) + kaddr =kmap_atomic (page + i);memset (kaddr + start2,0 , this_end - start2); + } end2 -= this_end; start2 =0 ; }
_
Signature · 1 line
OGAWA Hirofumi <[email protected]>
Quoted 9 lines · OGAWA Hirofumi
zero_user_segments()is used from__block_write_begin_int(), for example like the followingzero_user_segments(page, 4096, 1024, 512, 918)But new
zero_user_segments()implements for HIGMEM +TRANSPARENT_HUGEPAGEdoesn't handle "start > end" case correctly, and hitsBUG_ON(). (we can fix__block_write_begin_int()instead though, it is the old and multiple usage)
Why don't we just take out the BUG_ON instead? The function doesn't actually do the wrong thing.
Quoted 1 line
Also it calls
kmap_atomic()unnecessary while start == end == 0.
I'm OK with that. It always used to do that.
Quoted 2 lines
Cc <[email protected]>Signed-off-by OGAWA Hirofumi <[email protected]>
Quoted 6 lines · Matthew Wilcox
Quoted 5 lines · OGAWA Hirofumi
zero_user_segments()is used from__block_write_begin_int(), for example like the followingzero_user_segments(page, 4096, 1024, 512, 918)
Quoted 7 lines
Quoted 4 lines
But new
zero_user_segments()implements for HIGMEM +TRANSPARENT_HUGEPAGEdoesn't handle "start > end" case correctly, and hitsBUG_ON(). (we can fix__block_write_begin_int()instead though, it is the old and multiple usage)Why don't we just take out the
BUG_ONinstead? The function doesn't actually do the wrong thing.
end1 is underflow with
if (start1 >= PAGE_SIZE) {
start1 -= PAGE_SIZE;
end1 -= PAGE_SIZE;
}Quoted 3 lines
Quoted 1 line
Also it calls
kmap_atomic()unnecessary while start == end == 0.I'm OK with that. It always used to do that.
Old one is only one page, so it is always necessary if start1/end1 or start2/end2 is valid range. But this one is multiple pages, so there are completely unnecessary pages possibly.
Quoted 4 lines
Quoted 2 lines
Cc <[email protected]>Signed-off-by OGAWA Hirofumi <[email protected]>Fixes 0060ef3b4e6d ("mm: support THPs in zero_user_segments")
OK.
Signature · 1 line
OGAWA Hirofumi <[email protected]>