All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 1/4] fat: split fat_truncate_time() into separate functions
@ 2022-05-03 15:25 Chung-Chiang Cheng
  2022-05-03 15:25 ` [PATCH v6 2/4] fat: ignore ctime updates, and keep ctime identical to mtime in memory Chung-Chiang Cheng
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Chung-Chiang Cheng @ 2022-05-03 15:25 UTC (permalink / raw)
  To: hirofumi; +Cc: linux-fsdevel, shepjeng, kernel, Chung-Chiang Cheng

Separate fat_truncate_time() to each timestamps for later creation time
work.

This patch does not introduce any functional changes, it's merely
refactoring change.

Signed-off-by: Chung-Chiang Cheng <cccheng@synology.com>
---
 fs/fat/fat.h  |  6 +++++
 fs/fat/misc.c | 74 ++++++++++++++++++++++++++++++++-------------------
 2 files changed, 53 insertions(+), 27 deletions(-)

diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 02d4d4234956..6b04aa623b3b 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -446,6 +446,12 @@ extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec64 *ts,
 			      __le16 __time, __le16 __date, u8 time_cs);
 extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts,
 			      __le16 *time, __le16 *date, u8 *time_cs);
+extern struct timespec64 fat_truncate_atime(const struct msdos_sb_info *sbi,
+					    const struct timespec64 *ts);
+extern struct timespec64 fat_truncate_crtime(const struct msdos_sb_info *sbi,
+					     const struct timespec64 *ts);
+extern struct timespec64 fat_truncate_mtime(const struct msdos_sb_info *sbi,
+					    const struct timespec64 *ts);
 extern int fat_truncate_time(struct inode *inode, struct timespec64 *now,
 			     int flags);
 extern int fat_update_time(struct inode *inode, struct timespec64 *now,
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 91ca3c304211..63160e47be00 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -187,7 +187,7 @@ static long days_in_year[] = {
 	0,   0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
 };
 
-static inline int fat_tz_offset(struct msdos_sb_info *sbi)
+static inline int fat_tz_offset(const struct msdos_sb_info *sbi)
 {
 	return (sbi->options.tz_set ?
 	       -sbi->options.time_offset :
@@ -282,16 +282,49 @@ static inline struct timespec64 fat_timespec64_trunc_10ms(struct timespec64 ts)
 	return ts;
 }
 
+/*
+ * truncate atime to 24 hour granularity (00:00:00 in local timezone)
+ */
+struct timespec64 fat_truncate_atime(const struct msdos_sb_info *sbi,
+				     const struct timespec64 *ts)
+{
+	/* to localtime */
+	time64_t seconds = ts->tv_sec - fat_tz_offset(sbi);
+	s32 remainder;
+
+	div_s64_rem(seconds, SECS_PER_DAY, &remainder);
+	/* to day boundary, and back to unix time */
+	seconds = seconds + fat_tz_offset(sbi) - remainder;
+
+	return (struct timespec64){ seconds, 0 };
+}
+
+/*
+ * truncate creation time with appropriate granularity:
+ *   msdos - 2 seconds
+ *   vfat  - 10 milliseconds
+ */
+struct timespec64 fat_truncate_crtime(const struct msdos_sb_info *sbi,
+				      const struct timespec64 *ts)
+{
+	if (sbi->options.isvfat)
+		return fat_timespec64_trunc_10ms(*ts);
+	else
+		return fat_timespec64_trunc_2secs(*ts);
+}
+
+/*
+ * truncate mtime to 2 second granularity
+ */
+struct timespec64 fat_truncate_mtime(const struct msdos_sb_info *sbi,
+				     const struct timespec64 *ts)
+{
+	return fat_timespec64_trunc_2secs(*ts);
+}
+
 /*
  * truncate the various times with appropriate granularity:
- *   root inode:
- *     all times always 0
- *   all other inodes:
- *     mtime - 2 seconds
- *     ctime
- *       msdos - 2 seconds
- *       vfat  - 10 milliseconds
- *     atime - 24 hours (00:00:00 in local timezone)
+ *   all times in root node are always 0
  */
 int fat_truncate_time(struct inode *inode, struct timespec64 *now, int flags)
 {
@@ -306,25 +339,12 @@ int fat_truncate_time(struct inode *inode, struct timespec64 *now, int flags)
 		ts = current_time(inode);
 	}
 
-	if (flags & S_ATIME) {
-		/* to localtime */
-		time64_t seconds = now->tv_sec - fat_tz_offset(sbi);
-		s32 remainder;
-
-		div_s64_rem(seconds, SECS_PER_DAY, &remainder);
-		/* to day boundary, and back to unix time */
-		seconds = seconds + fat_tz_offset(sbi) - remainder;
-
-		inode->i_atime = (struct timespec64){ seconds, 0 };
-	}
-	if (flags & S_CTIME) {
-		if (sbi->options.isvfat)
-			inode->i_ctime = fat_timespec64_trunc_10ms(*now);
-		else
-			inode->i_ctime = fat_timespec64_trunc_2secs(*now);
-	}
+	if (flags & S_ATIME)
+		inode->i_atime = fat_truncate_atime(sbi, now);
+	if (flags & S_CTIME)
+		inode->i_ctime = fat_truncate_crtime(sbi, now);
 	if (flags & S_MTIME)
-		inode->i_mtime = fat_timespec64_trunc_2secs(*now);
+		inode->i_mtime = fat_truncate_mtime(sbi, now);
 
 	return 0;
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 2/4] fat: ignore ctime updates, and keep ctime identical to mtime in memory
  2022-05-03 15:25 [PATCH v6 1/4] fat: split fat_truncate_time() into separate functions Chung-Chiang Cheng
@ 2022-05-03 15:25 ` Chung-Chiang Cheng
  2022-05-15 14:00   ` OGAWA Hirofumi
  2022-05-03 15:25 ` [PATCH v6 3/4] fat: report creation time in statx Chung-Chiang Cheng
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Chung-Chiang Cheng @ 2022-05-03 15:25 UTC (permalink / raw)
  To: hirofumi; +Cc: linux-fsdevel, shepjeng, kernel, Chung-Chiang Cheng

