[PATCH 5/7] ecryptfs: zero the tail of the last folio in place on truncate

From: Tal Zussman

Date: Wed Oct 14 2026 - 21:40:19 EST


A shrinking truncate zeroes the rest of the folio that holds the new
end of the file by copying from the zero page through ecryptfs_write().
Zero the folio in place with folio_zero_range() instead, the way the
truncate helpers in other filesystems do, and encrypt it to the lower
file. This no longer bumps i_size to the end of the folio and writes
that to the metadata before the real size is written. It also removes
the last struct page usage in ecryptfs.

Signed-off-by: Tal Zussman <tz2294@xxxxxxxxxxxx>
---
fs/ecryptfs/inode.c | 49 ++++++++++++++++++++++++++++++++++++-------------
1 file changed, 36 insertions(+), 13 deletions(-)

diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 525297c7ebd8..c743b0f2ab4b 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -718,6 +718,34 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
return lower_size;
}

+/**
+ * ecryptfs_zero_tail
+ * @inode: The ecryptfs inode
+ * @pos: The file offset from which to zero
+ *
+ * Zero the folio that holds @pos from @pos to its end, and write the
+ * result out to the lower file.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_zero_tail(struct inode *inode, loff_t pos)
+{
+ struct folio *folio;
+ size_t from;
+ int rc;
+
+ folio = read_mapping_folio(inode->i_mapping, pos >> PAGE_SHIFT, NULL);
+ if (IS_ERR(folio))
+ return PTR_ERR(folio);
+ from = offset_in_folio(folio, pos);
+ folio_lock(folio);
+ folio_zero_range(folio, from, folio_size(folio) - from);
+ folio_unlock(folio);
+ rc = ecryptfs_encrypt_page(folio);
+ folio_put(folio);
+ return rc;
+}
+
/**
* __ecryptfs_truncate
* @dentry: The ecryptfs layer dentry
@@ -739,7 +767,6 @@ static int __ecryptfs_truncate(struct dentry *dentry, const struct iattr *ia)
loff_t lower_size_before_truncate;
loff_t lower_size_after_truncate;
struct iattr lower_ia;
- size_t num_zeros;
int rc;

ecryptfs_iattr_to_lower(&lower_ia, ia);
@@ -788,19 +815,15 @@ static int __ecryptfs_truncate(struct dentry *dentry, const struct iattr *ia)
}

/*
- * We're chopping off all the pages down to the page in which
- * ia->ia_size is located. Fill in the end of that page from
- * (ia->ia_size & ~PAGE_MASK) to PAGE_SIZE with zeros.
+ * We're chopping off all the folios down to the folio in which
+ * ia->ia_size is located. Fill in the end of that folio from
+ * ia->ia_size with zeros.
*/
- num_zeros = PAGE_SIZE - (ia->ia_size & ~PAGE_MASK);
- if (num_zeros) {
- rc = ecryptfs_write(inode, page_address(ZERO_PAGE(0)),
- ia->ia_size, num_zeros);
- if (rc) {
- pr_err("Error attempting to zero out the remainder of the end page on reducing truncate; rc = [%d]\n",
- rc);
- goto out;
- }
+ rc = ecryptfs_zero_tail(inode, ia->ia_size);
+ if (rc) {
+ pr_err("Error attempting to zero out the remainder of the end folio on reducing truncate; rc = [%d]\n",
+ rc);
+ goto out;
}
truncate_setsize(inode, ia->ia_size);
rc = ecryptfs_write_inode_size_to_metadata(inode);

--
2.39.5