aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
authorZhan Xusheng <zhanxusheng1024@gmail.com>2026-05-08 17:52:45 +0800
committerKonstantin Komarov <almaz.alexandrovich@paragon-software.com>2026-05-26 11:58:39 +0200
commit2d06bfbdcd09fa63faf8001cfda3fb75c99213e2 (patch)
tree5c95b6a50a2479d92663d69bcf3e415745569c75 /fs
parentc4e5d32cb5226660d9e0f6b9e01d98ba0d8872dc (diff)
downloadlinux-next-history-2d06bfbdcd09fa63faf8001cfda3fb75c99213e2.tar.gz
fs/ntfs3: fix wrong LCN in run_remove_range() when splitting a run
When run_remove_range() removes a middle portion of a non-sparse run, it splits the run into head and tail parts. The tail is inserted via run_add_entry() but uses the original r->lcn as its starting LCN instead of advancing it by the split offset. For example, removing VCN range [10, 20) from a run {vcn=0, lcn=100, len=30} should produce: {vcn=0, lcn=100, len=10} (head) {vcn=20, lcn=120, len=10} (tail, lcn advanced by 20) But the current code produces: {vcn=0, lcn=100, len=10} {vcn=20, lcn=100, len=10} (wrong: points to same physical clusters) This creates overlapping physical mappings in the in-memory run tree, which can corrupt cluster allocation decisions and lead to data corruption. The correct pattern is already used in run_insert_range(): CLST lcn2 = r->lcn == SPARSE_LCN ? SPARSE_LCN : (r->lcn + len1); Apply the same logic in run_remove_range(). Fixes: 10d7c95af043 ("fs/ntfs3: add delayed-allocation (delalloc) support") Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com> Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ntfs3/run.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/fs/ntfs3/run.c b/fs/ntfs3/run.c
index 19aa044fd1fcc..ad7db67514ef7 100644
--- a/fs/ntfs3/run.c
+++ b/fs/ntfs3/run.c
@@ -1297,9 +1297,12 @@ bool run_remove_range(struct runs_tree *run, CLST vcn, CLST len, CLST *done)
if (r_end > end) {
/* Remove a middle part, split. */
+ CLST tail_lcn = r->lcn == SPARSE_LCN ?
+ SPARSE_LCN : (r->lcn + (end - r->vcn));
+
*done += len;
r->len = d;
- return run_add_entry(run, end, r->lcn, r_end - end,
+ return run_add_entry(run, end, tail_lcn, r_end - end,
false);
}
/* Remove tail of run .*/