[PATCH] jffs2: Fix truncate never update m/ctime
Jubin Zhong
zhongjubin at huawei.com
Tue Nov 16 07:37:16 PST 2021
From: zhongjubin <zhongjubin at huawei.com>
Syscall truncate() never updates m/ctime in jffs2 even if the file
size is changed. This is incorrect according to man file:
truncate (2):
If the size changed, then the st_ctime and st_mtime fields
(respectively, time of last status change and time of last
modification; see stat(2)) for the file are updated, and the
set-user-ID and set-group-ID mode bits may be cleared.
This is because truncate() will not set ATTR_CTIME and ATTR_MTIME even
when file size is changed. Fix this special case just like what other
filesystems do.
Test Steps:
1. cd /path/to/mnt/point
2. dd if=/dev/zero of=test bs=1M count=1
3. stat test
4. /bin/my_truncate -s 1024 test
5. stat test
6. compare m/ctime of step 5 with step 3
Program source:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char **argv)
{
int ret;
char file_name[128] = {0};
if (argc < 4 || argv == NULL || argv[1] == NULL ||
argv[2] == NULL || argv[3] == NULL) {
return -1;
}
if (strcmp(argv[1], "-s")) {
return -1;
}
if (realpath(argv[3], file_name) == NULL) {
printf("truncate: input file name %s err.\n", argv[3]);
return -1;
}
off_t size = (off_t)strtol(argv[2], 0, 0);
ret = truncate(file_name, size);
if (ret) {
printf("truncate return err %d\n", ret);
}
return ret;
}
Signed-off-by: zhongjubin <zhongjubin at huawei.com>
----
v1:
https://lore.kernel.org/all/1636974018-31285-1-git-send-email-zhongjubin@huawei.com/
I considered fixing this problem in vfs_truncate(), but it is
suggested to implement the proper semantics in jffs's ->setattr.
---
fs/jffs2/fs.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 2ac410477c4f..181f053d072b 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -114,8 +114,18 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime));
- ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime));
- ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime));
+ /*
+ * Special case for truncate() where we should update the times despite not having
+ * ATTR_CTIME and ATTR_MTIME set.
+ */
+ if ((ivalid & ATTR_SIZE) && (iattr->ia_size != inode->i_size) &&
+ !(ivalid & (ATTR_CTIME | ATTR_MTIME))) {
+ ri->mtime = cpu_to_je32(I_SEC(iattr->ia_mtime));
+ ri->ctime = cpu_to_je32(I_SEC(iattr->ia_ctime));
+ } else {
+ ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime));
+ ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime));
+ }
ri->offset = cpu_to_je32(0);
ri->csize = ri->dsize = cpu_to_je32(mdatalen);
--
2.12.3
More information about the linux-mtd
mailing list