All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 1/3] fat: split fat_truncate_time() into separate functions
@ 2022-04-30  4:41 Chung-Chiang Cheng
  2022-04-30  4:41 ` [PATCH v5 2/3] fat: ignore ctime updates, and keep ctime identical to mtime in memory Chung-Chiang Cheng
  2022-04-30  4:41 ` [PATCH v5 3/3] fat: report creation time in statx Chung-Chiang Cheng
  0 siblings, 2 replies; 5+ messages in thread
From: Chung-Chiang Cheng @ 2022-04-30  4:41 UTC (permalink / raw)
  To: hirofumi; +Cc: linux-fsdevel, kernel, shepjeng, 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] 5+ messages in thread

* [PATCH v5 2/3] fat: ignore ctime updates, and keep ctime identical to mtime in memory
  2022-04-30  4:41 [PATCH v5 1/3] fat: split fat_truncate_time() into separate functions Chung-Chiang Cheng
@ 2022-04-30  4:41 ` Chung-Chiang Cheng
  2022-04-30  4:41 ` [PATCH v5 3/3] fat: report creation time in statx Chung-Chiang Cheng
  1 sibling, 0 replies; 5+ messages in thread
From: Chung-Chiang Cheng @ 2022-04-30  4:41 UTC (permalink / raw)
  To: hirofumi; +Cc: linux-fsdevel, kernel, shepjeng, 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] 5+ messages in thread

* [PATCH v5 3/3] fat: report creation time in statx
  2022-04-30  4:41 [PATCH v5 1/3] fat: split fat_truncate_time() into separate functions Chung-Chiang Cheng
  2022-04-30  4:41 ` [PATCH v5 2/3] fat: ignore ctime updates, and keep ctime identical to mtime in memory Chung-Chiang Cheng
@ 2022-04-30  4:41 ` Chung-Chiang Cheng
  2022-04-30  9:01   ` OGAWA Hirofumi
  1 sibling, 1 reply; 5+ messages in thread
From: Chung-Chiang Cheng @ 2022-04-30  4:41 UTC (permalink / raw)
  To: hirofumi; +Cc: linux-fsdevel, kernel, shepjeng, 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.

fat_truncate_crtime() is also removed. Because crtime comes from only
the following two cases and won't be changed afterward.

(1) vfat_lookup
(2) vfat_create/vfat_mkdir -> vfat_add_entry -> vfat_build_slots

They are all in {cdate:16, ctime:16, ctime_cs:8} format, which ensures
crtime will be kept at the correct granularity (10 ms). The remaining
timestamps may be copied from the vfs inode, so we need to truncate them
to fit FAT's format. But crtime doesn't need to do that.

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

diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 6b04aa623b3b..47b90deef284 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;
 };
 
@@ -448,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/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);
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 85bb9dc3af2d..3f3b47e48a1b 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -299,20 +299,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
  */
-- 
2.34.1


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

* Re: [PATCH v5 3/3] fat: report creation time in statx
  2022-04-30  4:41 ` [PATCH v5 3/3] fat: report creation time in statx Chung-Chiang Cheng
@ 2022-04-30  9:01   ` OGAWA Hirofumi
  2022-04-30 14:52     ` Chung-Chiang Cheng
  0 siblings, 1 reply; 5+ messages in thread
From: OGAWA Hirofumi @ 2022-04-30  9:01 UTC (permalink / raw)
  To: Chung-Chiang Cheng; +Cc: linux-fsdevel, kernel, shepjeng

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.
>
> fat_truncate_crtime() is also removed. Because crtime comes from only
> the following two cases and won't be changed afterward.
>
> (1) vfat_lookup
> (2) vfat_create/vfat_mkdir -> vfat_add_entry -> vfat_build_slots
>
> They are all in {cdate:16, ctime:16, ctime_cs:8} format, which ensures
> crtime will be kept at the correct granularity (10 ms). The remaining
> timestamps may be copied from the vfs inode, so we need to truncate them
> to fit FAT's format. But crtime doesn't need to do that.

Hm, maybe right.  I'm not checking fully though, then we can remove
fat_truncate_time() in vfat_create/mkdir()?

(Actually msdos too though, the state of timestamps for msdos is
strange, mean on-disk and in-core timestamps are not sync. So not
including for now)

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

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

* Re: [PATCH v5 3/3] fat: report creation time in statx
  2022-04-30  9:01   ` OGAWA Hirofumi
@ 2022-04-30 14:52     ` Chung-Chiang Cheng
  0 siblings, 0 replies; 5+ messages in thread
From: Chung-Chiang Cheng @ 2022-04-30 14:52 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: Chung-Chiang Cheng, linux-fsdevel, kernel

On Sat, Apr 30, 2022 at 5:01 PM OGAWA Hirofumi
<hirofumi@mail.parknet.co.jp> wrote:
> > They are all in {cdate:16, ctime:16, ctime_cs:8} format, which ensures
> > crtime will be kept at the correct granularity (10 ms). The remaining
> > timestamps may be copied from the vfs inode, so we need to truncate them
> > to fit FAT's format. But crtime doesn't need to do that.
>
> Hm, maybe right.  I'm not checking fully though, then we can remove
> fat_truncate_time() in vfat_create/mkdir()?
>
> (Actually msdos too though, the state of timestamps for msdos is
> strange, mean on-disk and in-core timestamps are not sync. So not
> including for now)

Thanks for your insight! Indeed all the time truncations in these two
functions can be removed, because all the timestamps come from
fat_time_fat2unix() which ensures the granularity.

I'll update this change in the last commit later if there's no additional
issues.

Thanks.

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

end of thread, other threads:[~2022-04-30 14:53 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-30  4:41 [PATCH v5 1/3] fat: split fat_truncate_time() into separate functions Chung-Chiang Cheng
2022-04-30  4:41 ` [PATCH v5 2/3] fat: ignore ctime updates, and keep ctime identical to mtime in memory Chung-Chiang Cheng
2022-04-30  4:41 ` [PATCH v5 3/3] fat: report creation time in statx Chung-Chiang Cheng
2022-04-30  9:01   ` OGAWA Hirofumi
2022-04-30 14:52     ` Chung-Chiang Cheng

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.