mirror of
https://github.com/versity/scoutfs.git
synced 2026-01-06 04:04:59 +00:00
Advance move_blocks extent search offset
The move_blocks ioctl finds extents to move in the source file by searching from the starting block offset of the region to move. Logically, this is fine. After each extent item is deleted the next search will find the next extent. The problem is that deleted items still exist in the item cache. The next iteration has to skip over all the deleted extents from the start of the region. This is fine with large extents, but with heavily fragmented extents this creates a huge amplification of the number of items to traverse when moving the fragmented extents in a large file. (It's not quite O(n^2)/2 for the total extents, deleted items are purged as we write out the dirty items in each transaction.. but it's still immense.) The fix is to simply start searching for the next extent after the one we just moved. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -1267,6 +1267,7 @@ int scoutfs_data_move_blocks(struct inode *from, u64 from_off,
|
||||
from_iblock = from_off >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
count = (byte_len + SCOUTFS_BLOCK_SM_MASK) >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
to_iblock = to_off >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
from_start = from_iblock;
|
||||
|
||||
/* only move extent blocks inside i_size, careful not to wrap */
|
||||
from_size = i_size_read(from);
|
||||
@@ -1343,7 +1344,7 @@ int scoutfs_data_move_blocks(struct inode *from, u64 from_off,
|
||||
|
||||
/* find the next extent to move */
|
||||
ret = scoutfs_ext_next(sb, &data_ext_ops, &from_args,
|
||||
from_iblock, 1, &ext);
|
||||
from_start, 1, &ext);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT) {
|
||||
done = true;
|
||||
@@ -1431,6 +1432,12 @@ int scoutfs_data_move_blocks(struct inode *from, u64 from_off,
|
||||
i_size_read(from);
|
||||
i_size_write(to, to_size);
|
||||
}
|
||||
|
||||
/* find next after moved extent, avoiding wrapping */
|
||||
if (from_start + len < from_start)
|
||||
from_start = from_iblock + count + 1;
|
||||
else
|
||||
from_start += len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user