diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-07-31 17:47:48 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-07-31 17:47:48 -0700 |
| commit | 0131b508c0e2489eac6e121135988f6eeb716f19 (patch) | |
| tree | 65ad600bd65f718a1c960617f7cd0de3c170213a | |
| parent | bc29fe1c617883f65da693be6abde0335d85f24c (diff) | |
| parent | 4e646ecd44759e552b0b9ccd995f3f608daab414 (diff) | |
Merge tag 'ntfs-for-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs
Pull ntfs fixes from Namjae Jeon:
- Keep RECALL_ON_OPEN in inode flags when reloading them from
$FILE_NAME
- Check runlist reallocation sizes for negative values and overflow
- Drop stale page cache after shrinking non-resident attributes to
prevent writeback failures and data loss
* tag 'ntfs-for-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs:
ntfs: drop stale page-cache when shrinking a non-resident attr
ntfs: harden runlist realloc size calculations
ntfs: preserve RECALL_ON_OPEN on WSL special-file reparse points
| -rw-r--r-- | fs/ntfs/attrib.c | 10 | ||||
| -rw-r--r-- | fs/ntfs/namei.c | 3 | ||||
| -rw-r--r-- | fs/ntfs/runlist.c | 50 |
3 files changed, 39 insertions, 24 deletions
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 239b7bcbaedf..58f32aac5f61 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -4293,6 +4293,16 @@ static int ntfs_non_resident_attr_shrink(struct ntfs_inode *ni, const s64 newsiz ni->initialized_size = newsize; ctx->attr->data.non_resident.initialized_size = cpu_to_le64(newsize); } + + /* + * Drop any page-cache folios that now lie beyond the shrunk + * attribute. The clusters backing them have just been freed and the + * runlist truncated, so leaving stale dirty folios around makes a + * later writeback map a vcn past the new allocation, which fails with + * -ENOENT and loses the write. + */ + truncate_inode_pages(VFS_I(ni)->i_mapping, newsize); + /* Update data size in the index. */ if (ni->type == AT_DATA && ni->name == AT_UNNAMED) NInoSetFileNameDirty(ni); diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c index 5ff25e9aaa32..cd403b1d99ee 100644 --- a/fs/ntfs/namei.c +++ b/fs/ntfs/namei.c @@ -685,7 +685,8 @@ static struct ntfs_inode *__ntfs_create(struct mnt_idmap *idmap, struct inode *d mutex_unlock(&dir_ni->mrec_lock); mutex_unlock(&ni->mrec_lock); - ni->flags = fn->file_attributes; + ni->flags = fn->file_attributes | + (ni->flags & FILE_ATTRIBUTE_RECALL_ON_OPEN); /* Set the sequence number. */ vi->i_generation = ni->seq_no; set_nlink(vi, 1); diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c index cbb6576cf725..8e0fd400e7f7 100644 --- a/fs/ntfs/runlist.c +++ b/fs/ntfs/runlist.c @@ -71,29 +71,46 @@ static inline void ntfs_rl_mc(struct runlist_element *dstbase, int dst, * On success, return a pointer to the newly allocated, or recycled, memory. * On error, return -errno. */ -struct runlist_element *ntfs_rl_realloc(struct runlist_element *rl, - int old_size, int new_size) +static inline struct runlist_element *ntfs_rl_realloc_gfp(struct runlist_element *rl, + int old_size, int new_size, gfp_t gfp) { struct runlist_element *new_rl; + size_t new_bytes; + + if (old_size < 0 || new_size < 0) + return ERR_PTR(-EINVAL); - old_size = old_size * sizeof(*rl); - new_size = new_size * sizeof(*rl); if (old_size == new_size) return rl; - new_rl = kvzalloc(new_size, GFP_NOFS); + if (check_mul_overflow(new_size, sizeof(*rl), &new_bytes)) + return ERR_PTR(-EINVAL); + + new_rl = kvzalloc(new_bytes, gfp); if (unlikely(!new_rl)) return ERR_PTR(-ENOMEM); if (likely(rl != NULL)) { - if (unlikely(old_size > new_size)) - old_size = new_size; - memcpy(new_rl, rl, old_size); + size_t old_bytes; + + if (check_mul_overflow(old_size, sizeof(*rl), &old_bytes)) { + kvfree(new_rl); + return ERR_PTR(-EINVAL); + } + if (unlikely(old_bytes > new_bytes)) + old_bytes = new_bytes; + memcpy(new_rl, rl, old_bytes); kvfree(rl); } return new_rl; } +struct runlist_element *ntfs_rl_realloc(struct runlist_element *rl, + int old_size, int new_size) +{ + return ntfs_rl_realloc_gfp(rl, old_size, new_size, GFP_NOFS); +} + /* * ntfs_rl_realloc_nofail - Reallocate memory for runlists * @rl: original runlist @@ -118,21 +135,8 @@ struct runlist_element *ntfs_rl_realloc(struct runlist_element *rl, static inline struct runlist_element *ntfs_rl_realloc_nofail(struct runlist_element *rl, int old_size, int new_size) { - struct runlist_element *new_rl; - - old_size = old_size * sizeof(*rl); - new_size = new_size * sizeof(*rl); - if (old_size == new_size) - return rl; - - new_rl = kvmalloc(new_size, GFP_NOFS | __GFP_NOFAIL); - if (likely(rl != NULL)) { - if (unlikely(old_size > new_size)) - old_size = new_size; - memcpy(new_rl, rl, old_size); - kvfree(rl); - } - return new_rl; + return ntfs_rl_realloc_gfp(rl, old_size, new_size, + GFP_NOFS | __GFP_NOFAIL); } /* |