FAT supports creation time but not change time, and there was no
corresponding timestamp for creation time in previous VFS. The
original implementation took the compromise of saving the in-memory
change time into the on-disk creation time field, but this would lead
to compatibility issues with non-linux systems.

To address this issue, this patch changes the behavior of ctime. It
will no longer be loaded and stored from the creation time on disk.
Instead of that, it'll be consistent with the in-memory mtime and share
the same on-disk field. All updates to mtime will also be applied to
ctime in memory, while all updates to ctime will be ignored.

Signed-off-by: Chung-Chiang Cheng <cccheng@synology.com>
---
 fs/fat/inode.c | 11 ++++-------
 fs/fat/misc.c  |  9 ++++++---
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index bf6051bdf1d1..16d5a52116d3 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -567,12 +567,11 @@ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
 			   & ~((loff_t)sbi->cluster_size - 1)) >> 9;
 
 	fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0);
-	if (sbi->options.isvfat) {
-		fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime,
-				  de->cdate, de->ctime_cs);
+	inode->i_ctime = inode->i_mtime;
+	if (sbi->options.isvfat)
 		fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0);
-	} else
-		fat_truncate_time(inode, &inode->i_mtime, S_ATIME|S_CTIME);
+	else
+		inode->i_atime = fat_truncate_atime(sbi, &inode->i_mtime);
 
 	return 0;
 }
@@ -888,8 +887,6 @@ static int __fat_write_inode(struct inode *inode, int wait)
 			  &raw_entry->date, NULL);
 	if (sbi->options.isvfat) {
 		__le16 atime;
-		fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime,
-				  &raw_entry->cdate, &raw_entry->ctime_cs);
 		fat_time_unix2fat(sbi, &inode->i_atime, &atime,
 				  &raw_entry->adate, NULL);
 	}
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 63160e47be00..85bb9dc3af2d 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -341,10 +341,13 @@ int fat_truncate_time(struct inode *inode, struct timespec64 *now, int flags)
 
 	if (flags & S_ATIME)
 		inode->i_atime = fat_truncate_atime(sbi, now);
-	if (flags & S_CTIME)
-		inode->i_ctime = fat_truncate_crtime(sbi, now);
+	/*
+	 * ctime and mtime share the same on-disk field, and should be
+	 * identical in memory. all mtime updates will be applied to ctime,
+	 * but ctime updates are ignored.
+	 */
 	if (flags & S_MTIME)
