smb: client: reduce stack usage in cifs_try_adding_channels()
authorPaulo Alcantara <pc@manguebit.com>
Thu, 17 Aug 2023 15:34:10 +0000 (12:34 -0300)
committerSteve French <stfrench@microsoft.com>
Sun, 20 Aug 2023 21:05:50 +0000 (16:05 -0500)
Clang warns about exceeded stack frame size

  fs/smb/client/sess.c:160:5: warning: stack frame size (1368) exceeds
  limit (1024) in 'cifs_try_adding_channels' [-Wframe-larger-than]

It turns out that cifs_ses_add_channel() got inlined into
cifs_try_adding_channels() which had a stack-allocated variable @ctx
of 624 bytes in size.  Fix this by making it heap-allocated.

Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202307270640.5ODmPwDl-lkp@intel.com/
Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/sess.c

index c57ca20..5292216 100644 (file)
@@ -360,11 +360,11 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
 {
        struct TCP_Server_Info *chan_server;
        struct cifs_chan *chan;
-       struct smb3_fs_context ctx = {NULL};
+       struct smb3_fs_context *ctx;
        static const char unc_fmt[] = "\\%s\\foo";
-       char unc[sizeof(unc_fmt)+SERVER_NAME_LEN_WITH_NULL] = {0};
        struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
        struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
+       size_t len;
        int rc;
        unsigned int xid = get_xid();
 
@@ -388,54 +388,64 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
         * the session and server without caring about memory
         * management.
         */
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               rc = -ENOMEM;
+               goto out_free_xid;
+       }
 
        /* Always make new connection for now (TODO?) */
-       ctx.nosharesock = true;
+       ctx->nosharesock = true;
 
        /* Auth */
-       ctx.domainauto = ses->domainAuto;
-       ctx.domainname = ses->domainName;
+       ctx->domainauto = ses->domainAuto;
+       ctx->domainname = ses->domainName;
 
        /* no hostname for extra channels */
-       ctx.server_hostname = "";
+       ctx->server_hostname = "";
 
-       ctx.username = ses->user_name;
-       ctx.password = ses->password;
-       ctx.sectype = ses->sectype;
-       ctx.sign = ses->sign;
+       ctx->username = ses->user_name;
+       ctx->password = ses->password;
+       ctx->sectype = ses->sectype;
+       ctx->sign = ses->sign;
 
        /* UNC and paths */
        /* XXX: Use ses->server->hostname? */
-       sprintf(unc, unc_fmt, ses->ip_addr);
-       ctx.UNC = unc;
-       ctx.prepath = "";
+       len = sizeof(unc_fmt) + SERVER_NAME_LEN_WITH_NULL;
+       ctx->UNC = kzalloc(len, GFP_KERNEL);
+       if (!ctx->UNC) {
+               rc = -ENOMEM;
+               goto out_free_ctx;
+       }
+       scnprintf(ctx->UNC, len, unc_fmt, ses->ip_addr);
+       ctx->prepath = "";
 
        /* Reuse same version as master connection */
-       ctx.vals = ses->server->vals;
-       ctx.ops = ses->server->ops;
+       ctx->vals = ses->server->vals;
+       ctx->ops = ses->server->ops;
 
-       ctx.noblocksnd = ses->server->noblocksnd;
-       ctx.noautotune = ses->server->noautotune;
-       ctx.sockopt_tcp_nodelay = ses->server->tcp_nodelay;
-       ctx.echo_interval = ses->server->echo_interval / HZ;
-       ctx.max_credits = ses->server->max_credits;
+       ctx->noblocksnd = ses->server->noblocksnd;
+       ctx->noautotune = ses->server->noautotune;
+       ctx->sockopt_tcp_nodelay = ses->server->tcp_nodelay;
+       ctx->echo_interval = ses->server->echo_interval / HZ;
+       ctx->max_credits = ses->server->max_credits;
 
        /*
         * This will be used for encoding/decoding user/domain/pw
         * during sess setup auth.
         */
-       ctx.local_nls = cifs_sb->local_nls;
+       ctx->local_nls = cifs_sb->local_nls;
 
        /* Use RDMA if possible */
-       ctx.rdma = iface->rdma_capable;
-       memcpy(&ctx.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage));
+       ctx->rdma = iface->rdma_capable;
+       memcpy(&ctx->dstaddr, &iface->sockaddr, sizeof(ctx->dstaddr));
 
        /* reuse master con client guid */
-       memcpy(&ctx.client_guid, ses->server->client_guid,
-              SMB2_CLIENT_GUID_SIZE);
-       ctx.use_client_guid = true;
+       memcpy(&ctx->client_guid, ses->server->client_guid,
+              sizeof(ctx->client_guid));
+       ctx->use_client_guid = true;
 
-       chan_server = cifs_get_tcp_session(&ctx, ses->server);
+       chan_server = cifs_get_tcp_session(ctx, ses->server);
 
        spin_lock(&ses->chan_lock);
        chan = &ses->chans[ses->chan_count];
@@ -497,6 +507,10 @@ out:
                cifs_put_tcp_session(chan->server, 0);
        }
 
+       kfree(ctx->UNC);
+out_free_ctx:
+       kfree(ctx);
+out_free_xid:
        free_xid(xid);
        return rc;
 }