* cleanup truncate handling in ecryptfs v2
@ 2026-04-07 14:02 Christoph Hellwig
2026-04-07 14:02 ` [PATCH 1/7] ecryptfs: streamline truncate_upper Christoph Hellwig
` (7 more replies)
0 siblings, 8 replies; 10+ messages in thread
From: Christoph Hellwig @ 2026-04-07 14:02 UTC (permalink / raw)
To: Tyler Hicks; +Cc: ecryptfs, linux-fsdevel
Hi Tyler,
this series cleans up the truncate handling in ecryptfs. I did
it as preparation for some changes into size changing truncate
VFS interfaces I'm looking into in the moment. The changes have
passed the regression test suite in the userspace ecryptfs
repository and against the ecryptfs next branch.
Changes since v1:
- fix a pre-existing spelling error in a comment
- pass an explicit new_size argument to the main truncate routines
- fix a comment that kept obsolete information
Diffstat:
inode.c | 243 +++++++++++++++++++++++++++-------------------------------------
1 file changed, 105 insertions(+), 138 deletions(-)
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/7] ecryptfs: streamline truncate_upper
2026-04-07 14:02 cleanup truncate handling in ecryptfs v2 Christoph Hellwig
@ 2026-04-07 14:02 ` Christoph Hellwig
2026-04-07 14:02 ` [PATCH 2/7] ecryptfs: cleanup ecryptfs_setattr Christoph Hellwig
` (6 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Christoph Hellwig @ 2026-04-07 14:02 UTC (permalink / raw)
To: Tyler Hicks; +Cc: ecryptfs, linux-fsdevel
Use a few strategic gotos to keep reduce indentation and keep the
main reduce size flow outside of branches. Switch all touched comments
to normal kernel style and avoid breaks in printed strings for all
the code touched.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/ecryptfs/inode.c | 115 +++++++++++++++++++++++---------------------
1 file changed, 60 insertions(+), 55 deletions(-)
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 8ab014db3e03..69a5dfaddc5c 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -725,83 +725,88 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
static int truncate_upper(struct dentry *dentry, struct iattr *ia,
struct iattr *lower_ia)
{
- int rc = 0;
struct inode *inode = d_inode(dentry);
struct ecryptfs_crypt_stat *crypt_stat;
loff_t i_size = i_size_read(inode);
loff_t lower_size_before_truncate;
loff_t lower_size_after_truncate;
+ size_t num_zeros;
+ int rc;
if (unlikely((ia->ia_size == i_size))) {
lower_ia->ia_valid &= ~ATTR_SIZE;
return 0;
}
+
rc = ecryptfs_get_lower_file(dentry, inode);
if (rc)
return rc;
- crypt_stat = &ecryptfs_inode_to_private(d_inode(dentry))->crypt_stat;
- /* Switch on growing or shrinking file */
+
if (ia->ia_size > i_size) {
char zero[] = { 0x00 };
+ /*
+ * Write a single 0 at the last position of the file; this
+ * triggers code that will fill in 0's throughout the
+ * intermediate portion of the previous end of the file and the
+ * new end of the file.
+ */
+ rc = ecryptfs_write(inode, zero, ia->ia_size - 1, 1);
lower_ia->ia_valid &= ~ATTR_SIZE;
- /* Write a single 0 at the last position of the file;
- * this triggers code that will fill in 0's throughout
- * the intermediate portion of the previous end of the
- * file and the new and of the file */
- rc = ecryptfs_write(inode, zero,
- (ia->ia_size - 1), 1);
- } else { /* ia->ia_size < i_size_read(inode) */
- /* 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. */
- size_t num_zeros = (PAGE_SIZE
- - (ia->ia_size & ~PAGE_MASK));
-
- if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
- truncate_setsize(inode, ia->ia_size);
- lower_ia->ia_size = ia->ia_size;
- lower_ia->ia_valid |= ATTR_SIZE;
- goto out;
- }
- if (num_zeros) {
- char *zeros_virt;
+ goto out;
+ }
- zeros_virt = kzalloc(num_zeros, GFP_KERNEL);
- if (!zeros_virt) {
- rc = -ENOMEM;
- goto out;
- }
- rc = ecryptfs_write(inode, zeros_virt,
- ia->ia_size, num_zeros);
- kfree(zeros_virt);
- if (rc) {
- printk(KERN_ERR "Error attempting to zero out "
- "the remainder of the end page on "
- "reducing truncate; rc = [%d]\n", rc);
- goto out;
- }
- }
+ crypt_stat = &ecryptfs_inode_to_private(d_inode(dentry))->crypt_stat;
+ if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
truncate_setsize(inode, ia->ia_size);
- rc = ecryptfs_write_inode_size_to_metadata(inode);
+ lower_ia->ia_size = ia->ia_size;
+ lower_ia->ia_valid |= ATTR_SIZE;
+ goto out;
+ }
+
+ /*
+ * 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.
+ */
+ num_zeros = PAGE_SIZE - (ia->ia_size & ~PAGE_MASK);
+ if (num_zeros) {
+ char *zeros_virt;
+
+ zeros_virt = kzalloc(num_zeros, GFP_KERNEL);
+ if (!zeros_virt) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ rc = ecryptfs_write(inode, zeros_virt, ia->ia_size, num_zeros);
+ kfree(zeros_virt);
if (rc) {
- printk(KERN_ERR "Problem with "
- "ecryptfs_write_inode_size_to_metadata; "
- "rc = [%d]\n", rc);
+ pr_err("Error attempting to zero out the remainder of the end page on reducing truncate; rc = [%d]\n",
+ rc);
goto out;
}
- /* We are reducing the size of the ecryptfs file, and need to
- * know if we need to reduce the size of the lower file. */
- lower_size_before_truncate =
- upper_size_to_lower_size(crypt_stat, i_size);
- lower_size_after_truncate =
- upper_size_to_lower_size(crypt_stat, ia->ia_size);
- if (lower_size_after_truncate < lower_size_before_truncate) {
- lower_ia->ia_size = lower_size_after_truncate;
- lower_ia->ia_valid |= ATTR_SIZE;
- } else
- lower_ia->ia_valid &= ~ATTR_SIZE;
+ }
+ truncate_setsize(inode, ia->ia_size);
+ rc = ecryptfs_write_inode_size_to_metadata(inode);
+ if (rc) {
+ pr_err("Problem with ecryptfs_write_inode_size_to_metadata; rc = [%d]\n",
+ rc);
+ goto out;
+ }
+
+ /*
+ * We are reducing the size of the ecryptfs file, and need to know if we
+ * need to reduce the size of the lower file.
+ */
+ lower_size_before_truncate =
+ upper_size_to_lower_size(crypt_stat, i_size);
+ lower_size_after_truncate =
+ upper_size_to_lower_size(crypt_stat, ia->ia_size);
+ if (lower_size_after_truncate < lower_size_before_truncate) {
+ lower_ia->ia_size = lower_size_after_truncate;
+ lower_ia->ia_valid |= ATTR_SIZE;
+ } else {
+ lower_ia->ia_valid &= ~ATTR_SIZE;
}
out:
ecryptfs_put_lower_file(inode);
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/7] ecryptfs: cleanup ecryptfs_setattr
2026-04-07 14:02 cleanup truncate handling in ecryptfs v2 Christoph Hellwig
2026-04-07 14:02 ` [PATCH 1/7] ecryptfs: streamline truncate_upper Christoph Hellwig
@ 2026-04-07 14:02 ` Christoph Hellwig
2026-04-07 14:02 ` [PATCH 3/7] ecryptfs: use ZERO_PAGE instead of allocating zeroed memory in truncate_upper Christoph Hellwig
` (5 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Christoph Hellwig @ 2026-04-07 14:02 UTC (permalink / raw)
To: Tyler Hicks; +Cc: ecryptfs, linux-fsdevel
Initialize variables at declaration time where applicable and reformat
conditionals to match the kernel coding style.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/ecryptfs/inode.c | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 69a5dfaddc5c..695573850569 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -891,25 +891,23 @@ ecryptfs_permission(struct mnt_idmap *idmap, struct inode *inode,
static int ecryptfs_setattr(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *ia)
{
- int rc = 0;
- struct dentry *lower_dentry;
+ struct inode *inode = d_inode(dentry);
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ struct inode *lower_inode = ecryptfs_inode_to_lower(inode);
struct iattr lower_ia;
- struct inode *inode;
- struct inode *lower_inode;
struct ecryptfs_crypt_stat *crypt_stat;
+ int rc;
crypt_stat = &ecryptfs_inode_to_private(d_inode(dentry))->crypt_stat;
if (!(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED))
ecryptfs_init_crypt_stat(crypt_stat);
- inode = d_inode(dentry);
- lower_inode = ecryptfs_inode_to_lower(inode);
- lower_dentry = ecryptfs_dentry_to_lower(dentry);
+
mutex_lock(&crypt_stat->cs_mutex);
if (d_is_dir(dentry))
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
- else if (d_is_reg(dentry)
- && (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)
- || !(crypt_stat->flags & ECRYPTFS_KEY_VALID))) {
+ else if (d_is_reg(dentry) &&
+ (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) ||
+ !(crypt_stat->flags & ECRYPTFS_KEY_VALID))) {
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
mount_crypt_stat = &ecryptfs_superblock_to_private(
@@ -922,8 +920,8 @@ static int ecryptfs_setattr(struct mnt_idmap *idmap,
rc = ecryptfs_read_metadata(dentry);
ecryptfs_put_lower_file(inode);
if (rc) {
- if (!(mount_crypt_stat->flags
- & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
+ if (!(mount_crypt_stat->flags &
+ ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
rc = -EIO;
printk(KERN_WARNING "Either the lower file "
"is not in a valid eCryptfs format, "
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/7] ecryptfs: use ZERO_PAGE instead of allocating zeroed memory in truncate_upper
2026-04-07 14:02 cleanup truncate handling in ecryptfs v2 Christoph Hellwig
2026-04-07 14:02 ` [PATCH 1/7] ecryptfs: streamline truncate_upper Christoph Hellwig
2026-04-07 14:02 ` [PATCH 2/7] ecryptfs: cleanup ecryptfs_setattr Christoph Hellwig
@ 2026-04-07 14:02 ` Christoph Hellwig
2026-04-07 14:02 ` [PATCH 4/7] ecryptfs: combine the two ATTR_SIZE blocks in ecryptfs_setattr Christoph Hellwig
` (4 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Christoph Hellwig @ 2026-04-07 14:02 UTC (permalink / raw)
To: Tyler Hicks; +Cc: ecryptfs, linux-fsdevel
Use the existing pre-zeroed memory instead of allocating a new chunk.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/ecryptfs/inode.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 695573850569..daa63b7dd015 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -771,15 +771,8 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
*/
num_zeros = PAGE_SIZE - (ia->ia_size & ~PAGE_MASK);
if (num_zeros) {
- char *zeros_virt;
-
- zeros_virt = kzalloc(num_zeros, GFP_KERNEL);
- if (!zeros_virt) {
- rc = -ENOMEM;
- goto out;
- }
- rc = ecryptfs_write(inode, zeros_virt, ia->ia_size, num_zeros);
- kfree(zeros_virt);
+ 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);
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/7] ecryptfs: combine the two ATTR_SIZE blocks in ecryptfs_setattr
2026-04-07 14:02 cleanup truncate handling in ecryptfs v2 Christoph Hellwig
` (2 preceding siblings ...)
2026-04-07 14:02 ` [PATCH 3/7] ecryptfs: use ZERO_PAGE instead of allocating zeroed memory in truncate_upper Christoph Hellwig
@ 2026-04-07 14:02 ` Christoph Hellwig
2026-04-07 14:02 ` [PATCH 5/7] ecryptfs: sanitize struct iattr handling in truncate_upper Christoph Hellwig
` (3 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Christoph Hellwig @ 2026-04-07 14:02 UTC (permalink / raw)
To: Tyler Hicks; +Cc: ecryptfs, linux-fsdevel
Simplify the logic in ecryptfs_setattr by combining the two ATTR_SIZE
blocks. This initializes lower_ia before the size check, which is
obviously correct as the size check doesn't look at it.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/ecryptfs/inode.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index daa63b7dd015..ec6aae5af1f8 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -934,16 +934,15 @@ static int ecryptfs_setattr(struct mnt_idmap *idmap,
rc = setattr_prepare(&nop_mnt_idmap, dentry, ia);
if (rc)
goto out;
- if (ia->ia_valid & ATTR_SIZE) {
- rc = ecryptfs_inode_newsize_ok(inode, ia->ia_size);
- if (rc)
- goto out;
- }
memcpy(&lower_ia, ia, sizeof(lower_ia));
if (ia->ia_valid & ATTR_FILE)
lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file);
if (ia->ia_valid & ATTR_SIZE) {
+ rc = ecryptfs_inode_newsize_ok(inode, ia->ia_size);
+ if (rc)
+ goto out;
+
rc = truncate_upper(dentry, ia, &lower_ia);
if (rc < 0)
goto out;
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/7] ecryptfs: sanitize struct iattr handling in truncate_upper
2026-04-07 14:02 cleanup truncate handling in ecryptfs v2 Christoph Hellwig
` (3 preceding siblings ...)
2026-04-07 14:02 ` [PATCH 4/7] ecryptfs: combine the two ATTR_SIZE blocks in ecryptfs_setattr Christoph Hellwig
@ 2026-04-07 14:02 ` Christoph Hellwig
2026-04-07 14:02 ` [PATCH 6/7] ecryptfs: merge ecryptfs_inode_newsize_ok into truncate_upper Christoph Hellwig
` (2 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Christoph Hellwig @ 2026-04-07 14:02 UTC (permalink / raw)
To: Tyler Hicks; +Cc: ecryptfs, linux-fsdevel
Currently the two callers of truncate_upper handle passing information
very differently. ecryptfs_truncate passes a zeroed lower_ia and expects
truncate_upper to fill it in from the upper ia created just for that,
while ecryptfs_setattr passes a fully initialized lower_ia copied from
the upper one.
Switch to only passing a new upper size and the lower ia. This cleans up
the logic in truncate_upper and ecryptfs_truncate.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/ecryptfs/inode.c | 49 ++++++++++++++++++++++-----------------------
1 file changed, 24 insertions(+), 25 deletions(-)
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index ec6aae5af1f8..870eb82003be 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -709,7 +709,7 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
/**
* truncate_upper
* @dentry: The ecryptfs layer dentry
- * @ia: Address of the ecryptfs inode's attributes
+ * @new_size: New upper file size.
* @lower_ia: Address of the lower inode's attributes
*
* Function to handle truncations modifying the size of the file. Note
@@ -722,8 +722,8 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
*
* Returns zero on success; non-zero otherwise
*/
-static int truncate_upper(struct dentry *dentry, struct iattr *ia,
- struct iattr *lower_ia)
+static int truncate_upper(struct dentry *dentry, loff_t new_size,
+ struct iattr *lower_ia)
{
struct inode *inode = d_inode(dentry);
struct ecryptfs_crypt_stat *crypt_stat;
@@ -733,7 +733,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
size_t num_zeros;
int rc;
- if (unlikely((ia->ia_size == i_size))) {
+ if (unlikely(new_size == i_size)) {
lower_ia->ia_valid &= ~ATTR_SIZE;
return 0;
}
@@ -742,7 +742,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
if (rc)
return rc;
- if (ia->ia_size > i_size) {
+ if (new_size > i_size) {
char zero[] = { 0x00 };
/*
@@ -751,35 +751,34 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
* intermediate portion of the previous end of the file and the
* new end of the file.
*/
- rc = ecryptfs_write(inode, zero, ia->ia_size - 1, 1);
+ rc = ecryptfs_write(inode, zero, new_size - 1, 1);
lower_ia->ia_valid &= ~ATTR_SIZE;
goto out;
}
crypt_stat = &ecryptfs_inode_to_private(d_inode(dentry))->crypt_stat;
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
- truncate_setsize(inode, ia->ia_size);
- lower_ia->ia_size = ia->ia_size;
- lower_ia->ia_valid |= ATTR_SIZE;
+ truncate_setsize(inode, new_size);
+ lower_ia->ia_size = new_size;
goto out;
}
/*
- * 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 pages down to the page in which new_size
+ * is located. Fill in the end of that page from new_size & ~PAGE_MASK
+ * to PAGE_SIZE with zeros.
*/
- num_zeros = PAGE_SIZE - (ia->ia_size & ~PAGE_MASK);
+ num_zeros = PAGE_SIZE - (new_size & ~PAGE_MASK);
if (num_zeros) {
- rc = ecryptfs_write(inode, page_address(ZERO_PAGE(0)),
- ia->ia_size, num_zeros);
+ rc = ecryptfs_write(inode, page_address(ZERO_PAGE(0)), new_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;
}
}
- truncate_setsize(inode, ia->ia_size);
+ truncate_setsize(inode, new_size);
rc = ecryptfs_write_inode_size_to_metadata(inode);
if (rc) {
pr_err("Problem with ecryptfs_write_inode_size_to_metadata; rc = [%d]\n",
@@ -794,13 +793,12 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
lower_size_before_truncate =
upper_size_to_lower_size(crypt_stat, i_size);
lower_size_after_truncate =
- upper_size_to_lower_size(crypt_stat, ia->ia_size);
- if (lower_size_after_truncate < lower_size_before_truncate) {
+ upper_size_to_lower_size(crypt_stat, new_size);
+ if (lower_size_after_truncate < lower_size_before_truncate)
lower_ia->ia_size = lower_size_after_truncate;
- lower_ia->ia_valid |= ATTR_SIZE;
- } else {
+ else
lower_ia->ia_valid &= ~ATTR_SIZE;
- }
+
out:
ecryptfs_put_lower_file(inode);
return rc;
@@ -840,15 +838,16 @@ static int ecryptfs_inode_newsize_ok(struct inode *inode, loff_t offset)
*/
int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
{
- struct iattr ia = { .ia_valid = ATTR_SIZE, .ia_size = new_length };
- struct iattr lower_ia = { .ia_valid = 0 };
+ struct iattr lower_ia = {
+ .ia_valid = ATTR_SIZE,
+ };
int rc;
rc = ecryptfs_inode_newsize_ok(d_inode(dentry), new_length);
if (rc)
return rc;
- rc = truncate_upper(dentry, &ia, &lower_ia);
+ rc = truncate_upper(dentry, new_length, &lower_ia);
if (!rc && lower_ia.ia_valid & ATTR_SIZE) {
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
@@ -943,7 +942,7 @@ static int ecryptfs_setattr(struct mnt_idmap *idmap,
if (rc)
goto out;
- rc = truncate_upper(dentry, ia, &lower_ia);
+ rc = truncate_upper(dentry, ia->ia_size, &lower_ia);
if (rc < 0)
goto out;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/7] ecryptfs: merge ecryptfs_inode_newsize_ok into truncate_upper
2026-04-07 14:02 cleanup truncate handling in ecryptfs v2 Christoph Hellwig
` (4 preceding siblings ...)
2026-04-07 14:02 ` [PATCH 5/7] ecryptfs: sanitize struct iattr handling in truncate_upper Christoph Hellwig
@ 2026-04-07 14:02 ` Christoph Hellwig
2026-04-07 14:02 ` [PATCH 7/7] ecryptfs: call notify_change from truncate_upper Christoph Hellwig
2026-04-07 14:50 ` cleanup truncate handling in ecryptfs v2 Christoph Hellwig
7 siblings, 0 replies; 10+ messages in thread
From: Christoph Hellwig @ 2026-04-07 14:02 UTC (permalink / raw)
To: Tyler Hicks; +Cc: ecryptfs, linux-fsdevel
Both callers of ecryptfs_inode_newsize_ok call truncate_upper right
after. Merge ecryptfs_inode_newsize_ok into truncate_upper to simplify
the logic.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/ecryptfs/inode.c | 53 +++++++++++++++------------------------------
1 file changed, 17 insertions(+), 36 deletions(-)
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 870eb82003be..a7c6171db85b 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -738,6 +738,23 @@ static int truncate_upper(struct dentry *dentry, loff_t new_size,
return 0;
}
+ crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+ lower_size_before_truncate =
+ upper_size_to_lower_size(crypt_stat, i_size);
+ lower_size_after_truncate =
+ upper_size_to_lower_size(crypt_stat, new_size);
+ if (lower_size_after_truncate > lower_size_before_truncate) {
+ /*
+ * The eCryptfs inode and the new *lower* size are mixed here
+ * because we may not have the lower i_mutex held and/or it may
+ * not be appropriate to call inode_newsize_ok() with inodes
+ * from other filesystems.
+ */
+ rc = inode_newsize_ok(inode, lower_size_after_truncate);
+ if (rc)
+ return rc;
+ }
+
rc = ecryptfs_get_lower_file(dentry, inode);
if (rc)
return rc;
@@ -756,7 +773,6 @@ static int truncate_upper(struct dentry *dentry, loff_t new_size,
goto out;
}
- crypt_stat = &ecryptfs_inode_to_private(d_inode(dentry))->crypt_stat;
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
truncate_setsize(inode, new_size);
lower_ia->ia_size = new_size;
@@ -790,42 +806,15 @@ static int truncate_upper(struct dentry *dentry, loff_t new_size,
* We are reducing the size of the ecryptfs file, and need to know if we
* need to reduce the size of the lower file.
*/
- lower_size_before_truncate =
- upper_size_to_lower_size(crypt_stat, i_size);
- lower_size_after_truncate =
- upper_size_to_lower_size(crypt_stat, new_size);
if (lower_size_after_truncate < lower_size_before_truncate)
lower_ia->ia_size = lower_size_after_truncate;
else
lower_ia->ia_valid &= ~ATTR_SIZE;
-
out:
ecryptfs_put_lower_file(inode);
return rc;
}
-static int ecryptfs_inode_newsize_ok(struct inode *inode, loff_t offset)
-{
- struct ecryptfs_crypt_stat *crypt_stat;
- loff_t lower_oldsize, lower_newsize;
-
- crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
- lower_oldsize = upper_size_to_lower_size(crypt_stat,
- i_size_read(inode));
- lower_newsize = upper_size_to_lower_size(crypt_stat, offset);
- if (lower_newsize > lower_oldsize) {
- /*
- * The eCryptfs inode and the new *lower* size are mixed here
- * because we may not have the lower i_mutex held and/or it may
- * not be appropriate to call inode_newsize_ok() with inodes
- * from other filesystems.
- */
- return inode_newsize_ok(inode, lower_newsize);
- }
-
- return 0;
-}
-
/**
* ecryptfs_truncate
* @dentry: The ecryptfs layer dentry
@@ -843,10 +832,6 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
};
int rc;
- rc = ecryptfs_inode_newsize_ok(d_inode(dentry), new_length);
- if (rc)
- return rc;
-
rc = truncate_upper(dentry, new_length, &lower_ia);
if (!rc && lower_ia.ia_valid & ATTR_SIZE) {
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
@@ -938,10 +923,6 @@ static int ecryptfs_setattr(struct mnt_idmap *idmap,
if (ia->ia_valid & ATTR_FILE)
lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file);
if (ia->ia_valid & ATTR_SIZE) {
- rc = ecryptfs_inode_newsize_ok(inode, ia->ia_size);
- if (rc)
- goto out;
-
rc = truncate_upper(dentry, ia->ia_size, &lower_ia);
if (rc < 0)
goto out;
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 7/7] ecryptfs: call notify_change from truncate_upper
2026-04-07 14:02 cleanup truncate handling in ecryptfs v2 Christoph Hellwig
` (5 preceding siblings ...)
2026-04-07 14:02 ` [PATCH 6/7] ecryptfs: merge ecryptfs_inode_newsize_ok into truncate_upper Christoph Hellwig
@ 2026-04-07 14:02 ` Christoph Hellwig
2026-04-07 14:50 ` cleanup truncate handling in ecryptfs v2 Christoph Hellwig
7 siblings, 0 replies; 10+ messages in thread
From: Christoph Hellwig @ 2026-04-07 14:02 UTC (permalink / raw)
To: Tyler Hicks; +Cc: ecryptfs, linux-fsdevel
Keep all the truncation logic in one place by also moving the call to
notify_change into truncate_upper. Rename the resulting function to
__ecryptfs_truncate as it deals with both the lower and upper inodes.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/ecryptfs/inode.c | 74 ++++++++++++++++++++-------------------------
1 file changed, 33 insertions(+), 41 deletions(-)
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index a7c6171db85b..58ec6229da4c 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -707,25 +707,23 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
}
/**
- * truncate_upper
+ * __ecryptfs_truncate - change size of an ecryptfs file.
* @dentry: The ecryptfs layer dentry
* @new_size: New upper file size.
* @lower_ia: Address of the lower inode's attributes
*
- * Function to handle truncations modifying the size of the file. Note
- * that the file sizes are interpolated. When expanding, we are simply
- * writing strings of 0's out. When truncating, we truncate the upper
- * inode and update the lower_ia according to the page index
- * interpolations. If ATTR_SIZE is set in lower_ia->ia_valid upon return,
- * the caller must use lower_ia in a call to notify_change() to perform
- * the truncation of the lower inode.
+ * Function to handle truncations modifying the size of the file. Note that the
+ * lower file sizes are interpolated. When expanding, we are simply writing
+ * strings of 0's out. When truncating, we truncate the upper inode and update
+ * the lower_ia according to the page index interpolations.
*
- * Returns zero on success; non-zero otherwise
+ * Returns zero on success; non-zero otherwise.
*/
-static int truncate_upper(struct dentry *dentry, loff_t new_size,
+static int __ecryptfs_truncate(struct dentry *dentry, loff_t new_size,
struct iattr *lower_ia)
{
struct inode *inode = d_inode(dentry);
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
struct ecryptfs_crypt_stat *crypt_stat;
loff_t i_size = i_size_read(inode);
loff_t lower_size_before_truncate;
@@ -733,10 +731,8 @@ static int truncate_upper(struct dentry *dentry, loff_t new_size,
size_t num_zeros;
int rc;
- if (unlikely(new_size == i_size)) {
- lower_ia->ia_valid &= ~ATTR_SIZE;
+ if (unlikely(new_size == i_size))
return 0;
- }
crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
lower_size_before_truncate =
@@ -769,14 +765,13 @@ static int truncate_upper(struct dentry *dentry, loff_t new_size,
* new end of the file.
*/
rc = ecryptfs_write(inode, zero, new_size - 1, 1);
- lower_ia->ia_valid &= ~ATTR_SIZE;
goto out;
}
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
truncate_setsize(inode, new_size);
lower_ia->ia_size = new_size;
- goto out;
+ goto set_size;
}
/*
@@ -806,10 +801,14 @@ static int truncate_upper(struct dentry *dentry, loff_t new_size,
* We are reducing the size of the ecryptfs file, and need to know if we
* need to reduce the size of the lower file.
*/
- if (lower_size_after_truncate < lower_size_before_truncate)
- lower_ia->ia_size = lower_size_after_truncate;
- else
- lower_ia->ia_valid &= ~ATTR_SIZE;
+ if (lower_size_after_truncate >= lower_size_before_truncate)
+ goto out;
+
+ lower_ia->ia_size = lower_size_after_truncate;
+set_size:
+ inode_lock(d_inode(lower_dentry));
+ rc = notify_change(&nop_mnt_idmap, lower_dentry, lower_ia, NULL);
+ inode_unlock(d_inode(lower_dentry));
out:
ecryptfs_put_lower_file(inode);
return rc;
@@ -830,18 +829,8 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
struct iattr lower_ia = {
.ia_valid = ATTR_SIZE,
};
- int rc;
-
- rc = truncate_upper(dentry, new_length, &lower_ia);
- if (!rc && lower_ia.ia_valid & ATTR_SIZE) {
- struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
- inode_lock(d_inode(lower_dentry));
- rc = notify_change(&nop_mnt_idmap, lower_dentry,
- &lower_ia, NULL);
- inode_unlock(d_inode(lower_dentry));
- }
- return rc;
+ return __ecryptfs_truncate(dentry, new_length, &lower_ia);
}
static int
@@ -869,7 +858,6 @@ static int ecryptfs_setattr(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *ia)
{
struct inode *inode = d_inode(dentry);
- struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
struct inode *lower_inode = ecryptfs_inode_to_lower(inode);
struct iattr lower_ia;
struct ecryptfs_crypt_stat *crypt_stat;
@@ -920,13 +908,6 @@ static int ecryptfs_setattr(struct mnt_idmap *idmap,
goto out;
memcpy(&lower_ia, ia, sizeof(lower_ia));
- if (ia->ia_valid & ATTR_FILE)
- lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file);
- if (ia->ia_valid & ATTR_SIZE) {
- rc = truncate_upper(dentry, ia->ia_size, &lower_ia);
- if (rc < 0)
- goto out;
- }
/*
* mode change is for clearing setuid/setgid bits. Allow lower fs
@@ -935,9 +916,20 @@ static int ecryptfs_setattr(struct mnt_idmap *idmap,
if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
lower_ia.ia_valid &= ~ATTR_MODE;
- inode_lock(d_inode(lower_dentry));
- rc = notify_change(&nop_mnt_idmap, lower_dentry, &lower_ia, NULL);
- inode_unlock(d_inode(lower_dentry));
+ if (ia->ia_valid & ATTR_SIZE) {
+ if (ia->ia_valid & ATTR_FILE)
+ lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file);
+ rc = __ecryptfs_truncate(dentry, ia->ia_size, &lower_ia);
+ if (rc < 0)
+ goto out;
+ } else {
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+
+ inode_lock(d_inode(lower_dentry));
+ rc = notify_change(&nop_mnt_idmap, lower_dentry, &lower_ia,
+ NULL);
+ inode_unlock(d_inode(lower_dentry));
+ }
out:
fsstack_copy_attr_all(inode, lower_inode);
return rc;
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: cleanup truncate handling in ecryptfs v2
2026-04-07 14:02 cleanup truncate handling in ecryptfs v2 Christoph Hellwig
` (6 preceding siblings ...)
2026-04-07 14:02 ` [PATCH 7/7] ecryptfs: call notify_change from truncate_upper Christoph Hellwig
@ 2026-04-07 14:50 ` Christoph Hellwig
2026-04-08 1:10 ` Tyler Hicks
7 siblings, 1 reply; 10+ messages in thread
From: Christoph Hellwig @ 2026-04-07 14:50 UTC (permalink / raw)
To: Tyler Hicks, ecryptfs, linux-fsdevel
On Tue, Apr 07, 2026 at 04:02:36PM +0200, Christoph Hellwig wrote:
> Hi Tyler,
>
> this series cleans up the truncate handling in ecryptfs. I did
> it as preparation for some changes into size changing truncate
> VFS interfaces I'm looking into in the moment. The changes have
> passed the regression test suite in the userspace ecryptfs
> repository and against the ecryptfs next branch.
So right after I posted this I came up with an idea how to better
pass arguments to the low-level truncate helper as the size + lower_ia
kept irking me. The branch here:
https://git.infradead.org/?p=users/hch/misc.git;a=shortlog;h=refs/heads/ecryptfs-truncate
simply only passed the upper ia, which feels a lot cleaner. It passes
the ecryptfs test suite, but otherwise is hot off the press. If you
like the new version I'll send it out tomorrow.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: cleanup truncate handling in ecryptfs v2
2026-04-07 14:50 ` cleanup truncate handling in ecryptfs v2 Christoph Hellwig
@ 2026-04-08 1:10 ` Tyler Hicks
0 siblings, 0 replies; 10+ messages in thread
From: Tyler Hicks @ 2026-04-08 1:10 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: ecryptfs, linux-fsdevel
On 2026-04-07 07:50:27, Christoph Hellwig wrote:
> On Tue, Apr 07, 2026 at 04:02:36PM +0200, Christoph Hellwig wrote:
> > Hi Tyler,
> >
> > this series cleans up the truncate handling in ecryptfs. I did
> > it as preparation for some changes into size changing truncate
> > VFS interfaces I'm looking into in the moment. The changes have
> > passed the regression test suite in the userspace ecryptfs
> > repository and against the ecryptfs next branch.
>
> So right after I posted this I came up with an idea how to better
> pass arguments to the low-level truncate helper as the size + lower_ia
> kept irking me. The branch here:
>
> https://git.infradead.org/?p=users/hch/misc.git;a=shortlog;h=refs/heads/ecryptfs-truncate
>
> simply only passed the upper ia, which feels a lot cleaner. It passes
> the ecryptfs test suite, but otherwise is hot off the press. If you
> like the new version I'll send it out tomorrow.
>
Yep, that's the right thing to do. Thanks for give it more thought.
I only had time to do a diff between v1 and this branch. The code
changes look good. One tiny typo in a code comment:
s/file systen/file system/
Tyler
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-04-08 1:10 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-07 14:02 cleanup truncate handling in ecryptfs v2 Christoph Hellwig
2026-04-07 14:02 ` [PATCH 1/7] ecryptfs: streamline truncate_upper Christoph Hellwig
2026-04-07 14:02 ` [PATCH 2/7] ecryptfs: cleanup ecryptfs_setattr Christoph Hellwig
2026-04-07 14:02 ` [PATCH 3/7] ecryptfs: use ZERO_PAGE instead of allocating zeroed memory in truncate_upper Christoph Hellwig
2026-04-07 14:02 ` [PATCH 4/7] ecryptfs: combine the two ATTR_SIZE blocks in ecryptfs_setattr Christoph Hellwig
2026-04-07 14:02 ` [PATCH 5/7] ecryptfs: sanitize struct iattr handling in truncate_upper Christoph Hellwig
2026-04-07 14:02 ` [PATCH 6/7] ecryptfs: merge ecryptfs_inode_newsize_ok into truncate_upper Christoph Hellwig
2026-04-07 14:02 ` [PATCH 7/7] ecryptfs: call notify_change from truncate_upper Christoph Hellwig
2026-04-07 14:50 ` cleanup truncate handling in ecryptfs v2 Christoph Hellwig
2026-04-08 1:10 ` Tyler Hicks
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox