Message ID | 20210623055529.166678-8-wqu@suse.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | btrfs: experimental compression support for subpage | expand |
On 2021/6/23 下午1:55, Qu Wenruo wrote: > Function extent_write_locked_range() gets called when an async range > falls back to regular COW. > > In that case, we need to finish the ordered extents for the range. > > But the function is still using hardcoded PAGE_SIZE to calculate the > range. > > If it get called with a range like this: > > 0 16K 32K 48K 64K > | |////|/////| | > > Then the range passed to btrfs_writepage_endio_finish_ordered() will be > start == 16K, end == 80K, and the page range will no longer cover it, > triggering an ASSERT(). > > Fix it by properly calculate the range end by considering both the page > end and range end. > > Signed-off-by: Qu Wenruo <wqu@suse.com> > --- > fs/btrfs/extent_io.c | 7 +++++-- > 1 file changed, 5 insertions(+), 2 deletions(-) > > diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c > index e244c10074c8..c5491720a346 100644 > --- a/fs/btrfs/extent_io.c > +++ b/fs/btrfs/extent_io.c > @@ -5070,16 +5070,19 @@ int extent_write_locked_range(struct inode *inode, u64 start, u64 end, > > wbc_attach_fdatawrite_inode(&wbc_writepages, inode); > while (start <= end) { > + u64 cur_end = min(round_down(start, PAGE_SIZE) + PAGE_SIZE - 1, Here it should be round_down(cur, PAGE_SIZE) other than @start. Fixed in my github repo, as this is makeing tons of weird bugs even for x86_64. Thank god this patch is just an RFC... Thanks, Qu > + end); > + > page = find_get_page(mapping, start >> PAGE_SHIFT); > if (clear_page_dirty_for_io(page)) > ret = __extent_writepage(page, &wbc_writepages, &epd); > else { > btrfs_writepage_endio_finish_ordered(BTRFS_I(inode), > - page, start, start + PAGE_SIZE - 1, 1); > + page, start, cur_end, 1); > unlock_page(page); > } > put_page(page); > - start += PAGE_SIZE; > + start = cur_end + 1; > } > > ASSERT(ret <= 0); >
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index e244c10074c8..c5491720a346 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -5070,16 +5070,19 @@ int extent_write_locked_range(struct inode *inode, u64 start, u64 end, wbc_attach_fdatawrite_inode(&wbc_writepages, inode); while (start <= end) { + u64 cur_end = min(round_down(start, PAGE_SIZE) + PAGE_SIZE - 1, + end); + page = find_get_page(mapping, start >> PAGE_SHIFT); if (clear_page_dirty_for_io(page)) ret = __extent_writepage(page, &wbc_writepages, &epd); else { btrfs_writepage_endio_finish_ordered(BTRFS_I(inode), - page, start, start + PAGE_SIZE - 1, 1); + page, start, cur_end, 1); unlock_page(page); } put_page(page); - start += PAGE_SIZE; + start = cur_end + 1; } ASSERT(ret <= 0);
Function extent_write_locked_range() gets called when an async range falls back to regular COW. In that case, we need to finish the ordered extents for the range. But the function is still using hardcoded PAGE_SIZE to calculate the range. If it get called with a range like this: 0 16K 32K 48K 64K | |////|/////| | Then the range passed to btrfs_writepage_endio_finish_ordered() will be start == 16K, end == 80K, and the page range will no longer cover it, triggering an ASSERT(). Fix it by properly calculate the range end by considering both the page end and range end. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/extent_io.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)