From nobody Mon Jun 8 21:52:13 2026 Received: from relayaws-01.paragon-software.com (relayaws-01.paragon-software.com [35.157.23.187]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 375FC3FD13B; Tue, 26 May 2026 13:49:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=35.157.23.187 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779803364; cv=none; b=FAKvCH7aaFNfZzitpWZ1mndyTY2kSFE99bGGoo5LMsj1VRXsXD2upno0pG9cq7Y37gVXj67ypNHlvwUZCiAlJw0PHU2A8qAal76Ir6owyZUKTlNKVOGZhIWSeu3yYvcvfnghyPrk3zhEIdNY/QELeNJeuYmXUrYcWOUFMUx7j/g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779803364; c=relaxed/simple; bh=K1CZOvYw26/2CnOXQQMSlIdrrc2BIL3sfekVnobidk8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=u15VuVQXjKSS+fVRUyQuohtWVxajba+b2scctuJWksmBHO6ZtiaThsSju5NNj+FI657RMam5GlvKlJT+Q7IBmZj1Ko9bmvuRpkYJhA3RYWdDaepDFGnKRgxgaZjhO+28dHK4D3NrWjBojzQ6ySDZ335bDcPGWd2JVm+VUx0ZTac= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=paragon-software.com; spf=pass smtp.mailfrom=paragon-software.com; dkim=pass (1024-bit key) header.d=paragon-software.com header.i=@paragon-software.com header.b=VTP1jbKR; arc=none smtp.client-ip=35.157.23.187 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=paragon-software.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=paragon-software.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=paragon-software.com header.i=@paragon-software.com header.b="VTP1jbKR" Received: from relayfre-01.paragon-software.com (relayfre-01.paragon-software.com [176.12.100.13]) by relayaws-01.paragon-software.com (Postfix) with ESMTPS id 10FB51D40; Tue, 26 May 2026 13:49:23 +0000 (UTC) Authentication-Results: relayaws-01.paragon-software.com; dkim=pass (1024-bit key; unprotected) header.d=paragon-software.com header.i=@paragon-software.com header.b=VTP1jbKR; dkim-atps=neutral Received: from dlg2.mail.paragon-software.com (vdlg-exch-02.paragon-software.com [172.30.1.105]) by relayfre-01.paragon-software.com (Postfix) with ESMTPS id 58EBD1E07; Tue, 26 May 2026 13:49:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paragon-software.com; s=mail; t=1779803360; bh=L/Uc4IxEWBGjiSYqcNyQivMtiJFGpQIxuvDhehHtO/4=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=VTP1jbKRunr5DRMSoYP/gK+lCK5xNZpRDcuV+jYeDDZGPa6Q1yxm5ffxiVId3aI7w wHxfxSqXQmyAGF3t8hbD4RBWZt3TZwH+L1gwdCfoY53wvslOynAtZLiJAaDngkXanZ R6ImnV6XgFXD4QbAMDZWWvdx4b3rWZg+15ap26g0= Received: from localhost.localdomain (172.30.20.153) by vdlg-exch-02.paragon-software.com (172.30.1.105) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.7; Tue, 26 May 2026 16:49:19 +0300 From: Konstantin Komarov To: CC: , , Konstantin Komarov Subject: [PATCH 1/6] fs/ntfs3: add fileattr support Date: Tue, 26 May 2026 15:49:02 +0200 Message-ID: <20260526134907.11402-2-almaz.alexandrovich@paragon-software.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260526134907.11402-1-almaz.alexandrovich@paragon-software.com> References: <20260526134907.11402-1-almaz.alexandrovich@paragon-software.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: vobn-exch-01.paragon-software.com (172.30.72.13) To vdlg-exch-02.paragon-software.com (172.30.1.105) Content-Type: text/plain; charset="utf-8" Implement fileattr_get() and fileattr_set() to fix a problem found during the internal testing. This allows ntfs3 to expose and modify inode flags through the generic file attribute interface used by FS_IOC_GETFLAGS and FS_IOC_SETFLAGS. Signed-off-by: Konstantin Komarov --- fs/ntfs3/file.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++ fs/ntfs3/inode.c | 2 ++ fs/ntfs3/namei.c | 4 +++ fs/ntfs3/ntfs_fs.h | 6 ++++ 4 files changed, 91 insertions(+) diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index b041639ab406..f421a36b1ed6 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -89,6 +89,80 @@ static int ntfs_ioctl_fitrim(struct ntfs_sb_info *sbi, u= nsigned long arg) return 0; } =20 +/* + * ntfs_fileattr_get - inode_operations::fileattr_get + */ +int ntfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) +{ + struct inode *inode =3D d_inode(dentry); + struct ntfs_inode *ni =3D ntfs_i(inode); + u32 flags =3D 0; + + /* Avoid any operation if inode is bad. */ + if (unlikely(is_bad_ni(ni))) + return -EINVAL; + + if (inode->i_flags & S_IMMUTABLE) + flags |=3D FS_IMMUTABLE_FL; + + if (inode->i_flags & S_APPEND) + flags |=3D FS_APPEND_FL; + + if (is_compressed(ni)) + flags |=3D FS_COMPR_FL; + + if (is_encrypted(ni)) + flags |=3D FS_ENCRYPT_FL; + + if (ni->nodump) + flags |=3D FS_NODUMP_FL; + + fileattr_fill_flags(fa, flags); + + return 0; +} + +/* + * ntfs_fileattr_set - inode_operations::fileattr_set + */ +int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, + struct file_kattr *fa) +{ + struct inode *inode =3D d_inode(dentry); + struct ntfs_inode *ni =3D ntfs_i(inode); + u32 flags =3D fa->flags; + unsigned int new_fl =3D 0; + + /* Avoid any operation if inode is bad. */ + if (unlikely(is_bad_ni(ni))) + return -EINVAL; + + if (fileattr_has_fsx(fa)) + return -EOPNOTSUPP; + + if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL)) + return -EOPNOTSUPP; + + if (flags & FS_IMMUTABLE_FL) + new_fl |=3D S_IMMUTABLE; + + if (flags & FS_APPEND_FL) + new_fl |=3D S_APPEND; + + inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND); + + /* Save nodump flag to return in ntfs_getattr. */ + if (flags & FS_NODUMP_FL) + ni->nodump =3D 1; + else + ni->nodump =3D 0; + + inode_set_ctime_current(inode); + mark_inode_dirty(inode); + + return 0; +} + static int ntfs_ioctl_get_volume_label(struct ntfs_sb_info *sbi, u8 __user= *buf) { if (copy_to_user(buf, sbi->volume.label, FSLABEL_MAX)) @@ -203,6 +277,9 @@ int ntfs_getattr(struct mnt_idmap *idmap, const struct = path *path, if (inode->i_flags & S_APPEND) stat->attributes |=3D STATX_ATTR_APPEND; =20 + if (ni->nodump) + stat->attributes |=3D STATX_ATTR_NODUMP; + if (is_compressed(ni)) stat->attributes |=3D STATX_ATTR_COMPRESSED; =20 @@ -1547,6 +1624,8 @@ const struct inode_operations ntfs_file_inode_operati= ons =3D { .get_acl =3D ntfs_get_acl, .set_acl =3D ntfs_set_acl, .fiemap =3D ntfs_fiemap, + .fileattr_get =3D ntfs_fileattr_get, + .fileattr_set =3D ntfs_fileattr_set, }; =20 const struct file_operations ntfs_file_operations =3D { diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 42af1abe17f8..356fc94c5a18 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -2095,6 +2095,8 @@ const struct inode_operations ntfs_link_inode_operati= ons =3D { .get_link =3D ntfs_get_link, .setattr =3D ntfs_setattr, .listxattr =3D ntfs_listxattr, + .fileattr_get =3D ntfs_fileattr_get, + .fileattr_set =3D ntfs_fileattr_set, }; =20 const struct address_space_operations ntfs_aops =3D { diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index 64cde1a856f4..c59de5f2fa97 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -518,6 +518,8 @@ const struct inode_operations ntfs_dir_inode_operations= =3D { .getattr =3D ntfs_getattr, .listxattr =3D ntfs_listxattr, .fiemap =3D ntfs_fiemap, + .fileattr_get =3D ntfs_fileattr_get, + .fileattr_set =3D ntfs_fileattr_set, }; =20 const struct inode_operations ntfs_special_inode_operations =3D { @@ -526,6 +528,8 @@ const struct inode_operations ntfs_special_inode_operat= ions =3D { .listxattr =3D ntfs_listxattr, .get_acl =3D ntfs_get_acl, .set_acl =3D ntfs_set_acl, + .fileattr_get =3D ntfs_fileattr_get, + .fileattr_set =3D ntfs_fileattr_set, }; =20 const struct dentry_operations ntfs_dentry_ops =3D { diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index d53febc2559c..9939556dcdc1 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -392,6 +392,9 @@ struct ntfs_inode { */ u8 ni_bad; =20 + /* Keep track of FS_NODUMP_FL. */ + u8 nodump; + union { struct ntfs_index dir; struct { @@ -529,6 +532,9 @@ bool dir_is_empty(struct inode *dir); extern const struct file_operations ntfs_dir_operations; =20 /* Globals from file.c */ +int ntfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa); +int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, + struct file_kattr *fa); int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path, struct kstat *stat, u32 request_mask, u32 flags); int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, --=20 2.43.0 From nobody Mon Jun 8 21:52:13 2026 Received: from relayaws-01.paragon-software.com (relayaws-01.paragon-software.com [35.157.23.187]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1392C3BD64A; Tue, 26 May 2026 13:49:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=35.157.23.187 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779803369; cv=none; b=f1UcR/irZL5jlUxGsYTv3cK2fSB9gUWpZ4IATPFLfZHojfR9OOP8r733UtGpLjnoAyhH1YaYANszOhQrRPW+wJKetg85AZadZeVqiFGVMwm58byW5xPNYLzfNNUPEsvs23SWajw35xzL5kJgIfOsan8UhoSQv80NqqXbpgULVs8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779803369; c=relaxed/simple; bh=BjYGjZ/HnsGo4HbIKCKjKOLElSF6P6xO6eCtL84xUk8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=foQi4jhRm2XOmw0uSD9sCPDFFY1oWz+8rKirKmshL7/pE8D72yHEmqEmR9WFi5TytrNiF/aVsJduKUWUISHdUwGcW+In1wisRsID1bC0HFsGqcIBhSagBgyhw5m7xvQ++ueLP+zdtoU+xJelHxFCrNQj6NK1XUGcRtFBtZvoERI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=paragon-software.com; spf=pass smtp.mailfrom=paragon-software.com; dkim=pass (1024-bit key) header.d=paragon-software.com header.i=@paragon-software.com header.b=EWoM+Z31; arc=none smtp.client-ip=35.157.23.187 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=paragon-software.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=paragon-software.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=paragon-software.com header.i=@paragon-software.com header.b="EWoM+Z31" Received: from relayfre-01.paragon-software.com (relayfre-01.paragon-software.com [176.12.100.13]) by relayaws-01.paragon-software.com (Postfix) with ESMTPS id 0719A1D3B; Tue, 26 May 2026 13:49:29 +0000 (UTC) Authentication-Results: relayaws-01.paragon-software.com; dkim=pass (1024-bit key; unprotected) header.d=paragon-software.com header.i=@paragon-software.com header.b=EWoM+Z31; dkim-atps=neutral Received: from dlg2.mail.paragon-software.com (vdlg-exch-02.paragon-software.com [172.30.1.105]) by relayfre-01.paragon-software.com (Postfix) with ESMTPS id 4236C1E07; Tue, 26 May 2026 13:49:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paragon-software.com; s=mail; t=1779803362; bh=I+OgGMIyFfChPVogbE0+wCj4JgHDmMFqX0Vr6/fsv4E=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=EWoM+Z31PXwkTWd1hYdNOSKdyupXXUd2sgqRyRnqlZZ5Kw1B4+Cee+gAziwNsJPOQ gefYuohKXTSCdUTn+rZBqnWCzE2Ly80N+iDgOajaLy/sXm+wWT1YnSPBVvC+8KsRyc QZCBap8lIWforz/0h5uZp5gjvF5zXOz0XMcQluE0= Received: from localhost.localdomain (172.30.20.153) by vdlg-exch-02.paragon-software.com (172.30.1.105) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.7; Tue, 26 May 2026 16:49:21 +0300 From: Konstantin Komarov To: CC: , , Konstantin Komarov Subject: [PATCH 2/6] fs/ntfs3: zero stale pagecache beyond valid data length Date: Tue, 26 May 2026 15:49:03 +0200 Message-ID: <20260526134907.11402-3-almaz.alexandrovich@paragon-software.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260526134907.11402-1-almaz.alexandrovich@paragon-software.com> References: <20260526134907.11402-1-almaz.alexandrovich@paragon-software.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: vobn-exch-01.paragon-software.com (172.30.72.13) To vdlg-exch-02.paragon-software.com (172.30.1.105) Content-Type: text/plain; charset="utf-8" Zero cached folios beyond the valid data length when closing a writable mapping. This keeps cached data beyond initialized file contents zeroed and prevents stale pagecache exposure after mmap-based writes. Signed-off-by: Konstantin Komarov --- fs/ntfs3/file.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index f421a36b1ed6..2d1de3739ffe 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -323,18 +323,44 @@ static int ntfs_extend_initialized_size(struct file *= file, return 0; } =20 +/* Zero pagecache after 'from'. */ +static void ntfs_zero_tail(struct address_space *mapping, loff_t from) +{ + struct folio_batch fbatch; + pgoff_t index =3D from >> PAGE_SHIFT; + unsigned nr, i; + + folio_batch_init(&fbatch); + + nr =3D filemap_get_folios(mapping, &index, -1, &fbatch); + + for (i =3D 0; i < nr; i++) { + struct folio *folio =3D fbatch.folios[i]; + u32 st =3D folio_pos(folio) < from ? + offset_in_folio(folio, from) : + 0; + + folio_lock(folio); + folio_zero_segment(folio, st, folio_size(folio)); + + folio_unlock(folio); + } + folio_batch_release(&fbatch); +} + static void ntfs_filemap_close(struct vm_area_struct *vma) { struct inode *inode =3D file_inode(vma->vm_file); struct ntfs_inode *ni =3D ntfs_i(inode); + u64 i_size =3D i_size_read(inode); u64 from =3D (u64)vma->vm_pgoff << PAGE_SHIFT; - u64 to =3D min_t(u64, i_size_read(inode), - from + vma->vm_end - vma->vm_start); + u64 to =3D min(i_size, from + vma->vm_end - vma->vm_start); =20 if (ni->i_valid < to) { ni->i_valid =3D to; mark_inode_dirty(inode); } + ntfs_zero_tail(inode->i_mapping, ni->i_valid); } =20 /* Copy of generic_file_vm_ops. */ --=20 2.43.0 From nobody Mon Jun 8 21:52:13 2026 Received: from relayaws-01.paragon-software.com (relayaws-01.paragon-software.com [35.157.23.187]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8DABB3FCB1C; Tue, 26 May 2026 13:49:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=35.157.23.187 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779803371; cv=none; b=R56q56yaM52BkGIoYvdU+k/s0Vn6Gb2rLm2rj/ki67htOWSF5FY70OD7LnGcT8xQZj5DDXjK8j/Js1RzmlgFtmrzl+7ui73cvtv73wvPo1cWBJR9iHQy2JpgEVp8cU99V8kDyxHfyvp2yf1qUJZh67GE3vumW/O8mis9Rr2N0Tk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779803371; c=relaxed/simple; bh=BpStdpV4/JUm60l+jox3W1V7wvsjq5QV+XLdbXR9Av0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=LSd8Or5YVMkfvoMLSxz6BGL2MnMxYUFexDVXEp4u8lWQlBWFN3yD24g2C0xxXwUaD0TiTrwFQSffTWmPfoseEk9P377UmPWxkv6aBaFzzlqaf74z1yIxxsNtwoG2dhBgKrCsmahNDm9ZOLRVDpKm85H0WMirGZSLsYmeB1YWkKU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=paragon-software.com; spf=pass smtp.mailfrom=paragon-software.com; dkim=pass (1024-bit key) header.d=paragon-software.com header.i=@paragon-software.com header.b=GQdM979+; arc=none smtp.client-ip=35.157.23.187 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=paragon-software.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=paragon-software.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=paragon-software.com header.i=@paragon-software.com header.b="GQdM979+" Received: from relayfre-01.paragon-software.com (relayfre-01.paragon-software.com [176.12.100.13]) by relayaws-01.paragon-software.com (Postfix) with ESMTPS id 9C91A1D40; Tue, 26 May 2026 13:49:30 +0000 (UTC) Authentication-Results: relayaws-01.paragon-software.com; dkim=pass (1024-bit key; unprotected) header.d=paragon-software.com header.i=@paragon-software.com header.b=GQdM979+; dkim-atps=neutral Received: from dlg2.mail.paragon-software.com (vdlg-exch-02.paragon-software.com [172.30.1.105]) by relayfre-01.paragon-software.com (Postfix) with ESMTPS id DBD8E2126; Tue, 26 May 2026 13:49:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paragon-software.com; s=mail; t=1779803363; bh=UDW3N+JMgIi5Lg8BefOGc5Qm2j1OWOeUYRlefObcR+g=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=GQdM979+x/2LW0ehY4znUpE1pY7jsmwSKFUjYuOp5OY8au7qOz5XMxhwSIoavd0gn mbwXDhxiihbYtsb0qpb2+1DCX+xZQePE9N91cUcWNDpayuSbOJJugf1FLkSBpHtgJG hDwN6KCvweU0+Uvk/CJKHkdI9N9rkEdgNpw4x7lI= Received: from localhost.localdomain (172.30.20.153) by vdlg-exch-02.paragon-software.com (172.30.1.105) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.7; Tue, 26 May 2026 16:49:22 +0300 From: Konstantin Komarov To: CC: , , Konstantin Komarov Subject: [PATCH 3/6] fs/ntfs3: handle delayed allocation overlap in run lookup Date: Tue, 26 May 2026 15:49:04 +0200 Message-ID: <20260526134907.11402-4-almaz.alexandrovich@paragon-software.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260526134907.11402-1-almaz.alexandrovich@paragon-software.com> References: <20260526134907.11402-1-almaz.alexandrovich@paragon-software.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: vobn-exch-01.paragon-software.com (172.30.72.13) To vdlg-exch-02.paragon-software.com (172.30.1.105) Content-Type: text/plain; charset="utf-8" Introduce run_lookup_entry_da() to look up data runs while taking delayed allocation into account. ntfs3 may have both committed extents and delayed allocation extents for the same VCN range. The new helper checks delayed allocation first and falls back to the real run, then corrects the returned range when a real run overlaps with a delayed allocation run. Signed-off-by: Konstantin Komarov --- fs/ntfs3/attrib.c | 17 +++++-------- fs/ntfs3/ntfs_fs.h | 3 +++ fs/ntfs3/run.c | 61 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c index e61c5bf7e27e..0caf2f8a8c1e 100644 --- a/fs/ntfs3/attrib.c +++ b/fs/ntfs3/attrib.c @@ -962,11 +962,8 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vc= n, CLST clen, CLST *lcn, =20 /* Try to find in cache. */ down_read(&ni->file.run_lock); - if (!no_da && run_lookup_entry(&ni->file.run_da, vcn, lcn, len, NULL)) { - /* The requested vcn is delay allocated. */ - *lcn =3D DELALLOC_LCN; - } else if (run_lookup_entry(&ni->file.run, vcn, lcn, len, NULL)) { - /* The requested vcn is known in current run. */ + if (run_lookup_entry_da(&ni->file.run, !no_da ? &ni->file.run_da : NULL, + vcn, lcn, len)) { } else { *len =3D 0; } @@ -1011,11 +1008,8 @@ int attr_data_get_block_locked(struct ntfs_inode *ni= , CLST vcn, CLST clen, int step; =20 again: - if (da && run_lookup_entry(run_da, vcn, lcn, len, NULL)) { - /* The requested vcn is delay allocated. */ - *lcn =3D DELALLOC_LCN; - } else if (run_lookup_entry(run, vcn, lcn, len, NULL)) { - /* The requested vcn is known in current run. */ + if (run_lookup_entry_da(run, da ? &ni->file.run_da : NULL, vcn, lcn, + len)) { } else { *len =3D 0; } @@ -1100,7 +1094,8 @@ int attr_data_get_block_locked(struct ntfs_inode *ni,= CLST vcn, CLST clen, } =20 if (!*len) { - if (run_lookup_entry(run, vcn, lcn, len, NULL)) { + if (run_lookup_entry_da(run, da ? run_da : NULL, vcn, lcn, + len)) { if (*lcn !=3D SPARSE_LCN || !new) goto ok; /* Slow normal way without allocation. */ =20 diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 9939556dcdc1..d98d7e474476 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -858,6 +858,9 @@ static inline void mi_get_ref(const struct mft_inode *m= i, struct MFT_REF *ref) /* Globals from run.c */ bool run_lookup_entry(const struct runs_tree *run, CLST vcn, CLST *lcn, CLST *len, size_t *index); +bool run_lookup_entry_da(const struct runs_tree *run, + const struct runs_tree *run_da, CLST vcn, CLST *lcn, + CLST *len); void run_truncate(struct runs_tree *run, CLST vcn); void run_truncate_head(struct runs_tree *run, CLST vcn); void run_truncate_around(struct runs_tree *run, CLST vcn); diff --git a/fs/ntfs3/run.c b/fs/ntfs3/run.c index ad7db67514ef..3ebf0154eda3 100644 --- a/fs/ntfs3/run.c +++ b/fs/ntfs3/run.c @@ -223,6 +223,66 @@ bool run_lookup_entry(const struct runs_tree *run, CLS= T vcn, CLST *lcn, return true; } =20 +/* + * run_overlaps + * + * true if run overlaps with range [svcn, svcn + len) + */ +static bool run_overlaps(const struct runs_tree *run, CLST svcn, CLST len, + CLST *vcn, CLST *clen) +{ + size_t i; + const struct ntfs_run *r =3D run->runs; + CLST end =3D svcn + len; + + for (i =3D 0; i < run->count; i++, r++) { + /* Check if [r->vcn, r->vcn+r->len) overlaps [svcn, end). */ + if (r->vcn < end && svcn < r->vcn + r->len) { + if (vcn) + *vcn =3D r->vcn; + if (clen) + *clen =3D r->len; + return true; + } + } + + return false; +} + +/* + * run_lookup_entry_da + * + * - lookup vcn in delalloc run + * - lookup vcn in real run + * - correct result if real run overlaps with delalloc + */ +bool run_lookup_entry_da(const struct runs_tree *run, + const struct runs_tree *run_da, CLST vcn, CLST *lcn, + CLST *len) +{ + CLST vcn1, len1; + + if (run_da && run_lookup_entry(run_da, vcn, lcn, len, NULL)) { + *lcn =3D DELALLOC_LCN; + return true; + } + + if (!run_lookup_entry(run, vcn, lcn, len, NULL)) + return false; + + if (run_da && run_overlaps(run_da, vcn, *len, &vcn1, &len1)) { + /* Correct return value. */ + if (vcn1 > vcn) { + *len =3D vcn1 - vcn; + } else { + *lcn =3D DELALLOC_LCN; + *len =3D len1; + } + } + + return true; +} + /* * run_truncate_head - Decommit the range before vcn. */ @@ -1286,7 +1346,6 @@ bool run_remove_range(struct runs_tree *run, CLST vcn= , CLST len, CLST *done) return true; } =20 - e =3D run->runs + run->count; r =3D run->runs + index; end =3D vcn + len; --=20 2.43.0 From nobody Mon Jun 8 21:52:13 2026 Received: from relayaws-01.paragon-software.com (relayaws-01.paragon-software.com [35.157.23.187]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 384573FD130; Tue, 26 May 2026 13:49:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=35.157.23.187 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779803371; cv=none; b=BdADkJpi16AKsQvTAJudO7WB8DWqe9orR3/eG/ifMgXuc7Amy8+0FLHoJPlOd+/tYLWtN0PJeFCTBDKiMWdlypN6amfzk9HZ/A068jS5PH6a3+gYjLaPCqvGhNJhhTdDs3TG1+eFXKQIDyYZltMYXN0shKfnlMAXqQzrbe60Ja0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779803371; c=relaxed/simple; bh=vf+GseZ/pJZVjDMPSDzYzToiTkPA75SS50G/1zqph0w=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=mqkmEhNnekwQWSAjuy4xAtHTLC8EqZwy0qZ6XWcF2hdw1BnvHx+eSr8HYBQO0ow23kUsQOirve0qXHSGSaEv+axgfIjqJCwpO5hucLNfy7r0BM7EQAkds9Cr0UR4qBXkcCHpAkF+lsytafyKekVB9ipwG4i3myj4qYjJz+YwTA4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=paragon-software.com; spf=pass smtp.mailfrom=paragon-software.com; dkim=pass (1024-bit key) header.d=paragon-software.com header.i=@paragon-software.com header.b=SYJ5MQYR; arc=none smtp.client-ip=35.157.23.187 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=paragon-software.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=paragon-software.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=paragon-software.com header.i=@paragon-software.com header.b="SYJ5MQYR" Received: from relayfre-01.paragon-software.com (relayfre-01.paragon-software.com [176.12.100.13]) by relayaws-01.paragon-software.com (Postfix) with ESMTPS id 4B83A1D60; Tue, 26 May 2026 13:49:31 +0000 (UTC) Authentication-Results: relayaws-01.paragon-software.com; dkim=pass (1024-bit key; unprotected) header.d=paragon-software.com header.i=@paragon-software.com header.b=SYJ5MQYR; dkim-atps=neutral Received: from dlg2.mail.paragon-software.com (vdlg-exch-02.paragon-software.com [172.30.1.105]) by relayfre-01.paragon-software.com (Postfix) with ESMTPS id 92AB61E07; Tue, 26 May 2026 13:49:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paragon-software.com; s=mail; t=1779803368; bh=Kra1PonV8Y7fa98j1UGk7fEnmHNOowvevtZp10SzyAk=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=SYJ5MQYRzBMw0brV2y7FOcqAvqvfk0mrd+y6B/oqCwdXvhsTfbeDGLjOxDXuYZsu+ 1nSRac+Vpsvo7JcyVDOQ9LFS70s2MtekVonJtVb1OT9VGZ+N8LleDqK3CcIwYZRxmB fCAbwjEP0UdmuVa2xyMByufTVQtIR7ieQVxAwq+c= Received: from localhost.localdomain (172.30.20.153) by vdlg-exch-02.paragon-software.com (172.30.1.105) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.7; Tue, 26 May 2026 16:49:27 +0300 From: Konstantin Komarov To: CC: , , Konstantin Komarov Subject: [PATCH 4/6] fs/ntfs3: fold resident writeback into writepages loop Date: Tue, 26 May 2026 15:49:05 +0200 Message-ID: <20260526134907.11402-5-almaz.alexandrovich@paragon-software.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260526134907.11402-1-almaz.alexandrovich@paragon-software.com> References: <20260526134907.11402-1-almaz.alexandrovich@paragon-software.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: vobn-exch-01.paragon-software.com (172.30.72.13) To vdlg-exch-02.paragon-software.com (172.30.1.105) Content-Type: text/plain; charset="utf-8" Remove the separate ntfs_resident_writepage() helper and handle resident writeback directly from ntfs_writepages(). This simplifies the resident writeback path and keeps the folio handling local to ntfs_writepages(). Signed-off-by: Konstantin Komarov --- fs/ntfs3/inode.c | 42 +++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 356fc94c5a18..9a75c2d832ca 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -992,31 +992,6 @@ static const struct iomap_writeback_ops ntfs_writeback= _ops =3D { .writeback_submit =3D iomap_ioend_writeback_submit, }; =20 -static int ntfs_resident_writepage(struct folio *folio, - struct writeback_control *wbc) -{ - struct address_space *mapping =3D folio->mapping; - struct inode *inode =3D mapping->host; - struct ntfs_inode *ni =3D ntfs_i(inode); - int ret; - - /* Avoid any operation if inode is bad. */ - if (unlikely(is_bad_ni(ni))) - return -EINVAL; - - if (unlikely(ntfs3_forced_shutdown(inode->i_sb))) - return -EIO; - - ni_lock(ni); - ret =3D attr_data_write_resident(ni, folio); - ni_unlock(ni); - - if (ret !=3D E_NTFS_NONRESIDENT) - folio_unlock(folio); - mapping_set_error(mapping, ret); - return ret; -} - static int ntfs_writepages(struct address_space *mapping, struct writeback_control *wbc) { @@ -1038,9 +1013,22 @@ static int ntfs_writepages(struct address_space *map= ping, =20 if (is_resident(ni)) { struct folio *folio =3D NULL; + err =3D 0; + + while ((folio =3D writeback_iter(mapping, wbc, folio, &err))) { + int err2; + + ni_lock(ni); + err2 =3D attr_data_write_resident(ni, folio); + ni_unlock(ni); =20 - while ((folio =3D writeback_iter(mapping, wbc, folio, &err))) - err =3D ntfs_resident_writepage(folio, wbc); + folio_unlock(folio); + if (err2) { + mapping_set_error(mapping, err2); + if (!err) + err =3D err2; + } + } =20 return err; } --=20 2.43.0 From nobody Mon Jun 8 21:52:13 2026 Received: from relayaws-01.paragon-software.com (relayaws-01.paragon-software.com [35.157.23.187]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3950D3FC5AD; Tue, 26 May 2026 13:49:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=35.157.23.187 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779803380; cv=none; b=J+kt1CJYV3Sx8o5dO5zW8k+EDP11/KJ+M1oI3ZUQQ0WjFC3g+JbE1v1HmmDKlZTGwQhc2SsjbqGntzP7ToLObxAbKep/idgtkl5LCPR1EicoHba0ZXwGzbdPqXdnWrPxc3VAbC2WQCwPWckjReBvdUM6l7FdGyQevRaIR2qRGeQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779803380; c=relaxed/simple; bh=et8wV0+Dbpjc2PWdiG74EPolYrWNCm3p+kN/uSHQpxs=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=dEp0uTJEJMDSs1Rmn8DODV+nKyiBetVeUgPo058DaIgA+w2BMFbOKQwx0FokxVdUj/1qFAf/eIKDrzdNGce5Ipu6OktXlIiixaFadf+oTIC/8ml+++43KxdlrED7VKK2EA/OkFVIDnKDriYRTQWI+XQp30qzDl04yhkdYI9fMJo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=paragon-software.com; spf=pass smtp.mailfrom=paragon-software.com; dkim=pass (1024-bit key) header.d=paragon-software.com header.i=@paragon-software.com header.b=MUYleGbA; arc=none smtp.client-ip=35.157.23.187 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=paragon-software.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=paragon-software.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=paragon-software.com header.i=@paragon-software.com header.b="MUYleGbA" Received: from relayfre-01.paragon-software.com (relayfre-01.paragon-software.com [176.12.100.13]) by relayaws-01.paragon-software.com (Postfix) with ESMTPS id 257AF1D40; Tue, 26 May 2026 13:49:40 +0000 (UTC) Authentication-Results: relayaws-01.paragon-software.com; dkim=pass (1024-bit key; unprotected) header.d=paragon-software.com header.i=@paragon-software.com header.b=MUYleGbA; dkim-atps=neutral Received: from dlg2.mail.paragon-software.com (vdlg-exch-02.paragon-software.com [172.30.1.105]) by relayfre-01.paragon-software.com (Postfix) with ESMTPS id 642611E07; Tue, 26 May 2026 13:49:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paragon-software.com; s=mail; t=1779803373; bh=yBaQf8E1u4/5HLFmn2hNEFmldxSLk3zJlkLM3MEVQUA=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=MUYleGbAKlFpfi2kPa4Z17BvsK9c5Bwh0xZRl+YgM+H8+Bnxp3043YdKh8p51jbcu y+4lQxZJa7939YKI0mnbwb9vTqwCHUOzjCwICEkCRrmLw42PYRSgtZY/SYq8GtXnj+ b9JThA0j38p4XSxtwj7gsejftIeqqPuCz9LpNtB0= Received: from localhost.localdomain (172.30.20.153) by vdlg-exch-02.paragon-software.com (172.30.1.105) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.7; Tue, 26 May 2026 16:49:32 +0300 From: Konstantin Komarov To: CC: , , Konstantin Komarov Subject: [PATCH 5/6] fs/ntfs3: force waiting for direct I/O completion Date: Tue, 26 May 2026 15:49:06 +0200 Message-ID: <20260526134907.11402-6-almaz.alexandrovich@paragon-software.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260526134907.11402-1-almaz.alexandrovich@paragon-software.com> References: <20260526134907.11402-1-almaz.alexandrovich@paragon-software.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: vobn-exch-01.paragon-software.com (172.30.72.13) To vdlg-exch-02.paragon-software.com (172.30.1.105) Content-Type: text/plain; charset="utf-8" It makes ntfs3 wait for direct I/O completion before returning to the caller, instead of allowing the write path to complete asynchronously. The issue was discovered during internal tests. Signed-off-by: Konstantin Komarov --- fs/ntfs3/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index 2d1de3739ffe..26bec5be248e 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -1398,7 +1398,8 @@ static ssize_t ntfs_file_write_iter(struct kiocb *ioc= b, struct iov_iter *from) goto out; } =20 - ret =3D iomap_dio_rw(iocb, from, &ntfs_iomap_ops, NULL, 0, NULL, 0); + ret =3D iomap_dio_rw(iocb, from, &ntfs_iomap_ops, NULL, + IOMAP_DIO_FORCE_WAIT, NULL, 0); =20 if (ret =3D=3D -ENOTBLK) { /* Returns -ENOTBLK in case of a page invalidation failure for writes.*/ --=20 2.43.0 From nobody Mon Jun 8 21:52:13 2026 Received: from relayaws-01.paragon-software.com (relayaws-01.paragon-software.com [35.157.23.187]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D1BF53D1CA7; Tue, 26 May 2026 13:49:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=35.157.23.187 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779803379; cv=none; b=iFhtdYj3UFrAdwiTOWsgZpzlc/tzlJUR7kx2cqsDEzj86bJeDDoXspyWw+NbfyDw/8GKrkzWcoVGBOBOp8YA8uu7bugmYR9fBBPtA1k4VVXdj7BMeUSNo9SfWRshUtYg8X34pf7CrH/TlpbYsdNt6A2Cn8gB6bG2iHNF2gb2p9A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779803379; c=relaxed/simple; bh=zoxcOjS65bzYA183nVfLEM9Mp+YADBx0tA2OotYBBII=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=qwTTzy1HSRzWyfSnb9bsvGY6aIaG2cLnnR6HXro0+IOhFGZdr2xNfvCulcnr6i/HAU3uPhxvLdjduVpaAP+AX9tln6+wNa6CxxOCK8NnNrwd7A7g28iOlqvosk9+nzxxK6Sfom9tJgyEjEt3GaPNxDEiF90eWG1Yt3zP85VzW54= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=paragon-software.com; spf=pass smtp.mailfrom=paragon-software.com; dkim=pass (1024-bit key) header.d=paragon-software.com header.i=@paragon-software.com header.b=ZJHXJo6E; arc=none smtp.client-ip=35.157.23.187 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=paragon-software.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=paragon-software.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=paragon-software.com header.i=@paragon-software.com header.b="ZJHXJo6E" Received: from relayfre-01.paragon-software.com (relayfre-01.paragon-software.com [176.12.100.13]) by relayaws-01.paragon-software.com (Postfix) with ESMTPS id AD2561D3B; Tue, 26 May 2026 13:49:38 +0000 (UTC) Authentication-Results: relayaws-01.paragon-software.com; dkim=pass (1024-bit key; unprotected) header.d=paragon-software.com header.i=@paragon-software.com header.b=ZJHXJo6E; dkim-atps=neutral Received: from dlg2.mail.paragon-software.com (vdlg-exch-02.paragon-software.com [172.30.1.105]) by relayfre-01.paragon-software.com (Postfix) with ESMTPS id F339C2126; Tue, 26 May 2026 13:49:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paragon-software.com; s=mail; t=1779803376; bh=oXFfSAS2haSHo8sd3SCqP5trv8nTkjRXWKTqfWLQcKI=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=ZJHXJo6EBpA44VoWOpgPQioTYh5VmQfdGVuAp/jeyudR+9yYD1UX2iDSqGkqaGNz4 gOgsSXWJSt9nIcVuwMlRrvu7ejzcuUjrOU6KIbQMVofxQUS1k5ZXYeldCTiBhR0Q+P JozkP03V6qT6yoeXfxOkZLTOR/I8FLrXepnNcN24= Received: from localhost.localdomain (172.30.20.153) by vdlg-exch-02.paragon-software.com (172.30.1.105) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.7; Tue, 26 May 2026 16:49:34 +0300 From: Konstantin Komarov To: CC: , , Konstantin Komarov Subject: [PATCH 6/6] fs/ntfs3: fold file size handling into ntfs_set_size() Date: Tue, 26 May 2026 15:49:07 +0200 Message-ID: <20260526134907.11402-7-almaz.alexandrovich@paragon-software.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260526134907.11402-1-almaz.alexandrovich@paragon-software.com> References: <20260526134907.11402-1-almaz.alexandrovich@paragon-software.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: vobn-exch-01.paragon-software.com (172.30.72.13) To vdlg-exch-02.paragon-software.com (172.30.1.105) Content-Type: text/plain; charset="utf-8" Remove the separate ntfs_extend() and ntfs_truncate() helpers and route file size changes through ntfs_set_size(). This consolidates ntfs3 size updates in one place and lets the write, fallocate, and setattr paths share the same logic for updating i_size, valid data length, and preallocated extents. This patch fixes a few issues found during internal tests. Signed-off-by: Konstantin Komarov --- fs/ntfs3/file.c | 178 +++++++++++------------------------------------ fs/ntfs3/inode.c | 21 +++--- 2 files changed, 51 insertions(+), 148 deletions(-) diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index 26bec5be248e..06a5d9b44ac1 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -450,93 +450,6 @@ static int ntfs_file_mmap_prepare(struct vm_area_desc = *desc) return err; } =20 -static int ntfs_extend(struct inode *inode, loff_t pos, size_t count, - struct file *file) -{ - struct ntfs_inode *ni =3D ntfs_i(inode); - struct address_space *mapping =3D inode->i_mapping; - loff_t end =3D pos + count; - bool extend_init =3D file && pos > ni->i_valid; - int err; - - if (end <=3D inode->i_size && !extend_init) - return 0; - - /* Mark rw ntfs as dirty. It will be cleared at umount. */ - ntfs_set_state(ni->mi.sbi, NTFS_DIRTY_DIRTY); - - if (end > inode->i_size) { - /* - * Normal files: increase file size, allocate space. - * Sparse/Compressed: increase file size. No space allocated. - */ - err =3D ntfs_set_size(inode, end); - if (err) - goto out; - } - - if (extend_init && !is_compressed(ni)) { - err =3D ntfs_extend_initialized_size(file, ni, pos); - if (err) - goto out; - } else { - err =3D 0; - } - - inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); - mark_inode_dirty(inode); - - if (IS_SYNC(inode)) { - int err2; - - err =3D filemap_fdatawrite_range(mapping, pos, end - 1); - err2 =3D write_inode_now(inode, 1); - if (!err) - err =3D err2; - if (!err) - err =3D filemap_fdatawait_range(mapping, pos, end - 1); - } - -out: - return err; -} - -static int ntfs_truncate(struct inode *inode, loff_t new_size) -{ - int err; - struct ntfs_inode *ni =3D ntfs_i(inode); - u64 new_valid =3D min_t(u64, ni->i_valid, new_size); - - truncate_setsize(inode, new_size); - - ni_lock(ni); - - down_write(&ni->file.run_lock); - err =3D attr_set_size_ex(ni, ATTR_DATA, NULL, 0, &ni->file.run, new_size, - &new_valid, ni->mi.sbi->options->prealloc, NULL, - false); - up_write(&ni->file.run_lock); - - ni->i_valid =3D new_valid; - - ni_unlock(ni); - - if (err) - return err; - - ni->std_fa |=3D FILE_ATTRIBUTE_ARCHIVE; - inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); - if (!IS_DIRSYNC(inode)) { - mark_inode_dirty(inode); - } else { - err =3D ntfs_sync_inode(inode); - if (err) - return err; - } - - return 0; -} - /* * ntfs_fallocate - file_operations::ntfs_fallocate * @@ -743,57 +656,25 @@ static long ntfs_fallocate(struct file *file, int mod= e, loff_t vbo, loff_t len) if (is_supported_holes) { CLST vcn =3D vbo >> cluster_bits; CLST cend =3D bytes_to_cluster(sbi, end); - CLST cend_v =3D bytes_to_cluster(sbi, ni->i_valid); CLST lcn, clen; bool new; =20 - if (cend_v > cend) - cend_v =3D cend; - /* * Allocate and zero new clusters. - * Zeroing these clusters may be too long. - */ - for (; vcn < cend_v; vcn +=3D clen) { - err =3D attr_data_get_block(ni, vcn, cend_v - vcn, - &lcn, &clen, &new, - true, NULL, false); - if (err) - goto out; - } - - /* - * Moving up 'valid size'. - */ - err =3D ntfs_extend_initialized_size( - file, ni, (u64)cend_v << cluster_bits); - if (err) - goto out; - - /* - * Allocate but not zero new clusters. */ for (; vcn < cend; vcn +=3D clen) { err =3D attr_data_get_block(ni, vcn, cend - vcn, &lcn, &clen, &new, - false, NULL, false); + true, NULL, false); if (err) goto out; } } =20 if (mode & FALLOC_FL_KEEP_SIZE) { - ni_lock(ni); - /* True - Keep preallocated. */ - err =3D attr_set_size(ni, ATTR_DATA, NULL, 0, - &ni->file.run, i_size, &ni->i_valid, - true); - ni_unlock(ni); + err =3D ntfs_set_size(inode, i_size); if (err) goto out; - i_size_write(inode, i_size); - } else if (new_size > i_size) { - i_size_write(inode, new_size); } } =20 @@ -850,16 +731,20 @@ int ntfs_setattr(struct mnt_idmap *idmap, struct dent= ry *dentry, oldsize =3D i_size_read(inode); newsize =3D attr->ia_size; =20 - if (newsize <=3D oldsize) - err =3D ntfs_truncate(inode, newsize); - else - err =3D ntfs_extend(inode, newsize, 0, NULL); + if (newsize !=3D oldsize) { + truncate_setsize(inode, newsize); =20 - if (err) - goto out; + err =3D ntfs_set_size(inode, newsize); + if (err) { + i_size_write(inode, oldsize); + goto out; + } =20 - ni->ni_flags |=3D NI_FLAG_UPDATE_PARENT; - i_size_write(inode, newsize); + ni->std_fa |=3D FILE_ATTRIBUTE_ARCHIVE; + ni->ni_flags |=3D NI_FLAG_UPDATE_PARENT; + inode_set_mtime_to_ts(inode, + inode_set_ctime_current(inode)); + } } =20 setattr_copy(idmap, inode, attr); @@ -1333,6 +1218,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *ioc= b, struct iov_iter *from) struct file *file =3D iocb->ki_filp; struct inode *inode =3D file_inode(file); struct ntfs_inode *ni =3D ntfs_i(inode); + loff_t vbo, endbyte; ssize_t ret, err; =20 if (!inode_trylock(inode)) { @@ -1367,15 +1253,30 @@ static ssize_t ntfs_file_write_iter(struct kiocb *i= ocb, struct iov_iter *from) goto out; } =20 - ret =3D ntfs_extend(inode, iocb->ki_pos, ret, file); - if (ret) - goto out; + vbo =3D iocb->ki_pos; + endbyte =3D vbo + ret; + + if (endbyte > inode->i_size) { + /* + * Normal files: increase file size, allocate space. + * Sparse/Compressed: increase file size. No space allocated. + */ + ret =3D ntfs_set_size(inode, endbyte); + if (ret) + goto out; + } =20 if (is_compressed(ni)) { ret =3D ntfs_compress_write(iocb, from); goto out; } =20 + if (vbo > ni->i_valid) { + ret =3D ntfs_extend_initialized_size(file, ni, vbo); + if (ret) + goto out; + } + /* Fallback to buffered I/O if the inode does not support direct I/O. */ if (!(iocb->ki_flags & IOCB_DIRECT) || !ntfs_should_use_dio(iocb, from)) { @@ -1408,7 +1309,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *ioc= b, struct iov_iter *from) } =20 if (ret >=3D 0 && iov_iter_count(from)) { - loff_t offset =3D iocb->ki_pos, endbyte; + vbo =3D iocb->ki_pos; =20 iocb->ki_flags &=3D ~IOCB_DIRECT; err =3D iomap_file_buffered_write(iocb, from, &ntfs_iomap_ops, @@ -1426,15 +1327,15 @@ static ssize_t ntfs_file_write_iter(struct kiocb *i= ocb, struct iov_iter *from) * to complete off the I/O request. */ ret +=3D err; - endbyte =3D offset + err - 1; - err =3D filemap_write_and_wait_range(inode->i_mapping, offset, + endbyte =3D vbo + err - 1; + err =3D filemap_write_and_wait_range(inode->i_mapping, vbo, endbyte); if (err) { ret =3D err; goto out; } =20 - invalidate_mapping_pages(inode->i_mapping, offset >> PAGE_SHIFT, + invalidate_mapping_pages(inode->i_mapping, vbo >> PAGE_SHIFT, endbyte >> PAGE_SHIFT); } =20 @@ -1515,8 +1416,9 @@ static int ntfs_file_release(struct inode *inode, str= uct file *file) down_write(&ni->file.run_lock); =20 /* Deallocate preallocated. */ - err =3D attr_set_size(ni, ATTR_DATA, NULL, 0, &ni->file.run, - inode->i_size, &ni->i_valid, false); + err =3D attr_set_size_ex(ni, ATTR_DATA, NULL, 0, &ni->file.run, + inode->i_size, &ni->i_valid, false, NULL, + true); =20 up_write(&ni->file.run_lock); ni_unlock(ni); diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 9a75c2d832ca..2d3aad60caa4 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -693,17 +693,18 @@ int ntfs_set_size(struct inode *inode, u64 new_size) return -EFBIG; } =20 + /* Mark rw ntfs as dirty. It will be cleared at umount. */ + ntfs_set_state(sbi, NTFS_DIRTY_DIRTY); + ni_lock(ni); down_write(&ni->file.run_lock); + if (new_size < ni->i_valid) + ni->i_valid =3D new_size; =20 + /* last 'true' means keep preallocated. */ err =3D attr_set_size(ni, ATTR_DATA, NULL, 0, &ni->file.run, new_size, &ni->i_valid, true); =20 - if (!err) { - i_size_write(inode, new_size); - mark_inode_dirty(inode); - } - up_write(&ni->file.run_lock); ni_unlock(ni); =20 @@ -778,11 +779,6 @@ static int ntfs_iomap_begin(struct inode *inode, loff_= t offset, loff_t length, return err; } =20 - if (!clen) { - /* broken file? */ - return -EINVAL; - } - if (lcn =3D=3D EOF_LCN) { /* request out of file. */ if (flags & IOMAP_REPORT) { @@ -816,6 +812,11 @@ static int ntfs_iomap_begin(struct inode *inode, loff_= t offset, loff_t length, return 0; } =20 + if (!clen) { + /* broken file? */ + return -EINVAL; + } + iomap->bdev =3D inode->i_sb->s_bdev; iomap->offset =3D offset; iomap->length =3D ((loff_t)clen << cluster_bits) - off; --=20 2.43.0