From 99580a386220b8b0f156738c4bf195da53d3ba85 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 12 Jul 2026 09:02:02 +0900 Subject: [PATCH] ksmbd: send lease breaks for handle-caching share conflicts RH leases map to SMB2_OPLOCK_LEVEL_II because they do not include write caching. smb_grant_oplock() only sent break notifications for previous BATCH or EXCLUSIVE levels, so a conflicting open could skip the lease break when the existing lease was RH. That leaves the opener to fail or complete without the expected pending lease break sequence, instead of first asking the holder to drop handle caching. Treat share-mode conflicts against leases with HANDLE_CACHING as needing a break even when the mapped oplock level is LEVEL_II. This lets the server send the RH -> R lease break and wait for the normal break handling before continuing the conflicting open. Signed-off-by: Namjae Jeon --- fs/smb/server/oplock.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c index 0fe82e740ffb..5b46af94cd82 100644 --- a/fs/smb/server/oplock.c +++ b/fs/smb/server/oplock.c @@ -1454,6 +1454,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid, bool prev_durable_detached = false; unsigned long long prev_fid = KSMBD_NO_FID; bool new_lease = false; + bool break_needed; __le32 prev_op_state = 0; /* Only v2 leases handle the directory */ @@ -1532,8 +1533,11 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid, goto err_out; } - if (prev_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH && - prev_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) { + break_needed = prev_opinfo->level == SMB2_OPLOCK_LEVEL_BATCH || + prev_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE || + (share_ret < 0 && prev_op_has_lease && + (prev_op_state & SMB2_LEASE_HANDLE_CACHING_LE)); + if (!break_needed) { opinfo_put(prev_opinfo); goto op_break_not_needed; }