cifs: connect individual channel servers to primary channel server
authorShyam Prasad N <sprasad@microsoft.com>
Mon, 19 Jul 2021 11:26:24 +0000 (11:26 +0000)
committerSteve French <stfrench@microsoft.com>
Sat, 13 Nov 2021 02:27:06 +0000 (20:27 -0600)
Today, we don't have any way to get the smb session for any
of the secondary channels. Introducing a pointer to the primary
server from server struct of any secondary channel. The value will
be NULL for the server of the primary channel. This will enable us
to get the smb session for any channel.

This will be needed for some of the changes that I'm planning
to make soon.

Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/cifs_debug.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/sess.c
fs/cifs/smb2pdu.c

index 248a8f973cf9c11cd23f2cd68ec2a84d8fefdce0..d282caf9f03721a6c41656a6cde4f775d747d955 100644 (file)
@@ -271,7 +271,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
        c = 0;
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
-               if (server->is_channel)
+               /* channel info will be printed as a part of sessions below */
+               if (CIFS_SERVER_IS_CHAN(server))
                        continue;
 
                c++;
index 3c18c56a119ba649fcb0699b2fa170c73860090f..be74606724c7939d0fe944ebf572d2090b62b09c 100644 (file)
@@ -690,7 +690,15 @@ struct TCP_Server_Info {
         */
        int nr_targets;
        bool noblockcnt; /* use non-blocking connect() */
-       bool is_channel; /* if a session channel */
+
+       /*
+        * If this is a session channel,
+        * primary_server holds the ref-counted
+        * pointer to primary channel connection for the session.
+        */
+#define CIFS_SERVER_IS_CHAN(server)    (!!(server)->primary_server)
+       struct TCP_Server_Info *primary_server;
+
 #ifdef CONFIG_CIFS_SWN_UPCALL
        bool use_swn_dstaddr;
        struct sockaddr_storage swn_dstaddr;
index b2697356b5e7db2512f7d802863f462ce2069a90..f3073a62ce574e379e054163d664dd97114b1623 100644 (file)
@@ -269,8 +269,9 @@ extern void cifs_close_all_deferred_files(struct cifs_tcon *cifs_tcon);
 
 extern void cifs_close_deferred_file_under_dentry(struct cifs_tcon *cifs_tcon,
                                const char *path);
-
-extern struct TCP_Server_Info *cifs_get_tcp_session(struct smb3_fs_context *ctx);
+extern struct TCP_Server_Info *
+cifs_get_tcp_session(struct smb3_fs_context *ctx,
+                    struct TCP_Server_Info *primary_server);
 extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
                                 int from_reconnect);
 extern void cifs_put_tcon(struct cifs_tcon *tcon);
index 09a532ed8fe42eb657fef0e758fb9d78cfc9329c..f80b73f2d0a08c93501dde70f45a8f196503cf2b 100644 (file)
@@ -173,6 +173,7 @@ static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server
        struct cifs_tcon *tcon;
        struct mid_q_entry *mid, *nmid;
        struct list_head retry_list;
+       struct TCP_Server_Info *pserver;
 
        server->maxBuf = 0;
        server->max_read = 0;
@@ -184,8 +185,12 @@ static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server
         * are not used until reconnected.
         */
        cifs_dbg(FYI, "%s: marking sessions and tcons for reconnect\n", __func__);
+
+       /* 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) {
                ses->need_reconnect = true;
                list_for_each_entry(tcon, &ses->tcon_list, tcon_list)
                        tcon->need_reconnect = true;
@@ -1338,7 +1343,7 @@ cifs_find_tcp_session(struct smb3_fs_context *ctx)
                 * Skip ses channels since they're only handled in lower layers
                 * (e.g. cifs_send_recv).
                 */
-               if (server->is_channel || !match_server(server, ctx))
+               if (CIFS_SERVER_IS_CHAN(server) || !match_server(server, ctx))
                        continue;
 
                ++server->srv_count;
@@ -1369,6 +1374,10 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
        list_del_init(&server->tcp_ses_list);
        spin_unlock(&cifs_tcp_ses_lock);
 
+       /* For secondary channels, we pick up ref-count on the primary server */
+       if (CIFS_SERVER_IS_CHAN(server))
+               cifs_put_tcp_session(server->primary_server, from_reconnect);
+
        cancel_delayed_work_sync(&server->echo);
        cancel_delayed_work_sync(&server->resolve);
 
@@ -1401,7 +1410,8 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
 }
 
 struct TCP_Server_Info *
-cifs_get_tcp_session(struct smb3_fs_context *ctx)
+cifs_get_tcp_session(struct smb3_fs_context *ctx,
+                    struct TCP_Server_Info *primary_server)
 {
        struct TCP_Server_Info *tcp_ses = NULL;
        int rc;
@@ -1438,6 +1448,10 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx)
        tcp_ses->in_flight = 0;
        tcp_ses->max_in_flight = 0;
        tcp_ses->credits = 1;
+       if (primary_server) {
+               ++primary_server->srv_count;
+               tcp_ses->primary_server = primary_server;
+       }
        init_waitqueue_head(&tcp_ses->response_q);
        init_waitqueue_head(&tcp_ses->request_q);
        INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
@@ -1559,6 +1573,8 @@ out_err_crypto_release:
 
 out_err:
        if (tcp_ses) {
+               if (CIFS_SERVER_IS_CHAN(tcp_ses))
+                       cifs_put_tcp_session(tcp_ses->primary_server, false);
                kfree(tcp_ses->hostname);
                if (tcp_ses->ssocket)
                        sock_release(tcp_ses->ssocket);
@@ -2960,7 +2976,7 @@ static int mount_get_conns(struct mount_ctx *mnt_ctx)
        xid = get_xid();
 
        /* get a reference to a tcp session */
-       server = cifs_get_tcp_session(ctx);
+       server = cifs_get_tcp_session(ctx, NULL);
        if (IS_ERR(server)) {
                rc = PTR_ERR(server);
                server = NULL;
index 27660bffb91884005343b4451d4ea3421a62d29d..2c10b186ed6ee6444c43c852500fb4714bf291b5 100644 (file)
@@ -258,7 +258,7 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
               SMB2_CLIENT_GUID_SIZE);
        ctx.use_client_guid = true;
 
-       chan_server = cifs_get_tcp_session(&ctx);
+       chan_server = cifs_get_tcp_session(&ctx, ses->server);
 
        mutex_lock(&ses->session_mutex);
        spin_lock(&ses->chan_lock);
@@ -272,10 +272,6 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
        }
        spin_unlock(&ses->chan_lock);
 
-       spin_lock(&cifs_tcp_ses_lock);
-       chan->server->is_channel = true;
-       spin_unlock(&cifs_tcp_ses_lock);
-
        /*
         * We need to allocate the server crypto now as we will need
         * to sign packets before we generate the channel signing key
index 5e032b2b2adb0026f0befae5c1a532715512242d..2f5f2c4c6183c9461bf819b21781989046f6c338 100644 (file)
@@ -257,7 +257,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
        /*
         * If we are reconnecting an extra channel, bind
         */
-       if (server->is_channel) {
+       if (CIFS_SERVER_IS_CHAN(server)) {
                ses->binding = true;
                ses->binding_chan = cifs_ses_find_chan(ses, server);
        }