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 <linkinjeon@kernel.org>
This commit is contained in:
Namjae Jeon 2026-07-12 09:02:02 +09:00
parent cb946cd133
commit 99580a3862

View File

@ -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;
}