-		inode->i_mtime = fat_truncate_mtime(sbi, now);
+		inode->i_mtime = inode->i_ctime = fat_truncate_mtime(sbi, now);
 
 	return 0;
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 3/4] fat: report creation time in statx
  2022-05-03 15:25 [PATCH v6 1/4] fat: split fat_truncate_time() into separate functions Chung-Chiang Cheng
  2022-05-03 15:25 ` [PATCH v6 2/4] fat: ignore ctime updates, and keep ctime identical to mtime in memory Chung-Chiang Cheng
@ 2022-05-03 15:25 ` Chung-Chiang Cheng
  2022-05-15 14:00   ` OGAWA Hirofumi
  2022-05-03 15:25 ` [PATCH v6 4/4] fat: remove time truncations in vfat_create/vfat_mkdir Chung-Chiang Cheng
  2022-05-15 13:59 ` [PATCH v6 1/4] fat: split fat_truncate_time() into separate functions OGAWA Hirofumi
  3 siblings, 1 reply; 8+ messages in thread
From: Chung-Chiang Cheng @ 2022-05-03 15:25 UTC (permalink / raw)
  To: hirofumi; +Cc: linux-fsdevel, shepjeng, kernel, Chung-Chiang Cheng

creation time is no longer mixed with change time. Add an in-memory
field for it, and report it in statx if supported.

Signed-off-by: Chung-Chiang Cheng <cccheng@synology.com>
---
 fs/fat/fat.h   |  1 +
 fs/fat/file.c  | 14 +++++++++++---
 fs/fat/inode.c | 10 ++++++++--
 3 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 6b04aa623b3b..f3bbf17ee352 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -126,6 +126,7 @@ struct msdos_inode_info {
 	struct hlist_node i_fat_hash;	/* hash by i_location */
 	struct hlist_node i_dir_hash;	/* hash by i_logstart */
 	struct rw_semaphore truncate_lock; /* protect bmap against truncate */
+	struct timespec64 i_crtime;	/* File creation (birth) time */
 	struct inode vfs_inode;
 };
 
diff --git a/fs/fat/file.c b/fs/fat/file.c
index a5a309fcc7fa..8f5218450a3a 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -399,13 +399,21 @@ int fat_getattr(struct user_namespace *mnt_userns, const struct path *path,
 		struct kstat *stat, u32 request_mask, unsigned int flags)
 {
 	struct inode *inode = d_inode(path->dentry);
+	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+
 	generic_fillattr(mnt_userns, inode, stat);
-	stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size;
+	stat->blksize = sbi->cluster_size;
 
-	if (MSDOS_SB(inode->i_sb)->options.nfs == FAT_NFS_NOSTALE_RO) {
+	if (sbi->options.nfs == FAT_NFS_NOSTALE_RO) {
 		/* Use i_pos for ino. This is used as fileid of nfs. */
-		stat->ino = fat_i_pos_read(MSDOS_SB(inode->i_sb), inode);
+		stat->ino = fat_i_pos_read(sbi, inode);
 	}
+
+	if (sbi->options.isvfat && request_mask & STATX_BTIME) {
+		stat->result_mask |= STATX_BTIME;
+		stat->btime = MSDOS_I(inode)->i_crtime;
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(fat_getattr);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 16d5a52116d3..2472a357198a 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -568,9 +568,11 @@ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
 
 	fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0);
 	inode->i_ctime = inode->i_mtime;
-	if (sbi->options.isvfat)
+	if (sbi->options.isvfat) {
 		fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0);
-	else
+		fat_time_fat2unix(sbi, &MSDOS_I(inode)->i_crtime, de->ctime,
+				  de->cdate, de->ctime_cs);
+	} else
 		inode->i_atime = fat_truncate_atime(sbi, &inode->i_mtime);
 
 	return 0;
@@ -756,6 +758,8 @@ static struct inode *fat_alloc_inode(struct super_block *sb)
 	ei->i_logstart = 0;
 	ei->i_attrs = 0;
 	ei->i_pos = 0;
+	ei->i_crtime.tv_sec = 0;
+	ei->i_crtime.tv_nsec = 0;
 
 	return &ei->vfs_inode;
 }
@@ -889,6 +893,8 @@ static int __fat_write_inode(struct inode *inode, int wait)
 		__le16 atime;
 		fat_time_unix2fat(sbi, &inode->i_atime, &atime,
 				  &raw_entry->adate, NULL);
+		fat_time_unix2fat(sbi, &MSDOS_I(inode)->i_crtime, &raw_entry->ctime,
+				  &raw_entry->cdate, &raw_entry->ctime_cs);
 	}
 	spin_unlock(&sbi->inode_hash_lock);
 	mark_buffer_dirty(bh);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 4/4] fat: remove time truncations in vfat_create/vfat_mkdir
  2022-05-03 15:25 [PATCH v6 1/4] fat: split fat_truncate_time() into separate functions Chung-Chiang Cheng
  2022-05-03 15:25 ` [PATCH v6 2/4] fat: ignore ctime updates, and keep ctime identical to mtime in memory Chung-Chiang Cheng
  2022-05-03 15:25 ` [PATCH v6 3/4] fat: report creation time in statx Chung-Chiang Cheng
@ 2022-05-03 15:25 ` Chung-Chiang Cheng
  2022-05-15 14:00   ` OGAWA Hirofumi
  2022-05-15 13:59 ` [PATCH v6 1/4] fat: split fat_truncate_time() into separate functions OGAWA Hirofumi
  3 siblings, 1 reply; 8+ messages in thread
From: Chung-Chiang Cheng @ 2022-05-03 15:25 UTC (permalink / raw)
  To: hirofumi; +Cc: linux-fsdevel, shepjeng, kernel, Chung-Chiang Cheng

