]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ext4: mark move extents fast-commit ineligible
authorLi Chen <me@linux.beauty>
Thu, 11 Dec 2025 11:51:40 +0000 (19:51 +0800)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 20 Jan 2026 00:26:35 +0000 (19:26 -0500)
Fast commits only log operations that have dedicated replay support.
EXT4_IOC_MOVE_EXT swaps extents between regular files and may copy
data, rewriting the affected inodes' block mapping layout without
going through the fast commit tracking paths.
In practice these operations are rare and usually followed by further
updates, but mixing them into a fast commit makes the overall
semantics harder to reason about and risks replay gaps if new call
sites appear.

Teach ext4 to mark the filesystem fast-commit ineligible for the
journal transactions used by move_extent_per_page() when
EXT4_IOC_MOVE_EXT runs.
This forces those transactions to fall back to a full commit,
ensuring that these multi-inode extent swaps are captured by the
normal journal rather than partially encoded in fast commit TLVs.
This change should not affect common workloads but makes online
defragmentation safer and easier to reason about under fast commit.

Testing:
1. prepare:
        dd if=/dev/zero of=/root/fc_move.img bs=1M count=0 seek=256
        mkfs.ext4 -O fast_commit -F /root/fc_move.img
        mkdir -p /mnt/fc_move && mount -t ext4 -o loop \
/root/fc_move.img /mnt/fc_move
2. Created two files, ran EXT4_IOC_MOVE_EXT via e4defrag, and checked
   the ineligible reason statistics:
        fallocate -l 64M /mnt/fc_move/file1
        cp /mnt/fc_move/file1 /mnt/fc_move/file2
        e4defrag /mnt/fc_move/file1
        cat /proc/fs/ext4/loop0/fc_info
   shows "Move extents": > 0 and fc stats ineligible > 0.

Signed-off-by: Li Chen <me@linux.beauty>
Link: https://patch.msgid.link/20251211115146.897420-4-me@linux.beauty
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/fast_commit.c
fs/ext4/fast_commit.h
fs/ext4/move_extent.c
include/trace/events/ext4.h

index 242b69e5fe13073ccc65602da7e98311f529a07a..0ef2154a2b1f55fbc15e17a554e7599d986d8065 100644 (file)
@@ -2304,6 +2304,7 @@ static const char * const fc_ineligible_reasons[] = {
        [EXT4_FC_REASON_ENCRYPTED_FILENAME] = "Encrypted filename",
        [EXT4_FC_REASON_MIGRATE] = "Inode format migration",
        [EXT4_FC_REASON_VERITY] = "fs-verity enable",
+       [EXT4_FC_REASON_MOVE_EXT] = "Move extents",
 };
 
 int ext4_fc_info_show(struct seq_file *seq, void *v)
index 20f65135208fa22ccbfafdc139b54849f5dc44df..2f77a37fb101802d3faac323eae852f23fdf9604 100644 (file)
@@ -99,6 +99,7 @@ enum {
        EXT4_FC_REASON_ENCRYPTED_FILENAME,
        EXT4_FC_REASON_MIGRATE,
        EXT4_FC_REASON_VERITY,
+       EXT4_FC_REASON_MOVE_EXT,
        EXT4_FC_REASON_MAX
 };
 
index 635fb8a52e0c20842d64b7d849c4c5ef85afe51b..ce1f738dff938c5685ef87099df4c87702657a39 100644 (file)
@@ -321,6 +321,8 @@ static int mext_move_extent(struct mext_data *mext, u64 *m_len)
                ret = PTR_ERR(handle);
                goto out;
        }
+       ext4_fc_mark_ineligible(orig_inode->i_sb, EXT4_FC_REASON_MOVE_EXT,
+                               handle);
 
        ret = mext_move_begin(mext, folio, &move_type);
        if (ret)
index 726705bce9d36177fe2289dfb793365453b9a0db..a3e8fe414df85c53e8aa15836ab93c3ae514c815 100644 (file)
@@ -104,6 +104,7 @@ TRACE_DEFINE_ENUM(EXT4_FC_REASON_INODE_JOURNAL_DATA);
 TRACE_DEFINE_ENUM(EXT4_FC_REASON_ENCRYPTED_FILENAME);
 TRACE_DEFINE_ENUM(EXT4_FC_REASON_MIGRATE);
 TRACE_DEFINE_ENUM(EXT4_FC_REASON_VERITY);
+TRACE_DEFINE_ENUM(EXT4_FC_REASON_MOVE_EXT);
 TRACE_DEFINE_ENUM(EXT4_FC_REASON_MAX);
 
 #define show_fc_reason(reason)                                         \
@@ -119,7 +120,8 @@ TRACE_DEFINE_ENUM(EXT4_FC_REASON_MAX);
                { EXT4_FC_REASON_INODE_JOURNAL_DATA,    "INODE_JOURNAL_DATA"}, \
                { EXT4_FC_REASON_ENCRYPTED_FILENAME,    "ENCRYPTED_FILENAME"}, \
                { EXT4_FC_REASON_MIGRATE,               "MIGRATE"},     \
-               { EXT4_FC_REASON_VERITY,                "VERITY"})
+               { EXT4_FC_REASON_VERITY,                "VERITY"},      \
+               { EXT4_FC_REASON_MOVE_EXT,              "MOVE_EXT"})
 
 TRACE_DEFINE_ENUM(CR_POWER2_ALIGNED);
 TRACE_DEFINE_ENUM(CR_GOAL_LEN_FAST);