From eb67671cd8149d563c04764d39fda16f17194eae Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 20 Jul 2026 17:43:34 +0900 Subject: [PATCH] ntfs: write compressed data before replacing old clusters ntfs_write_cb() punches the old compression unit and publishes the new mapping before submitting the replacement data. An allocation or I/O failure after the punch loses the previous contents and can leave the mapping pointing at unwritten clusters. Allocate and write the replacement clusters first. Replace the runlist only after the synchronous write succeeds, and free new clusters on failure. Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/compress.c | 63 ++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c index 33ed0456bf7e..5b5cd494e5d8 100644 --- a/fs/ntfs/compress.c +++ b/fs/ntfs/compress.c @@ -1373,10 +1373,6 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages, new_length = ntfs_bytes_to_cluster(vol, round_up(bio_size, vol->cluster_size)); - err = ntfs_non_resident_attr_punch_hole(ni, new_vcn, ni->itype.compressed.block_clusters); - if (err < 0) - goto out; - rlc = ntfs_cluster_alloc(vol, new_vcn, new_length, -1, DATA_ZONE, false, true, true); if (IS_ERR(rlc)) { @@ -1385,28 +1381,6 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages, } bio_lcn = rlc->lcn; - down_write(&ni->runlist.lock); - rl = ntfs_runlists_merge(&ni->runlist, rlc, 0, &new_rl_count); - if (IS_ERR(rl)) { - up_write(&ni->runlist.lock); - ntfs_error(vol->sb, "Failed to merge runlists"); - err = PTR_ERR(rl); - if (ntfs_cluster_free_from_rl(vol, rlc)) - ntfs_error(vol->sb, "Failed to free hot clusters."); - kvfree(rlc); - goto out; - } - - ni->runlist.count = new_rl_count; - ni->runlist.rl = rl; - - err = ntfs_attr_update_mapping_pairs(ni, 0); - up_write(&ni->runlist.lock); - if (err) { - err = -EIO; - goto out; - } - i = 0; while (bio_size > 0) { int page_size; @@ -1423,6 +1397,10 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages, if (!bio) { bio = bio_alloc(vol->sb->s_bdev, 1, REQ_OP_WRITE, GFP_NOIO); + if (!bio) { + err = -ENOMEM; + goto free_rlc; + } bio->bi_iter.bi_sector = ntfs_bytes_to_sector(vol, ntfs_cluster_to_bytes(vol, bio_lcn) + @@ -1433,7 +1411,7 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages, err = submit_bio_wait(bio); bio_put(bio); if (err) - goto out; + goto free_rlc; bio = NULL; goto setup_bio; } @@ -1442,6 +1420,37 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages, err = submit_bio_wait(bio); bio_put(bio); + if (err) + goto free_rlc; + + /* Do not discard the old compression block until the new one is safe. */ + err = ntfs_non_resident_attr_punch_hole(ni, new_vcn, cb_clusters); + if (err) + goto free_rlc; + + down_write(&ni->runlist.lock); + rl = ntfs_runlists_merge(&ni->runlist, rlc, 0, &new_rl_count); + if (IS_ERR(rl)) { + up_write(&ni->runlist.lock); + ntfs_error(vol->sb, "Failed to merge runlists"); + err = PTR_ERR(rl); + goto free_rlc; + } + + ni->runlist.count = new_rl_count; + ni->runlist.rl = rl; + rlc = NULL; + + err = ntfs_attr_update_mapping_pairs(ni, 0); + up_write(&ni->runlist.lock); + if (err) + err = -EIO; + goto out; + +free_rlc: + if (ntfs_cluster_free_from_rl(vol, rlc)) + ntfs_error(vol->sb, "Failed to free hot clusters."); + kvfree(rlc); out: if (outbuf) vunmap(outbuf);