]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
cifs: always iterate smb sessions using primary channel
authorShyam Prasad N <sprasad@microsoft.com>
Fri, 28 Oct 2022 09:52:26 +0000 (09:52 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 26 Nov 2022 08:27:22 +0000 (09:27 +0100)
[ Upstream commit 8abcaeaed38109e5ccaf40218e0e9e387f07bfe6 ]

smb sessions and tcons currently hang off primary channel only.
Secondary channels have the lists as empty. Whenever there's a
need to iterate sessions or tcons, we should use the list in the
corresponding primary channel.

Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/cifs/misc.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2transport.c

index 87f60f7367315635949a924de6081ab336715e4c..35085fa8663679f4f1c94433281a0d8096901eaa 100644 (file)
@@ -400,6 +400,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
 {
        struct smb_hdr *buf = (struct smb_hdr *)buffer;
        struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
+       struct TCP_Server_Info *pserver;
        struct cifs_ses *ses;
        struct cifs_tcon *tcon;
        struct cifsInodeInfo *pCifsInode;
@@ -464,9 +465,12 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
        if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
                return false;
 
+       /* If server is a channel, select the primary channel */
+       pserver = CIFS_SERVER_IS_CHAN(srv) ? srv->primary_server : srv;
+
        /* look up tcon based on tid & uid */
        spin_lock(&cifs_tcp_ses_lock);
-       list_for_each_entry(ses, &srv->smb_ses_list, smb_ses_list) {
+       list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
                list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
                        if (tcon->tid != buf->Tid)
                                continue;
index d73e5672aac493b8e1694250c9b8b650d9e6e314..3bcd3ac65dc173ffcb21778b43a1ced3caa14058 100644 (file)
@@ -135,6 +135,7 @@ static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, __u32 len,
 int
 smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
 {
+       struct TCP_Server_Info *pserver;
        struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
        struct smb2_pdu *pdu = (struct smb2_pdu *)shdr;
        int hdr_size = sizeof(struct smb2_hdr);
@@ -143,6 +144,9 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
        __u32 calc_len; /* calculated length */
        __u64 mid;
 
+       /* If server is a channel, select the primary channel */
+       pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+
        /*
         * Add function to do table lookup of StructureSize by command
         * ie Validate the wct via smb2_struct_sizes table above
@@ -155,7 +159,7 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
 
                /* decrypt frame now that it is completely read in */
                spin_lock(&cifs_tcp_ses_lock);
-               list_for_each_entry(iter, &server->smb_ses_list, smb_ses_list) {
+               list_for_each_entry(iter, &pserver->smb_ses_list, smb_ses_list) {
                        if (iter->Suid == le64_to_cpu(thdr->SessionId)) {
                                ses = iter;
                                break;
@@ -671,6 +675,7 @@ bool
 smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
 {
        struct smb2_oplock_break *rsp = (struct smb2_oplock_break *)buffer;
+       struct TCP_Server_Info *pserver;
        struct cifs_ses *ses;
        struct cifs_tcon *tcon;
        struct cifsInodeInfo *cinode;
@@ -691,9 +696,12 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
 
        cifs_dbg(FYI, "oplock level 0x%x\n", rsp->OplockLevel);
 
+       /* If server is a channel, select the primary channel */
+       pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+
        /* look up tcon based on tid & uid */
        spin_lock(&cifs_tcp_ses_lock);
-       list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+       list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
                list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
 
                        spin_lock(&tcon->open_file_lock);
index 14376437187aecc4fbeebd6790523bfd252efd6e..c258a7b122b640cf5b94262ea0e0bd31d5b72ade 100644 (file)
@@ -2288,14 +2288,18 @@ static void
 smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
 {
        struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
+       struct TCP_Server_Info *pserver;
        struct cifs_ses *ses;
        struct cifs_tcon *tcon;
 
        if (shdr->Status != STATUS_NETWORK_NAME_DELETED)
                return;
 
+       /* If server is a channel, select the primary channel */
+       pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+
        spin_lock(&cifs_tcp_ses_lock);
-       list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+       list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
                list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
                        if (tcon->tid == le32_to_cpu(shdr->Id.SyncId.TreeId)) {
                                spin_lock(&tcon->tc_lock);
index 4640fc4a8b133d5b0f7a74a9c59a7520d87d8932..da85cfd7803b365e8a5da7c1ef9592bb8902364a 100644 (file)
@@ -140,9 +140,13 @@ out:
 static struct cifs_ses *
 smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
 {
+       struct TCP_Server_Info *pserver;
        struct cifs_ses *ses;
 
-       list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+       /* If server is a channel, select the primary channel */
+       pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+
+       list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
                if (ses->Suid != ses_id)
                        continue;
                ++ses->ses_count;