Re: [PATCH 11/11] ntfs: move attribute payload before shrinking its record
Hyunchul Lee <[email protected]> Thu, 23 Jul 2026 11:17:19 +0900
| Newsgroups | dev.linux.lists.ntfs |
|---|---|
| Message-ID | <CANFS6bZcYS7tuAHUmEOkqTgfyus8ic6hqO6ODbO6SMqWBFJC9g@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:55, N= amjae Jeon <[email protected]>=EB=8B=98=EC=9D=B4 =EC=9E=91=EC=84=B1: > > ntfs_new_attr_flags() resizes the non-resident attribute record before > moving its name and mapping pairs to their shorter-header offsets when > compression or sparse state is cleared. > > Shrinking the record first moves the following attribute over the tail of > the old record. The subsequent memmove() therefore copies bytes from that > following attribute instead of the old mapping pairs. Re-enabling > compression on an empty file persists those bytes as a malformed mapping > pairs array, which ntfsck reports as a missing or invalid run length. > > Move the payload before shrinking the record, while retaining the existin= g > resize-before-move ordering when growing it. > > Signed-off-by: Namjae Jeon <[email protected]> Looks good to me. Reviewed-by: Hyunchul Lee <[email protected]> > --- > fs/ntfs/ea.c | 23 +++++++++++++++-------- > 1 file changed, 15 insertions(+), 8 deletions(-) > > diff --git a/fs/ntfs/ea.c b/fs/ntfs/ea.c > index 95587b9a7129..4fb10d51211c 100644 > --- a/fs/ntfs/ea.c > +++ b/fs/ntfs/ea.c > @@ -631,7 +631,7 @@ static int ntfs_new_attr_flags(struct ntfs_inode *ni,= __le32 fattr) > struct attr_record *a; > __le16 new_aflags; > u16 old_name_ofs, old_mp_ofs; > - int mp_size, mp_ofs, name_ofs, arec_size, err; > + int mp_size, mp_ofs, name_ofs, old_arec_size, arec_size, err; > > m =3D map_mft_record(ni); > if (IS_ERR(m)) > @@ -726,6 +726,19 @@ static int ntfs_new_attr_flags(struct ntfs_inode *ni= , __le32 fattr) > > mp_ofs =3D (name_ofs + a->name_length * sizeof(__le16) + 7) & ~7; > arec_size =3D (mp_ofs + mp_size + 7) & ~7; > + old_arec_size =3D le32_to_cpu(a->length); > + > + /* > + * Move payloads before shrinking the record. Otherwise resizing= moves > + * the following attribute over the old payload before it can be = copied. > + */ > + if (arec_size < old_arec_size) { > + if (a->name_length && name_ofs !=3D old_name_ofs) > + memmove((u8 *)a + name_ofs, (u8 *)a + old_name_of= s, > + a->name_length * sizeof(__le16)); > + if (mp_ofs !=3D old_mp_ofs) > + memmove((u8 *)a + mp_ofs, (u8 *)a + old_mp_ofs, m= p_size); > + } > > err =3D ntfs_attr_record_resize(m, a, arec_size); > if (unlikely(err)) > @@ -736,18 +749,12 @@ static int ntfs_new_attr_flags(struct ntfs_inode *n= i, __le32 fattr) > * shrinks by the compressed_size field. Update the in-record pay= load layout > * to match the new offsets before exposing the new mapping_pairs= _offset. > */ > - if (name_ofs > old_name_ofs) { > + if (arec_size > old_arec_size) { > if (mp_ofs !=3D old_mp_ofs) > memmove((u8 *)a + mp_ofs, (u8 *)a + old_mp_ofs, m= p_size); > if (a->name_length) > memmove((u8 *)a + name_ofs, (u8 *)a + old_name_of= s, > a->name_length * sizeof(__le16)); > - } else { > - if (a->name_length && name_ofs !=3D old_name_ofs) > - memmove((u8 *)a + name_ofs, (u8 *)a + old_name_of= s, > - a->name_length * sizeof(__le16)); > - if (mp_ofs !=3D old_mp_ofs) > - memmove((u8 *)a + mp_ofs, (u8 *)a + old_mp_ofs, m= p_size); > } > > if (new_aflags & (ATTR_IS_SPARSE | ATTR_IS_COMPRESSED)) { > -- > 2.34.1 > --=20 Thanks, Hyunchul