All the timestamps in vfat_create() and vfat_mkdir() come from
fat_time_fat2unix() which ensures time granularity. We don't need to
truncate them to fit FAT's format.

Moreover, fat_truncate_crtime() and fat_timespec64_trunc_10ms() are
also removed because there is no caller anymore.

Signed-off-by: Chung-Chiang Cheng <cccheng@synology.com>
---
 fs/fat/fat.h        |  2 --
 fs/fat/misc.c       | 21 ---------------------
 fs/fat/namei_vfat.c |  4 ----
 3 files changed, 27 deletions(-)

diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index f3bbf17ee352..47b90deef284 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -449,8 +449,6 @@ extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts,
 			      __le16 *time, __le16 *date, u8 *time_cs);
 extern struct timespec64 fat_truncate_atime(const struct msdos_sb_info *sbi,
 					    const struct timespec64 *ts);
-extern struct timespec64 fat_truncate_crtime(const struct msdos_sb_info *sbi,
-					     const struct timespec64 *ts);
 extern struct timespec64 fat_truncate_mtime(const struct msdos_sb_info *sbi,
 					    const struct timespec64 *ts);
 extern int fat_truncate_time(struct inode *inode, struct timespec64 *now,
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 85bb9dc3af2d..010865dfc46b 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -275,13 +275,6 @@ static inline struct timespec64 fat_timespec64_trunc_2secs(struct timespec64 ts)
 	return (struct timespec64){ ts.tv_sec & ~1ULL, 0 };
 }
 
-static inline struct timespec64 fat_timespec64_trunc_10ms(struct timespec64 ts)
-{
-	if (ts.tv_nsec)
-		ts.tv_nsec -= ts.tv_nsec % 10000000UL;
-	return ts;
-}
-
 /*
  * truncate atime to 24 hour granularity (00:00:00 in local timezone)
  */
@@ -299,20 +292,6 @@ struct timespec64 fat_truncate_atime(const struct msdos_sb_info *sbi,
 	return (struct timespec64){ seconds, 0 };
 }
 
-/*
- * truncate creation time with appropriate granularity:
- *   msdos - 2 seconds
- *   vfat  - 10 milliseconds
- */
-struct timespec64 fat_truncate_crtime(const struct msdos_sb_info *sbi,
-				      const struct timespec64 *ts)
-{
-	if (sbi->options.isvfat)
-		return fat_timespec64_trunc_10ms(*ts);
-	else
-		return fat_timespec64_trunc_2secs(*ts);
-}
-
 /*
  * truncate mtime to 2 second granularity
  */
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index 5369d82e0bfb..c573314806cf 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -780,8 +780,6 @@ static int vfat_create(struct user_namespace *mnt_userns, struct inode *dir,
 		goto out;
 	}
 	inode_inc_iversion(inode);
-	fat_truncate_time(inode, &ts, S_ATIME|S_CTIME|S_MTIME);
-	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
 	d_instantiate(dentry, inode);
 out:
@@ -878,8 +876,6 @@ static int vfat_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 	}
 	inode_inc_iversion(inode);
 	set_nlink(inode, 2);
-	fat_truncate_time(inode, &ts, S_ATIME|S_CTIME|S_MTIME);
-	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
 	d_instantiate(dentry, inode);
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 1/4] fat: split fat_truncate_time() into separate functions
  2022-05-03 15:25 [PATCH v6 1/4] fat: split fat_truncate_time() into separate functions Chung-Chiang Cheng
                   ` (2 preceding siblings ...)
  2022-05-03 15:25 ` [PATCH v6 4/4] fat: remove time truncations in vfat_create/vfat_mkdir Chung-Chiang Cheng
