Re: [PATCH 04/11] ntfs: write compressed data before replacing old clusters

Hyunchul Lee <[email protected]> Thu, 23 Jul 2026 11:14:03 +0900
Newsgroups dev.linux.lists.ntfs
Message-ID <CANFS6bbgWJXbU9+nQ2W48yZ7iaE4vT1KN1EacDnKGa8GTBbrzA@mail.gmail.com>
2026=EB=85=84 7=EC=9B=94 21=EC=9D=BC (=ED=99=94) =EC=98=A4=ED=9B=84 6:54, N=
amjae Jeon <[email protected]>=EB=8B=98=EC=9D=B4 =EC=9E=91=EC=84=B1:
>
> 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 on=
ly
> after the synchronous write succeeds, and free new clusters on failure.
>
> Signed-off-by: Namjae Jeon <[email protected]>

Looks good to me.

Reviewed-by: Hyunchul Lee <[email protected]>


> ---
>  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, lo=
ff_t pos, struct page **pages,
>
>         new_length =3D ntfs_bytes_to_cluster(vol, round_up(bio_size, vol-=
>cluster_size));
>
> -       err =3D ntfs_non_resident_attr_punch_hole(ni, new_vcn, ni->itype.=
compressed.block_clusters);
> -       if (err < 0)
> -               goto out;
> -
>         rlc =3D ntfs_cluster_alloc(vol, new_vcn, new_length, -1, DATA_ZON=
E,
>                         false, true, true);
>         if (IS_ERR(rlc)) {
> @@ -1385,28 +1381,6 @@ static int ntfs_write_cb(struct ntfs_inode *ni, lo=
ff_t pos, struct page **pages,
>         }
>
>         bio_lcn =3D rlc->lcn;
> -       down_write(&ni->runlist.lock);
> -       rl =3D 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 =3D 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 =3D new_rl_count;
> -       ni->runlist.rl =3D rl;
> -
> -       err =3D ntfs_attr_update_mapping_pairs(ni, 0);
> -       up_write(&ni->runlist.lock);
> -       if (err) {
> -               err =3D -EIO;
> -               goto out;
> -       }
> -
>         i =3D 0;
>         while (bio_size > 0) {
>                 int page_size;
> @@ -1423,6 +1397,10 @@ static int ntfs_write_cb(struct ntfs_inode *ni, lo=
ff_t pos, struct page **pages,
>                 if (!bio) {
>                         bio =3D bio_alloc(vol->sb->s_bdev, 1, REQ_OP_WRIT=
E,
>                                         GFP_NOIO);
> +                       if (!bio) {
> +                               err =3D -ENOMEM;
> +                               goto free_rlc;
> +                       }
>                         bio->bi_iter.bi_sector =3D
>                                 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, lof=
f_t pos, struct page **pages,
>                         err =3D submit_bio_wait(bio);
>                         bio_put(bio);
>                         if (err)
> -                               goto out;
> +                               goto free_rlc;
>                         bio =3D NULL;
>                         goto setup_bio;
>                 }
> @@ -1442,6 +1420,37 @@ static int ntfs_write_cb(struct ntfs_inode *ni, lo=
ff_t pos, struct page **pages,
>
>         err =3D 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 =3D ntfs_non_resident_attr_punch_hole(ni, new_vcn, cb_cluster=
s);
> +       if (err)
> +               goto free_rlc;
> +
> +       down_write(&ni->runlist.lock);
> +       rl =3D 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 =3D PTR_ERR(rl);
> +               goto free_rlc;
> +       }
> +
> +       ni->runlist.count =3D new_rl_count;
> +       ni->runlist.rl =3D rl;
> +       rlc =3D NULL;
> +
> +       err =3D ntfs_attr_update_mapping_pairs(ni, 0);
> +       up_write(&ni->runlist.lock);
> +       if (err)
> +               err =3D -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);
> --
> 2.34.1
>


--=20
Thanks,
Hyunchul