Re: [PATCH] ntfs: file extension before write submission

Hyunchul Lee <[email protected]> Fri, 17 Jul 2026 07:28:07 +0900
Newsgroups dev.linux.lists.ntfs,org.kernel.vger.linux-fsdevel
Message-ID <CANFS6bZtvqDd+mGA9B1zJkCUXgHm_CvjkAfU8GP0gBKLS0r05Q@mail.gmail.com>
2026=EB=85=84 7=EC=9B=94 16=EC=9D=BC (=EB=AA=A9) =EC=98=A4=EC=A0=84 11:47, =
Namjae Jeon <[email protected]>=EB=8B=98=EC=9D=B4 =EC=9E=91=EC=84=B1:
>
> Prepare non-resident file allocation and initialized-size extension in
> ->write_iter() before entering the buffered or direct iomap write paths.
>
> Previously, the iomap write callback extended initialized_size. When a
> direct write started beyond initialized_size,
> ntfs_extend_initialized_size() used iomap_zero_range() to zero the gap
> through the page cache. This created dirty folios after iomap DIO had
> invalidated its target cache range. The bsync path then had to
> synchronously write back the entire zeroed gap to prevent the post-DIO
> invalidation from encountering a dirty boundary folio.
>
> Move allocation and initialized-size preparation ahead of iomap submissio=
n.
> For DIO, kiocb_invalidate_pages() now sees any dirty boundary folio creat=
ed
> by iomap_zero_range(), writes it back when necessary, and invalidates it
> before the direct I/O is issued. This removes the explicit synchronous
> writeback of the zeroed gap while preserving the required boundary-folio
> ordering.
>
> Keep compressed writes out of the early initialized-size extension so the=
ir
> existing write path can zero uninitialized data before compression. Move
> compressed-file allocation expansion to write_iter as well, eliminating t=
he
> now-redundant expansion from ntfs_compress_write().
>
> Signed-off-by: Namjae Jeon <[email protected]>

Looks good to me.

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