@ 2022-05-15 13:59 ` OGAWA Hirofumi
  3 siblings, 0 replies; 8+ messages in thread
From: OGAWA Hirofumi @ 2022-05-15 13:59 UTC (permalink / raw)
  To: Chung-Chiang Cheng; +Cc: Andrew Morton, linux-fsdevel, shepjeng, kernel

Chung-Chiang Cheng <cccheng@synology.com> writes:

> Separate fat_truncate_time() to each timestamps for later creation time
> work.
>
> This patch does not introduce any functional changes, it's merely
> refactoring change.

It seems working as expected. However, this is more or less incompatible
change with previous behavior, so let's start testing.

Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

Thanks.

> Signed-off-by: Chung-Chiang Cheng <cccheng@synology.com>
> ---
>  fs/fat/fat.h  |  6 +++++
>  fs/fat/misc.c | 74 ++++++++++++++++++++++++++++++++-------------------
>  2 files changed, 53 insertions(+), 27 deletions(-)
>
> diff --git a/fs/fat/fat.h b/fs/fat/fat.h
> index 02d4d4234956..6b04aa623b3b 100644
> --- a/fs/fat/fat.h
> +++ b/fs/fat/fat.h
> @@ -446,6 +446,12 @@ extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec64 *ts,
>  			      __le16 __time, __le16 __date, u8 time_cs);
>  extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts,
>  			      __le16 *time, __le16 *date, u8 *time_cs);
> +extern struct timespec64 fat_truncate_atime(const struct msdos_sb_info *sbi,
> +					    const struct timespec64 *ts);
> +extern struct timespec64 fat_truncate_crtime(const struct msdos_sb_info *sbi,
> +					     const struct timespec64 *ts);
> +extern struct timespec64 fat_truncate_mtime(const struct msdos_sb_info *sbi,
> +					    const struct timespec64 *ts);
>  extern int fat_truncate_time(struct inode *inode, struct timespec64 *now,
>  			     int flags);
>  extern int fat_update_time(struct inode *inode, struct timespec64 *now,
> diff --git a/fs/fat/misc.c b/fs/fat/misc.c
> index 91ca3c304211..63160e47be00 100644
> --- a/fs/fat/misc.c
> +++ b/fs/fat/misc.c
> @@ -187,7 +187,7 @@ static long days_in_year[] = {
>  	0,   0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
>  };
>  
> -static inline int fat_tz_offset(struct msdos_sb_info *sbi)
> +static inline int fat_tz_offset(const struct msdos_sb_info *sbi)
>  {
>  	return (sbi->options.tz_set ?
>  	       -sbi->options.time_offset :
> @@ -282,16 +282,49 @@ static inline struct timespec64 fat_timespec64_trunc_10ms(struct timespec64 ts)
>  	return ts;
>  }
>  
> +/*
> + * truncate atime to 24 hour granularity (00:00:00 in local timezone)
> + */
> +struct timespec64 fat_truncate_atime(const struct msdos_sb_info *sbi,
> +				     const struct timespec64 *ts)
> +{
> +	/* to localtime */
> +	time64_t seconds = ts->tv_sec - fat_tz_offset(sbi);
> +	s32 remainder;
> +
> +	div_s64_rem(seconds, SECS_PER_DAY, &remainder);
> +	/* to day boundary, and back to unix time */
> +	seconds = seconds + fat_tz_offset(sbi) - remainder;
> +
> +	return (struct timespec64){ seconds, 0 };
> +}
> +
> +/*
> + * truncate creation time with appropriate granularity:
> + *   msdos - 2 seconds
> + *   vfat  - 10 milliseconds
> + */
> +struct timespec64 fat_truncate_crtime(const struct msdos_sb_info *sbi,
> +				      const struct timespec64 *ts)
> +{
> +	if (sbi->options.isvfat)
> +		return fat_timespec64_trunc_10ms(*ts);
> +	else
> +		return fat_timespec64_trunc_2secs(*ts);
> +}
> +
> +/*
> + * truncate mtime to 2 second granularity
> + */
> +struct timespec64 fat_truncate_mtime(const struct msdos_sb_info *sbi,
> +				     const struct timespec64 *ts)
> +{
> +	return fat_timespec64_trunc_2secs(*ts);
> +}
> +
>  /*
>   * truncate the various times with appropriate granularity:
> - *   root inode:
> - *     all times always 0
> - *   all other inodes:
> - *     mtime - 2 seconds
> - *     ctime
> - *       msdos - 2 seconds
> - *       vfat  - 10 milliseconds
> - *     atime - 24 hours (00:00:00 in local timezone)
> + *   all times in root node are always 0
>   */
>  int fat_truncate_time(struct inode *inode, struct timespec64 *now, int flags)
>  {
> @@ -306,25 +339,12 @@ int fat_truncate_time(struct inode *inode, struct timespec64 *now, int flags)
>  		ts = current_time(inode);
>  	}
>  
> -	if (flags & S_ATIME) {
> -		/* to localtime */
> -		time64_t seconds = now->tv_sec - fat_tz_offset(sbi);
> -		s32 remainder;
> -
> -		div_s64_rem(seconds, SECS_PER_DAY, &remainder);
> -		/* to day boundary, and back to unix time */
> -		seconds = seconds + fat_tz_offset(sbi) - remainder;
> -
> -		inode->i_atime = (struct timespec64){ seconds, 0 };
> -	}
> -	if (flags & S_CTIME) {
> -		if (sbi->options.isvfat)
> -			inode->i_ctime = fat_timespec64_trunc_10ms(*now);
> -		else
> -			inode->i_ctime = fat_timespec64_trunc_2secs(*now);
> -	}
> +	if (flags & S_ATIME)
> +		inode->i_atime = fat_truncate_atime(sbi, now);
> +	if (flags & S_CTIME)
> +		inode->i_ctime = fat_truncate_crtime(sbi, now);
>  	if (flags & S_MTIME)
> -		inode->i_mtime = fat_timespec64_trunc_2secs(*now);
> +		inode->i_mtime = fat_truncate_mtime(sbi, now);
>  
>  	return 0;
>  }

-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 2/4] fat: ignore ctime updates, and keep ctime identical to mtime in memory
  2022-05-03 15:25 ` [PATCH v6 2/4] fat: ignore ctime updates, and keep ctime identical to mtime in memory Chung-Chiang Cheng
