Re: [PATCH] fix smb client defer close causes file corruption
Enzo Matsumiya <[email protected]> Wed, 24 Jun 2026 01:19:25 -0300
| Newsgroups | gmane.linux.kernel,gmane.linux.kernel.cifs,gmane.network.samba.internals |
|---|---|
| Message-ID | <[email protected]> |
On 06/23, Steve French wrote: >Do you see different behavior of this to different servers (Samba, >Windows, ksmbd, Azure xSMB etc)? > >Disabling deferred close carries metadata integrity issues because it >will lead users to set actimeo (or acregmax) to higher values, and >disabling deferred close could significantly hurt performance for some >common workload patterns (open/write/close/open/read/close e.g.) > >Other narrower client fixes for this presumably could be done, e.g. >forcing close on the deferred close when rename a hardlink. That looks like a safe measure to have IMO. Cheers, Enzo >On Mon, Jun 22, 2026 at 4:40=E2=80=AFAM Chunjie Zhu <[email protected]= m> wrote: >> >> Test environment >> >> 4 hosts as smb client, 1 host as smb server >> smb client hosts, kernel 6.6.138 >> mount options, >> //10.70.48.15/xxx /run/xxx cifs rw,relatime,vers=3D3.0, >> cache=3Dloose,username=3Dxxx,domain=3Dxxx,uid=3D0,noforceuid, >> gid=3D0,noforcegid,addr=3D10.70.48.15,file_mode=3D0755, >> dir_mode=3D0755,soft,nounix,serverino,mapposix,reparse=3Dnfs, >> rsize=3D1048576,wsize=3D1048576,bsize=3D1048576,echo_interval=3D60, >> actimeo=3D0,closetimeo=3D1 >> >> Work around >> >> mount with cache=3Dnone or closetimeo=3D0 >> >> The Race Condition Flow >> >> Step 1: Host-01 closes file >> >> Host-01: >> file close (eeefe8d0.vhd) >> -> CIFS defers SMB2 CLOSE >> -> Handle H1 stored in deferred_closes list >> -> Lease L1 (RWH or RH) still active on server >> -> Entry: { path=3D=E2=80=9Ceeefe8d0.vhd=E2=80=9D, handle=3DH1, inode= =3DI1 } >> >> Step 2: Host-02 does hardlink and rename >> >> Host-02: >> hardlink(eeefe8d0.vhd, 0f11b74e.vhd) >> -> SMB2: Creates new name for same inode >> -> Server: inode I1 now has 2 names (link count =3D 2) >> -> Host-01 lease L1: NO BREAK (same inode, just added name) >> >> crate(eeefe8d0.vhd.new) >> -> Entry { path=3D"eeefe8d0.vhd.new", handle=3DH2, inode=3DI2 } >> >> rename(eeefe8d0.vhd.new, eeefe8d0.vhd) >> -> SMB2: Replaces =E2=80=9Ceeefe8d0.vhd=E2=80=9D name =E2=86=92 point= s to new inode I2 >> -> Server: old inode I1 now only accessible as =E2=80=9C0f11b74e.vhd= =E2=80=9D >> -> Server SHOULD send: Lease Break notification to H1 =E2=86=90 KEY! >> >> Step 3: Lease break delivery is not reliable >> >> strict locking off, level2 oplock >> >> Host-01: >> -> Lease break not received or processed >> -> H1 is in deferred_closes list (not "active") >> >> Result: Stale entry remains: >> { path=3D=E2=80=9Ceeefe8d0.vhd=E2=80=9D, handle=3DH1, inode=3DI1_O= LD } >> >> Host-02: >> -> Open 0f11b74e.vhd in readonly >> >> Result: >> { path=3D"0f11b74e.vhd", inode=3DI1_NEW } >> >> Step 4: Host-01 reopens file >> >> Host-01: >> file open (eeefe8d0.vhd) >> -> Kernel checks deferred_closes for =E2=80=9Ceeefe8d0.vhd=E2=80=9D >> -> Found H1! (matched by pathname string) >> -> REUSES H1 without checking >> -> close or reconnect, flush buffered writes >> slient corruption? >> >> Signed-off-by: Chunjie Zhu <[email protected]> >> --- >> fs/smb/client/fs_context.c | 8 ++++---- >> 1 file changed, 4 insertions(+), 4 deletions(-) >> >> diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c >> index 0812af001417..4ed33de0a00d 100644 >> --- a/fs/smb/client/fs_context.c >> +++ b/fs/smb/client/fs_context.c >> @@ -1300,11 +1300,11 @@ static int smb3_fs_context_parse_param(struct fs= _context *fc, >> ctx->acdirmax =3D ctx->acregmax =3D HZ * result.uint_32; >> break; >> case Opt_closetimeo: >> - if (result.uint_32 > SMB3_MAX_DCLOSETIMEO / HZ) { >> - cifs_errorf(fc, "closetimeo too large\n"); >> + if (result.uint_32 !=3D 0) { >> + cifs_errorf(fc, "closetimeo must be 0, deferred = close is disabled\n"); >> goto cifs_parse_mount_err; >> } >> - ctx->closetimeo =3D HZ * result.uint_32; >> + ctx->closetimeo =3D 0; >> break; >> case Opt_echo_interval: >> if (result.uint_32 < SMB_ECHO_INTERVAL_MIN || >> @@ -1795,7 +1795,7 @@ int smb3_init_fs_context(struct fs_context *fc) >> >> ctx->acregmax =3D CIFS_DEF_ACTIMEO; >> ctx->acdirmax =3D CIFS_DEF_ACTIMEO; >> - ctx->closetimeo =3D SMB3_DEF_DCLOSETIMEO; >> + ctx->closetimeo =3D 0; >> ctx->max_cached_dirs =3D MAX_CACHED_FIDS; >> /* Most clients set timeout to 0, allows server to use its defau= lt */ >> ctx->handle_timeout =3D 0; /* See MS-SMB2 spec section 2.2.14.2.= 12 */ >> -- >> 2.52.0 >> >> > > >--=20 >Thanks, > >Steve >