ksmbd: preserve open change time across rename

inode ctime is updated when a file is renamed. ksmbd returned that
ctime directly as SMB2 ChangeTime for handle-based query information.
This makes ChangeTime change after a rename through an already-open
handle, while Windows keeps the handle's ChangeTime stable for this
case.

Store the SMB ChangeTime in struct ksmbd_file when the handle is opened
and use that value for create, close, and handle-based query information
responses.  If a client explicitly sets FILE_BASIC_INFORMATION
ChangeTime, update the stored value as well.

This fixes smbtorture smb2.rename.simple_modtime, which expects
ChangeTime and LastWriteTime to remain unchanged after renaming an
already-open file.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
Namjae Jeon 2026-06-21 19:36:40 +09:00 committed by Steve French
parent 16c3064970
commit 24dcee8305
2 changed files with 11 additions and 13 deletions

View File

@ -3783,6 +3783,7 @@ int smb2_open(struct ksmbd_work *work)
fp->create_time = ksmbd_UnixTimeToNT(stat.btime);
else
fp->create_time = ksmbd_UnixTimeToNT(stat.ctime);
fp->change_time = ksmbd_UnixTimeToNT(stat.ctime);
if (req->FileAttributes || fp->f_ci->m_fattr == 0)
fp->f_ci->m_fattr =
cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes)));
@ -3832,8 +3833,7 @@ int smb2_open(struct ksmbd_work *work)
rsp->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
rsp->LastWriteTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.ctime);
rsp->ChangeTime = cpu_to_le64(time);
rsp->ChangeTime = cpu_to_le64(fp->change_time);
rsp->AllocationSize = S_ISDIR(stat.mode) ? 0 :
cpu_to_le64(stat.blocks << 9);
rsp->EndofFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
@ -5102,8 +5102,7 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
basic_info->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
basic_info->LastWriteTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.ctime);
basic_info->ChangeTime = cpu_to_le64(time);
basic_info->ChangeTime = cpu_to_le64(fp->change_time);
basic_info->Attributes = fp->f_ci->m_fattr;
basic_info->Pad = 0;
rsp->OutputBufferLength =
@ -5205,8 +5204,7 @@ static int get_file_all_info(struct ksmbd_work *work,
file_info->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
file_info->LastWriteTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.ctime);
file_info->ChangeTime = cpu_to_le64(time);
file_info->ChangeTime = cpu_to_le64(fp->change_time);
file_info->Attributes = fp->f_ci->m_fattr;
file_info->Pad1 = 0;
if (ksmbd_stream_fd(fp) == false) {
@ -5415,8 +5413,7 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
file_info->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
file_info->LastWriteTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.ctime);
file_info->ChangeTime = cpu_to_le64(time);
file_info->ChangeTime = cpu_to_le64(fp->change_time);
file_info->Attributes = fp->f_ci->m_fattr;
if (ksmbd_stream_fd(fp) == false) {
file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
@ -5547,8 +5544,7 @@ static int find_file_posix_info(struct smb2_query_info_rsp *rsp,
file_info->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
file_info->LastWriteTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.ctime);
file_info->ChangeTime = cpu_to_le64(time);
file_info->ChangeTime = cpu_to_le64(fp->change_time);
file_info->DosAttributes = fp->f_ci->m_fattr;
file_info->Inode = cpu_to_le64(stat.ino);
if (ksmbd_stream_fd(fp) == false) {
@ -6271,8 +6267,7 @@ int smb2_close(struct ksmbd_work *work)
rsp->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
rsp->LastWriteTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.ctime);
rsp->ChangeTime = cpu_to_le64(time);
rsp->ChangeTime = cpu_to_le64(fp->change_time);
ksmbd_fd_put(work, fp);
} else {
rsp->Flags = 0;
@ -6485,9 +6480,11 @@ static int set_file_basic_info(struct ksmbd_file *fp,
attrs.ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);
}
if (file_info->ChangeTime)
if (file_info->ChangeTime) {
fp->change_time = le64_to_cpu(file_info->ChangeTime);
inode_set_ctime_to_ts(inode,
ksmbd_NTtimeToUnix(file_info->ChangeTime));
}
if (file_info->LastWriteTime) {
attrs.ia_mtime = ksmbd_NTtimeToUnix(file_info->LastWriteTime);

View File

@ -97,6 +97,7 @@ struct ksmbd_file {
__le32 coption;
__le32 cdoption;
__u64 create_time;
__u64 change_time;
__u64 itime;
bool is_nt_open;