@ 2022-05-15 14:00   ` OGAWA Hirofumi
  0 siblings, 0 replies; 8+ messages in thread
From: OGAWA Hirofumi @ 2022-05-15 14:00 UTC (permalink / raw)
  To: Chung-Chiang Cheng; +Cc: Andrew Morton, linux-fsdevel, shepjeng, kernel

Chung-Chiang Cheng <cccheng@synology.com> writes:

> FAT supports creation time but not change time, and there was no
> corresponding timestamp for creation time in previous VFS. The
> original implementation took the compromise of saving the in-memory
> change time into the on-disk creation time field, but this would lead
> to compatibility issues with non-linux systems.
>
> To address this issue, this patch changes the behavior of ctime. It
> will no longer be loaded and stored from the creation time on disk.
> Instead of that, it'll be consistent with the in-memory mtime and share
> the same on-disk field. All updates to mtime will also be applied to
> ctime in memory, while all updates to ctime will be ignored.

Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

Thanks.

> Signed-off-by: Chung-Chiang Cheng <cccheng@synology.com>
> ---
>  fs/fat/inode.c | 11 ++++-------
>  fs/fat/misc.c  |  9 ++++++---
>  2 files changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/fs/fat/inode.c b/fs/fat/inode.c
> index bf6051bdf1d1..16d5a52116d3 100644
> --- a/fs/fat/inode.c
> +++ b/fs/fat/inode.c
> @@ -567,12 +567,11 @@ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
>  			   & ~((loff_t)sbi->cluster_size - 1)) >> 9;
>  
>  	fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0);
> -	if (sbi->options.isvfat) {
> -		fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime,
> -				  de->cdate, de->ctime_cs);
> +	inode->i_ctime = inode->i_mtime;
> +	if (sbi->options.isvfat)
>  		fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0);
> -	} else
> -		fat_truncate_time(inode, &inode->i_mtime, S_ATIME|S_CTIME);
> +	else
> +		inode->i_atime = fat_truncate_atime(sbi, &inode->i_mtime);
>  
>  	return 0;
>  }
> @@ -888,8 +887,6 @@ static int __fat_write_inode(struct inode *inode, int wait)
>  			  &raw_entry->date, NULL);
>  	if (sbi->options.isvfat) {
>  		__le16 atime;
> -		fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime,
> -				  &raw_entry->cdate, &raw_entry->ctime_cs);
>  		fat_time_unix2fat(sbi, &inode->i_atime, &atime,
>  				  &raw_entry->adate, NULL);
>  	}
> diff --git a/fs/fat/misc.c b/fs/fat/misc.c
> index 63160e47be00..85bb9dc3af2d 100644
> --- a/fs/fat/misc.c
> +++ b/fs/fat/misc.c
> @@ -341,10 +341,13 @@ int fat_truncate_time(struct inode *inode, struct timespec64 *now, int flags)
>  
>  	if (flags & S_ATIME)
>  		inode->i_atime = fat_truncate_atime(sbi, now);
> -	if (flags & S_CTIME)
> -		inode->i_ctime = fat_truncate_crtime(sbi, now);
> +	/*
> +	 * ctime and mtime share the same on-disk field, and should be
> +	 * identical in memory. all mtime updates will be applied to ctime,
> +	 * but ctime updates are ignored.
> +	 */
>  	if (flags & S_MTIME)
> -		inode->i_mtime = fat_truncate_mtime(sbi, now);
> +		inode->i_mtime = inode->i_ctime = fat_truncate_mtime(sbi, now);
>  
>  	return 0;
>  }

-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 3/4] fat: report creation time in statx
  2022-05-03 15:25 ` [PATCH v6 3/4] fat: report creation time in statx Chung-Chiang Cheng
