summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorNamjae Jeon <linkinjeon@kernel.org>2026-07-01 23:59:29 +0900
committerSteve French <stfrench@microsoft.com>2026-07-06 07:55:41 -0500
commita0b765030f6ba37aaac59618d4f39dac18d42757 (patch)
treed833cd7edce58cebfee36471c1c2d16ae3d10b9a /fs
parent4b706360ffb7e459cb3d3edae30b06a584f6eddd (diff)
downloadlinux-next-a0b765030f6ba37aaac59618d4f39dac18d42757.tar.gz
linux-next-a0b765030f6ba37aaac59618d4f39dac18d42757.zip
ksmbd: coalesce sub-15ms write time updates on close
Windows reports automatic write-time updates with a resolution of roughly 15 milliseconds. If a file is written and closed within that interval, a close response requesting full information can report the write time from the open rather than the filesystem's finer-grained mtime update. ksmbd currently converts the filesystem mtime directly in SMB2 CLOSE, so even a sub-millisecond write is visible to the client. This makes smb2.timestamp_resolution.resolution1 fail because the immediate write changes LastWriteTime. Save the write time returned by SMB2 CREATE in the file handle. When CLOSE requests post-query attributes, coalesce a positive mtime change smaller than 15 milliseconds to that saved value. Larger changes remain visible, including the test's write after a 20 millisecond delay. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/smb/server/smb2pdu.c7
-rw-r--r--fs/smb/server/vfs_cache.h1
2 files changed, 8 insertions, 0 deletions
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 9c00f944fa3b..b1204d1d3cdd 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -61,6 +61,9 @@ static void __wbuf(struct ksmbd_work *work, void **req, void **rsp)
(FILE_ATTRIBUTE_MASK & ~(FILE_ATTRIBUTE_INTEGRITY_STREAM | \
FILE_ATTRIBUTE_NO_SCRUB_DATA))
+/* Windows reports automatic write-time updates at roughly 15 ms resolution. */
+#define KSMBD_WRITE_TIME_RESOLUTION (15ULL * 10000)
+
/**
* check_session_id() - check for valid session id in smb header
* @conn: connection instance
@@ -3985,6 +3988,7 @@ reconnected_fp:
time = ksmbd_UnixTimeToNT(stat.atime);
rsp->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
+ fp->open_mtime = time;
rsp->LastWriteTime = cpu_to_le64(time);
rsp->ChangeTime = cpu_to_le64(fp->change_time);
/*
@@ -6451,6 +6455,9 @@ int smb2_close(struct ksmbd_work *work)
time = ksmbd_UnixTimeToNT(stat.atime);
rsp->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
+ if (time > fp->open_mtime &&
+ time - fp->open_mtime < KSMBD_WRITE_TIME_RESOLUTION)
+ time = fp->open_mtime;
rsp->LastWriteTime = cpu_to_le64(time);
rsp->ChangeTime = cpu_to_le64(fp->change_time);
ksmbd_fd_put(work, fp);
diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
index 287f3e675cd3..b9e27307a26c 100644
--- a/fs/smb/server/vfs_cache.h
+++ b/fs/smb/server/vfs_cache.h
@@ -105,6 +105,7 @@ struct ksmbd_file {
__u64 change_time;
__u64 allocation_size;
__u64 itime;
+ __u64 open_mtime;
bool is_nt_open;
bool attrib_only;