]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: coalesce sub-15ms write time updates on close
authorNamjae Jeon <linkinjeon@kernel.org>
Wed, 1 Jul 2026 14:59:29 +0000 (23:59 +0900)
committerSteve French <stfrench@microsoft.com>
Mon, 6 Jul 2026 12:55:41 +0000 (07:55 -0500)
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>
fs/smb/server/smb2pdu.c
fs/smb/server/vfs_cache.h

index 9c00f944fa3b51970c3d90be50a850c61c1edab8..b1204d1d3cddb6d03d71e2572a9483b30543fc02 100644 (file)
@@ -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);
index 287f3e675cd30ab3aca328822eea92c03f4d12cc..b9e27307a26c1530b1d89c79b69deddcf2df33d2 100644 (file)
@@ -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;