@ 2022-05-15 14:00   ` OGAWA Hirofumi
  0 siblings, 0 replies; 8+ messages in thread
From: OGAWA Hirofumi @ 2022-05-15 14:00 UTC (permalink / raw)
  To: Chung-Chiang Cheng; +Cc: Andrew Morton, linux-fsdevel, shepjeng, kernel

Chung-Chiang Cheng <cccheng@synology.com> writes:

> creation time is no longer mixed with change time. Add an in-memory
> field for it, and report it in statx if supported.

Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

Thanks.

> Signed-off-by: Chung-Chiang Cheng <cccheng@synology.com>
> ---
>  fs/fat/fat.h   |  1 +
>  fs/fat/file.c  | 14 +++++++++++---
>  fs/fat/inode.c | 10 ++++++++--
>  3 files changed, 20 insertions(+), 5 deletions(-)
>
> diff --git a/fs/fat/fat.h b/fs/fat/fat.h
> index 6b04aa623b3b..f3bbf17ee352 100644
> --- a/fs/fat/fat.h
> +++ b/fs/fat/fat.h
> @@ -126,6 +126,7 @@ struct msdos_inode_info {
>  	struct hlist_node i_fat_hash;	/* hash by i_location */
>  	struct hlist_node i_dir_hash;	/* hash by i_logstart */
>  	struct rw_semaphore truncate_lock; /* protect bmap against truncate */
> +	struct timespec64 i_crtime;	/* File creation (birth) time */
>  	struct inode vfs_inode;
>  };
>  
> diff --git a/fs/fat/file.c b/fs/fat/file.c
> index a5a309fcc7fa..8f5218450a3a 100644
> --- a/fs/fat/file.c
> +++ b/fs/fat/file.c
> @@ -399,13 +399,21 @@ int fat_getattr(struct user_namespace *mnt_userns, const struct path *path,
>  		struct kstat *stat, u32 request_mask, unsigned int flags)
>  {
>  	struct inode *inode = d_inode(path->dentry);
> +	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
> +
>  	generic_fillattr(mnt_userns, inode, stat);
> -	stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size;
> +	stat->blksize = sbi->cluster_size;
>  
> -	if (MSDOS_SB(inode->i_sb)->options.nfs == FAT_NFS_NOSTALE_RO) {
> +	if (sbi->options.nfs == FAT_NFS_NOSTALE_RO) {
>  		/* Use i_pos for ino. This is used as fileid of nfs. */
> -		stat->ino = fat_i_pos_read(MSDOS_SB(inode->i_sb), inode);
> +		stat->ino = fat_i_pos_read(sbi, inode);
>  	}
> +
> +	if (sbi->options.isvfat && request_mask & STATX_BTIME) {
> +		stat->result_mask |= STATX_BTIME;
> +		stat->btime = MSDOS_I(inode)->i_crtime;
> +	}
> +
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(fat_getattr);
> diff --git a/fs/fat/inode.c b/fs/fat/inode.c
> index 16d5a52116d3..2472a357198a 100644
> --- a/fs/fat/inode.c
> +++ b/fs/fat/inode.c
> @@ -568,9 +568,11 @@ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
>  
>  	fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0);
>  	inode->i_ctime = inode->i_mtime;
> -	if (sbi->options.isvfat)
> +	if (sbi->options.isvfat) {
>  		fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0);
> -	else
> +		fat_time_fat2unix(sbi, &MSDOS_I(inode)->i_crtime, de->ctime,
> +				  de->cdate, de->ctime_cs);
> +	} else
>  		inode->i_atime = fat_truncate_atime(sbi, &inode->i_mtime);
>  
>  	return 0;
> @@ -756,6 +758,8 @@ static struct inode *fat_alloc_inode(struct super_block *sb)
>  	ei->i_logstart = 0;
>  	ei->i_attrs = 0;
>  	ei->i_pos = 0;
> +	ei->i_crtime.tv_sec = 0;
> +	ei->i_crtime.tv_nsec = 0;
>  
>  	return &ei->vfs_inode;
>  }
> @@ -889,6 +893,8 @@ static int __fat_write_inode(struct inode *inode, int wait)
>  		__le16 atime;
>  		fat_time_unix2fat(sbi, &inode->i_atime, &atime,
>  				  &raw_entry->adate, NULL);
> +		fat_time_unix2fat(sbi, &MSDOS_I(inode)->i_crtime, &raw_entry->ctime,
> +				  &raw_entry->cdate, &raw_entry->ctime_cs);
>  	}
>  	spin_unlock(&sbi->inode_hash_lock);
>  	mark_buffer_dirty(bh);

-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 4/4] fat: remove time truncations in vfat_create/vfat_mkdir
  2022-05-03 15:25 ` [PATCH v6 4/4] fat: remove time truncations in vfat_create/vfat_mkdir Chung-Chiang Cheng
