]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: route v2 lease breaks on the client lease channel
authorNamjae Jeon <linkinjeon@kernel.org>
Thu, 18 Jun 2026 12:33:40 +0000 (21:33 +0900)
committerSteve French <stfrench@microsoft.com>
Tue, 23 Jun 2026 01:15:04 +0000 (20:15 -0500)
v2 leases are scoped by ClientGuid.  When the same client uses multiple
connections, smbtorture expects lease break notifications to be sent on
the connection associated with the client lease table, not necessarily
on the connection that owns the individual open being broken.

Keep a referenced connection in the lease table and use it for v2 lease
break notifications while it is still active.  Fall back to the open's
connection if the table connection is being released.

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

index fe0bbb0e1c89eff22efaf0f160bd65f952280b5c..d936c338f7c7c9c35dabf019f182de6b3a1642af 100644 (file)
@@ -141,11 +141,21 @@ static struct lease_table *alloc_lease_table(struct oplock_info *opinfo)
 
        memcpy(lb->client_guid, opinfo->conn->ClientGUID,
               SMB2_CLIENT_GUID_SIZE);
+       lb->conn = ksmbd_conn_get(opinfo->conn);
        INIT_LIST_HEAD(&lb->lease_list);
        spin_lock_init(&lb->lb_lock);
        return lb;
 }
 
+static void free_lease_table(struct lease_table *lb)
+{
+       if (!lb)
+               return;
+
+       ksmbd_conn_put(lb->conn);
+       kfree(lb);
+}
+
 static struct lease *alloc_lease(struct lease_ctx_info *lctx,
                                 struct ksmbd_inode *ci)
 {
@@ -942,6 +952,9 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo, bool wait_ack,
        struct lease *lease = opinfo->o_lease;
 
        conn = READ_ONCE(opinfo->conn);
+       if (lease->version == 2 && lease->l_lb && lease->l_lb->conn &&
+           !ksmbd_conn_releasing(lease->l_lb->conn))
+               conn = lease->l_lb->conn;
        if (!conn)
                return 0;
 
@@ -1134,7 +1147,7 @@ void destroy_lease_table(struct ksmbd_conn *conn)
                list_for_each_entry_safe(lease, ltmp, &lb->lease_list, l_entry)
                        lease_del_table(lease);
                list_del(&lb->l_entry);
-               kfree(lb);
+               free_lease_table(lb);
        }
        write_unlock(&lease_list_lock);
 }
@@ -1193,7 +1206,7 @@ static void add_lease_global_list(struct lease *lease, struct ksmbd_conn *conn,
                            SMB2_CLIENT_GUID_SIZE)) {
                        lease_add_table(lease, lb);
                        write_unlock(&lease_list_lock);
-                       kfree(new_lb);
+                       free_lease_table(new_lb);
                        return;
                }
        }
index 1dd52b44557f25c50a8accfe642818a80f969a2e..8d19435862468f3de5b4e3d6364b9aa41c975ede 100644 (file)
@@ -34,6 +34,7 @@ struct lease_ctx_info {
 
 struct lease_table {
        char                    client_guid[SMB2_CLIENT_GUID_SIZE];
+       struct ksmbd_conn       *conn;
        struct list_head        lease_list;
        struct list_head        l_entry;
        spinlock_t              lb_lock;