From: Yongpeng Yang <[email protected]>

Previously, when an extent being inserted overlaps with the largest
extent, the largest extent is dropped entirely. This was done to handle
the case where the largest extent is not in memory, avoiding
inconsistency between the largest extent and the extent tree.

This patch changes the semantics of __drop_largest_extent (renamed to
__punch_largest_extent): instead of discarding the entire largest
extent when any overlap is detected, keep the larger remaining portion
(left or right) after the punch. This preserves extent cache coverage
for truncate and overwrite operations that only partially overlap the
largest extent.

Signed-off-by: Yongpeng Yang <[email protected]>
---
 fs/f2fs/extent_cache.c | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c
index f8d94db60dc6..82d84c4e98b2 100644
--- a/fs/f2fs/extent_cache.c
+++ b/fs/f2fs/extent_cache.c
@@ -397,14 +397,31 @@ static unsigned int __free_extent_tree(struct 
f2fs_sb_info *sbi,
        return count;
 }
 
-static void __drop_largest_extent(struct extent_tree *et,
+static void __punch_largest_extent(struct extent_tree *et,
                                        pgoff_t fofs, unsigned int len)
 {
-       if (fofs < (pgoff_t)et->largest.fofs + et->largest.len &&
-                       fofs + len > et->largest.fofs) {
-               et->largest.len = 0;
-               et->largest_updated = true;
+       unsigned int largest_end, punch_end;
+       unsigned int left_len, right_len;
+
+       if (fofs >= (pgoff_t)et->largest.fofs + et->largest.len ||
+                       fofs + len <= et->largest.fofs)
+               return;
+
+       /* Punch [fofs, fofs + len) from largest extent. */
+       largest_end = et->largest.fofs + et->largest.len;
+       punch_end = fofs + len;
+
+       left_len = fofs > et->largest.fofs ? fofs - et->largest.fofs : 0;
+       right_len = largest_end > punch_end ? largest_end - punch_end : 0;
+
+       if (left_len >= right_len) {
+               et->largest.len = left_len;
+       } else {
+               et->largest.blk += punch_end - et->largest.fofs;
+               et->largest.fofs = punch_end;
+               et->largest.len = right_len;
        }
+       et->largest_updated = true;
 }
 
 void f2fs_init_read_extent_tree(struct inode *inode, struct folio *ifolio)
@@ -680,10 +697,10 @@ static void __update_extent_tree_range(struct inode 
*inode,
                dei.len = 0;
 
                /*
-                * drop largest extent before lookup, in case it's already
+                * punch largest extent before lookup, in case it's already
                 * been shrunk from extent tree
                 */
-               __drop_largest_extent(et, fofs, len);
+               __punch_largest_extent(et, fofs, len);
        }
 
        if (et->largest.len != 0 &&
-- 
2.43.0



_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to