@ 2022-05-15 14:00   ` OGAWA Hirofumi
  0 siblings, 0 replies; 8+ messages in thread
From: OGAWA Hirofumi @ 2022-05-15 14:00 UTC (permalink / raw)
  To: Chung-Chiang Cheng; +Cc: Andrew Morton, linux-fsdevel, shepjeng, kernel

Chung-Chiang Cheng <cccheng@synology.com> writes:

> All the timestamps in vfat_create() and vfat_mkdir() come from
> fat_time_fat2unix() which ensures time granularity. We don't need to
> truncate them to fit FAT's format.
>
> Moreover, fat_truncate_crtime() and fat_timespec64_trunc_10ms() are
> also removed because there is no caller anymore.

Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

Thanks.

> Signed-off-by: Chung-Chiang Cheng <cccheng@synology.com>
> ---
>  fs/fat/fat.h        |  2 --
>  fs/fat/misc.c       | 21 ---------------------
>  fs/fat/namei_vfat.c |  4 ----
>  3 files changed, 27 deletions(-)
>
> diff --git a/fs/fat/fat.h b/fs/fat/fat.h
> index f3bbf17ee352..47b90deef284 100644
> --- a/fs/fat/fat.h
> +++ b/fs/fat/fat.h
> @@ -449,8 +449,6 @@ extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts,
>  			      __le16 *time, __le16 *date, u8 *time_cs);
>  extern struct timespec64 fat_truncate_atime(const struct msdos_sb_info *sbi,
>  					    const struct timespec64 *ts);
> -extern struct timespec64 fat_truncate_crtime(const struct msdos_sb_info *sbi,
> -					     const struct timespec64 *ts);
>  extern struct timespec64 fat_truncate_mtime(const struct msdos_sb_info *sbi,
>  					    const struct timespec64 *ts);
>  extern int fat_truncate_time(struct inode *inode, struct timespec64 *now,
> diff --git a/fs/fat/misc.c b/fs/fat/misc.c
> index 85bb9dc3af2d..010865dfc46b 100644
> --- a/fs/fat/misc.c
> +++ b/fs/fat/misc.c
> @@ -275,13 +275,6 @@ static inline struct timespec64 fat_timespec64_trunc_2secs(struct timespec64 ts)
>  	return (struct timespec64){ ts.tv_sec & ~1ULL, 0 };
>  }
>  
> -static inline struct timespec64 fat_timespec64_trunc_10ms(struct timespec64 ts)
> -{
> -	if (ts.tv_nsec)
> -		ts.tv_nsec -= ts.tv_nsec % 10000000UL;
> -	return ts;
> -}
> -
>  /*
>   * truncate atime to 24 hour granularity (00:00:00 in local timezone)
>   */
> @@ -299,20 +292,6 @@ struct timespec64 fat_truncate_atime(const struct msdos_sb_info *sbi,
>  	return (struct timespec64){ seconds, 0 };
>  }
>  
> -/*
> - * truncate creation time with appropriate granularity:
> - *   msdos - 2 seconds
> - *   vfat  - 10 milliseconds
> - */
> -struct timespec64 fat_truncate_crtime(const struct msdos_sb_info *sbi,
> -				      const struct timespec64 *ts)
> -{
> -	if (sbi->options.isvfat)
> -		return fat_timespec64_trunc_10ms(*ts);
> -	else
> -		return fat_timespec64_trunc_2secs(*ts);
> -}
> -
>  /*
>   * truncate mtime to 2 second granularity
>   */
> diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
> index 5369d82e0bfb..c573314806cf 100644
> --- a/fs/fat/namei_vfat.c
> +++ b/fs/fat/namei_vfat.c
> @@ -780,8 +780,6 @@ static int vfat_create(struct user_namespace *mnt_userns, struct inode *dir,
>  		goto out;
>  	}
>  	inode_inc_iversion(inode);
> -	fat_truncate_time(inode, &ts, S_ATIME|S_CTIME|S_MTIME);
> -	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
>  
>  	d_instantiate(dentry, inode);
>  out:
> @@ -878,8 +876,6 @@ static int vfat_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
>  	}
>  	inode_inc_iversion(inode);
>  	set_nlink(inode, 2);
> -	fat_truncate_time(inode, &ts, S_ATIME|S_CTIME|S_MTIME);
> -	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
>  
>  	d_instantiate(dentry, inode);

-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2022-05-15 14:00 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-03 15:25 [PATCH v6 1/4] fat: split fat_truncate_time() into separate functions Chung-Chiang Cheng
2022-05-03 15:25 ` [PATCH v6 2/4] fat: ignore ctime updates, and keep ctime identical to mtime in memory Chung-Chiang Cheng
2022-05-15 14:00   ` OGAWA Hirofumi
2022-05-03 15:25 ` [PATCH v6 3/4] fat: report creation time in statx Chung-Chiang Cheng
2022-05-15 14:00   ` OGAWA Hirofumi
2022-05-03 15:25 ` [PATCH v6 4/4] fat: remove time truncations in vfat_create/vfat_mkdir Chung-Chiang Cheng
2022-05-15 14:00   ` OGAWA Hirofumi
2022-05-15 13:59 ` [PATCH v6 1/4] fat: split fat_truncate_time() into separate functions OGAWA Hirofumi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.