]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: do not wait for RH lease break ack on overwrite
authorNamjae Jeon <linkinjeon@kernel.org>
Thu, 18 Jun 2026 12:31:53 +0000 (21:31 +0900)
committerSteve French <stfrench@microsoft.com>
Tue, 23 Jun 2026 01:15:04 +0000 (20:15 -0500)
smb2.lease.breaking4 expects an overwrite against an RH lease to send
RH->NONE lease break notification but complete the triggering create
without waiting for the break ack.

Keep the lease in break-in-progress state until the client eventually
acknowledges the downgrade, but do not hold the overwrite request behind
that ack.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/oplock.c

index 608961c838c974f790f72455ece3fcc1d10d5f95..4d89fbb6c9c59526b49bdc8a022a7289e20f6352 100644 (file)
@@ -927,7 +927,7 @@ out:
  *
  * Return:     0 on success, otherwise error
  */
-static int smb2_lease_break_noti(struct oplock_info *opinfo)
+static int smb2_lease_break_noti(struct oplock_info *opinfo, bool wait_ack)
 {
        struct ksmbd_conn *conn;
        struct ksmbd_work *work;
@@ -964,7 +964,8 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
        if (opinfo->op_state == OPLOCK_ACK_WAIT) {
                INIT_WORK(&work->work, __smb2_lease_break_noti);
                ksmbd_queue_work(work);
-               wait_for_break_ack(opinfo);
+               if (wait_ack)
+                       wait_for_break_ack(opinfo);
        } else {
                __smb2_lease_break_noti(&work->work);
                if (opinfo->o_lease->new_state == SMB2_LEASE_NONE_LE) {
@@ -1006,6 +1007,7 @@ static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level,
        if (brk_opinfo->is_lease) {
                struct lease *lease = brk_opinfo->o_lease;
                bool open_trunc = brk_opinfo->open_trunc;
+               bool wait_ack;
 
                if (in_work && test_bit(0, &brk_opinfo->pending_break)) {
                        setup_async_work(in_work, NULL, NULL);
@@ -1058,14 +1060,19 @@ again:
                } else
                        atomic_dec(&brk_opinfo->breaking_cnt);
 
-               err = smb2_lease_break_noti(brk_opinfo);
+               wait_ack = !(open_trunc &&
+                            lease->state == (SMB2_LEASE_READ_CACHING_LE |
+                                             SMB2_LEASE_HANDLE_CACHING_LE));
+               err = smb2_lease_break_noti(brk_opinfo, wait_ack);
 
                ksmbd_debug(OPLOCK, "oplock granted = %d\n", brk_opinfo->level);
                if (brk_opinfo->op_state == OPLOCK_CLOSING)
                        err = -ENOENT;
 
-               wait_lease_breaking(brk_opinfo);
-               if (!err && lease_break_needed(brk_opinfo, req_op_level, open_trunc))
+               if (wait_ack)
+                       wait_lease_breaking(brk_opinfo);
+               if (wait_ack && !err &&
+                   lease_break_needed(brk_opinfo, req_op_level, open_trunc))
                        goto again;
 
                wake_up_oplock_break(brk_opinfo);