[PATCH v2 7/9] ecryptfs: zero the tail of the last folio in place on truncate
From: Tal Zussman
Date: Fri Oct 30 2026 - 06:27:01 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.
The folio stays locked while it is encrypted, as in
ecryptfs_writepages(), and is marked not uptodate if that fails, so a
later read goes back to the lower file instead of returning zeroes that
were never written out.
Signed-off-by: Tal Zussman <tz2294@xxxxxxxxxxxx>
---
fs/ecryptfs/inode.c | 51 ++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 38 insertions(+), 13 deletions(-)
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 525297c7ebd8..2d6f4f440f65 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -718,6 +718,36 @@ 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);
+ rc = ecryptfs_encrypt_page(folio);
+ if (rc)
+ folio_clear_uptodate(folio);
+ folio_unlock(folio);
+ folio_put(folio);
+ return rc;
+}
+
/**
* __ecryptfs_truncate
* @dentry: The ecryptfs layer dentry
@@ -739,7 +769,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 +817,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