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)
committerSteve French <stfrench@microsoft.com>
Sat, 5 Nov 2022 04:34:02 +0000 (23:34 -0500)
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>
fs/cifs/misc.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2transport.c

index da51ffd..3e68d82 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 a387204..e73a3c6 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 4f53fa0..cca12ea 100644 (file)
@@ -2302,14 +2302,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 8e3f26e..8a9d9d0 100644 (file)
@@ -136,9 +136,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;