> ---
>  fs/ntfs/compress.c | 10 ----------
>  fs/ntfs/file.c     | 43 +++++++++++++++++++++++++++++++++++++++++--
>  fs/ntfs/inode.c    |  6 +-----
>  fs/ntfs/inode.h    |  2 +-
>  fs/ntfs/iomap.c    | 34 +---------------------------------
>  5 files changed, 44 insertions(+), 51 deletions(-)
>
> diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c
> index e866f43ca30b..fe1877b86f49 100644
> --- a/fs/ntfs/compress.c
> +++ b/fs/ntfs/compress.c
> @@ -1459,16 +1459,6 @@ int ntfs_compress_write(struct ntfs_inode *ni, lof=
f_t pos, size_t count,
>         size_t written =3D 0;
>         struct address_space *mapping =3D VFS_I(ni)->i_mapping;
>
> -       if (NInoCompressed(ni) && pos + count > ni->allocated_size) {
> -               int err;
> -               loff_t end =3D pos + count;
> -
> -               err =3D ntfs_attr_expand(ni, end,
> -                               round_up(end, ni->itype.compressed.block_=
size));
> -               if (err)
> -                       return err;
> -       }
> -
>         pages =3D kmalloc_array(pages_per_cb, sizeof(struct page *), GFP_=
NOFS);
>         if (!pages)
>                 return -ENOMEM;
> diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
> index 6a7b638e523d..9061f8f77f7e 100644
> --- a/fs/ntfs/file.c
> +++ b/fs/ntfs/file.c
> @@ -535,6 +535,31 @@ static ssize_t ntfs_dio_write_iter(struct kiocb *ioc=
b, struct iov_iter *from)
>         return ret;
>  }
>
> +static int ntfs_expand_for_write(struct ntfs_inode *ni, loff_t end)
> +{
> +       struct ntfs_volume *vol =3D ni->vol;
> +       loff_t prealloc_size =3D 0;
> +       int err;
> +
> +       if (end <=3D ni->data_size)
> +               return 0;
> +
> +       if (NInoCompressed(ni)) {
> +               if (end > ni->allocated_size)
> +                       prealloc_size =3D round_up(end,
> +                                                ni->itype.compressed.blo=
ck_size);
> +       } else if (end > ni->allocated_size &&
> +                  end < ni->allocated_size + vol->preallocated_size) {
> +               prealloc_size =3D ni->allocated_size + vol->preallocated_=
size;
> +       }
> +
> +       mutex_lock(&ni->mrec_lock);
> +       err =3D ntfs_attr_expand(ni, end, prealloc_size);
> +       mutex_unlock(&ni->mrec_lock);
> +
> +       return err;
> +}
> +
>  static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter =
*from)
>  {
>         struct file *file =3D iocb->ki_filp;
> @@ -543,7 +568,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *ioc=
b, struct iov_iter *from)
>         struct ntfs_volume *vol =3D ni->vol;
>         ssize_t ret;
>         ssize_t count;
> -       loff_t pos;
> +       loff_t pos, end;
>         int err;
>         loff_t old_data_size, old_init_size;
>
> @@ -580,10 +605,24 @@ static ssize_t ntfs_file_write_iter(struct kiocb *i=
ocb, struct iov_iter *from)
>
>         pos =3D iocb->ki_pos;
>         count =3D ret;
> +       end =3D pos + count;
>
>         old_data_size =3D ni->data_size;
>         old_init_size =3D ni->initialized_size;
>
> +       if (end > old_data_size) {
> +               ret =3D ntfs_expand_for_write(ni, end);
> +               if (ret < 0)
> +                       goto out;
> +       }
> +
> +       if (NInoNonResident(ni) && !NInoCompressed(ni) &&
> +           end > old_init_size) {
> +               ret =3D ntfs_extend_initialized_size(vi, pos, end);
> +               if (ret < 0)
> +                       goto out;
> +       }
> +
>         if (NInoNonResident(ni) && NInoCompressed(ni)) {
>                 ret =3D ntfs_compress_write(ni, pos, count, from);
>                 if (ret > 0)
> @@ -655,7 +694,7 @@ static int ntfs_file_mmap_prepare(struct vm_area_desc=
 *desc)
>                            from + desc->end - desc->start);
>
>                 if (NTFS_I(inode)->initialized_size < to) {
> -                       err =3D ntfs_extend_initialized_size(inode, to, t=
o, false);
> +                       err =3D ntfs_extend_initialized_size(inode, to, t=
o);
>                         if (err)
>                                 return err;
>                 }
> diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
> index 7381a18cfadd..50e244aa372e 100644
> --- a/fs/ntfs/inode.c
> +++ b/fs/ntfs/inode.c
> @@ -2401,7 +2401,7 @@ int ntfs_show_options(struct seq_file *sf, struct d=
entry *root)
>  }
>
>  int ntfs_extend_initialized_size(struct inode *vi, const loff_t offset,
> -                                const loff_t new_size, bool bsync)
> +                                const loff_t new_size)
>  {
>         struct ntfs_inode *ni =3D NTFS_I(vi);
>         loff_t old_init_size;
> @@ -2428,10 +2428,6 @@ int ntfs_extend_initialized_size(struct inode *vi,=
 const loff_t offset,
>                                        &ntfs_iomap_folio_ops, NULL);
>                 if (err)
>                         return err;
> -               if (bsync)
> -                       err =3D filemap_write_and_wait_range(vi->i_mappin=
g,
> -                                                          old_init_size,
> -                                                          offset - 1);
>         }
>
>
> diff --git a/fs/ntfs/inode.h b/fs/ntfs/inode.h
> index 9aacd5787ffe..c6d065aaecd5 100644
> --- a/fs/ntfs/inode.h
> +++ b/fs/ntfs/inode.h
> @@ -352,7 +352,7 @@ static inline void ntfs_commit_inode(struct inode *vi=
)
>
>  int ntfs_inode_sync_filename(struct ntfs_inode *ni);
>  int ntfs_extend_initialized_size(struct inode *vi, const loff_t offset,
> -               const loff_t new_size, bool bsync);
> +               const loff_t new_size);
>  void ntfs_set_vfs_operations(struct inode *inode, mode_t mode, dev_t dev=
);
>  struct folio *ntfs_get_locked_folio(struct address_space *mapping,
>                 pgoff_t index, pgoff_t end_index, struct file_ra_state *r=
a);
> diff --git a/fs/ntfs/iomap.c b/fs/ntfs/iomap.c
> index 52eecf5cb256..26a1831a2c18 100644
> --- a/fs/ntfs/iomap.c
> +++ b/fs/ntfs/iomap.c
> @@ -675,21 +675,7 @@ static int ntfs_write_iomap_begin_non_resident(struc=
t inode *inode, loff_t offse
>                                                loff_t length, unsigned in=
t flags,
>                                                struct iomap *iomap, int n=
tfs_iomap_flags)
>  {
> -       struct ntfs_inode *ni =3D NTFS_I(inode);
> -
> -       if (ntfs_iomap_flags & (NTFS_IOMAP_FLAGS_BEGIN | NTFS_IOMAP_FLAGS=
_DIO) &&
> -           offset + length > ni->initialized_size) {
> -               int ret;
> -
> -               ret =3D ntfs_extend_initialized_size(inode, offset,
> -                                                  offset + length,
> -                                                  ntfs_iomap_flags &
> -                                                  NTFS_IOMAP_FLAGS_DIO);
> -               if (ret < 0)
> -                       return ret;
> -       }
> -
> -       mutex_lock(&ni->mrec_lock);
> +       mutex_lock(&NTFS_I(inode)->mrec_lock);
>         if (ntfs_iomap_flags & NTFS_IOMAP_FLAGS_BEGIN)
>                 return  ntfs_write_simple_iomap_begin_non_resident(inode,=
 offset,
>                                                                    length=
, iomap);
> @@ -705,28 +691,10 @@ static int __ntfs_write_iomap_begin(struct inode *i=
node, loff_t offset,
>                                     struct iomap *iomap, int ntfs_iomap_f=
lags)
>  {
>         struct ntfs_inode *ni =3D NTFS_I(inode);
> -       loff_t end =3D offset + length;
>
>         if (NVolShutdown(ni->vol))
>                 return -EIO;
>
> -       if (ntfs_iomap_flags & (NTFS_IOMAP_FLAGS_BEGIN | NTFS_IOMAP_FLAGS=
_DIO) &&
> -           end > ni->data_size) {
> -               struct ntfs_volume *vol =3D ni->vol;
> -               int ret;
> -
> -               mutex_lock(&ni->mrec_lock);
> -               if (end > ni->allocated_size &&
> -                   end < ni->allocated_size + vol->preallocated_size)
> -                       ret =3D ntfs_attr_expand(ni, end,
> -                                       ni->allocated_size + vol->preallo=
cated_size);
> -               else
> -                       ret =3D ntfs_attr_expand(ni, end, 0);
> -               mutex_unlock(&ni->mrec_lock);
> -               if (ret)
> -                       return ret;
> -       }
> -
>         if (!NInoNonResident(ni)) {
>                 mutex_lock(&ni->mrec_lock);
>                 return ntfs_write_iomap_begin_resident(inode, offset, iom=
ap);
> --
> 2.25.1
>


--=20
Thanks,
Hyunchul