Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ext4: make online defragmentation support large folios

move_extent_per_page() currently assumes that each folio is the size of
PAGE_SIZE and only copies data for one page. ext4_move_extents() should
call move_extent_per_page() for each page. To support larger folios,
simply modify the calculations for the block start and end offsets
within the folio based on the provided range of 'data_offset_in_page'
and 'block_len_in_page'. This function will continue to handle PAGE_SIZE
of data at a time and will not convert this function to manage an entire
folio. Additionally, we use the source folio to copy data, so it doesn't
matter if the source and dest folios are different in size.

Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Link: https://patch.msgid.link/20250512063319.3539411-8-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>

authored by

Zhang Yi and committed by
Theodore Ts'o
01e807e1 cd9f76de

+4 -7
+4 -7
fs/ext4/move_extent.c
··· 269 269 unsigned int tmp_data_size, data_size, replaced_size; 270 270 int i, err2, jblocks, retries = 0; 271 271 int replaced_count = 0; 272 - int from = data_offset_in_page << orig_inode->i_blkbits; 272 + int from; 273 273 int blocks_per_page = PAGE_SIZE >> orig_inode->i_blkbits; 274 274 struct super_block *sb = orig_inode->i_sb; 275 275 struct buffer_head *bh = NULL; ··· 323 323 * hold page's lock, if it is still the case data copy is not 324 324 * necessary, just swap data blocks between orig and donor. 325 325 */ 326 - 327 - VM_BUG_ON_FOLIO(folio_test_large(folio[0]), folio[0]); 328 - VM_BUG_ON_FOLIO(folio_test_large(folio[1]), folio[1]); 329 - VM_BUG_ON_FOLIO(folio_nr_pages(folio[0]) != folio_nr_pages(folio[1]), folio[1]); 330 - 331 326 if (unwritten) { 332 327 ext4_double_down_write_data_sem(orig_inode, donor_inode); 333 328 /* If any of extents in range became initialized we have to ··· 355 360 goto unlock_folios; 356 361 } 357 362 data_copy: 363 + from = offset_in_folio(folio[0], 364 + orig_blk_offset << orig_inode->i_blkbits); 358 365 *err = mext_page_mkuptodate(folio[0], from, from + replaced_size); 359 366 if (*err) 360 367 goto unlock_folios; ··· 387 390 if (!bh) 388 391 bh = create_empty_buffers(folio[0], 389 392 1 << orig_inode->i_blkbits, 0); 390 - for (i = 0; i < data_offset_in_page; i++) 393 + for (i = 0; i < from >> orig_inode->i_blkbits; i++) 391 394 bh = bh->b_this_page; 392 395 for (i = 0; i < block_len_in_page; i++) { 393 396 *err = ext4_get_block(orig_inode, orig_blk_offset + i, bh, 0);