cifs: move allocation of new TCP_Server_Info into separate function
authorJeff Layton <jlayton@redhat.com>
Mon, 1 Dec 2008 23:41:46 +0000 (18:41 -0500)
committerSteve French <sfrench@us.ibm.com>
Fri, 26 Dec 2008 02:29:10 +0000 (02:29 +0000)
Clean up cifs_mount a bit by moving the code that creates new TCP
sessions into a separate function. Have that function search for an
existing socket and then create a new one if one isn't found.

Also reorganize the initializion of TCP_Server_Info a bit to prepare
for cleanup of the socket connection code.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
fs/cifs/connect.c

index 65c1219..56095b2 100644 (file)
@@ -1417,6 +1417,148 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
                force_sig(SIGKILL, task);
 }
 
+static struct TCP_Server_Info *
+cifs_get_tcp_session(struct smb_vol *volume_info)
+{
+       struct TCP_Server_Info *tcp_ses = NULL;
+       struct sockaddr addr;
+       struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
+       struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
+       int rc;
+
+       memset(&addr, 0, sizeof(struct sockaddr));
+
+       if (volume_info->UNCip && volume_info->UNC) {
+               rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
+                                   &sin_server->sin_addr.s_addr);
+
+               if (rc <= 0) {
+                       /* not ipv4 address, try ipv6 */
+                       rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
+                                           &sin_server6->sin6_addr.in6_u);
+                       if (rc > 0)
+                               addr.sa_family = AF_INET6;
+               } else {
+                       addr.sa_family = AF_INET;
+               }
+
+               if (rc <= 0) {
+                       /* we failed translating address */
+                       rc = -EINVAL;
+                       goto out_err;
+               }
+
+               cFYI(1, ("UNC: %s ip: %s", volume_info->UNC,
+                        volume_info->UNCip));
+       } else if (volume_info->UNCip) {
+               /* BB using ip addr as tcp_ses name to connect to the
+                  DFS root below */
+               cERROR(1, ("Connecting to DFS root not implemented yet"));
+               rc = -EINVAL;
+               goto out_err;
+       } else /* which tcp_sess DFS root would we conect to */ {
+               cERROR(1,
+                      ("CIFS mount error: No UNC path (e.g. -o "
+                       "unc=//192.168.1.100/public) specified"));
+               rc = -EINVAL;
+               goto out_err;
+       }
+
+       /* see if we already have a matching tcp_ses */
+       tcp_ses = cifs_find_tcp_session(&addr);
+       if (tcp_ses)
+               return tcp_ses;
+
+       tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
+       if (!tcp_ses) {
+               rc = -ENOMEM;
+               goto out_err;
+       }
+
+       tcp_ses->hostname = extract_hostname(volume_info->UNC);
+       if (IS_ERR(tcp_ses->hostname)) {
+               rc = PTR_ERR(tcp_ses->hostname);
+               goto out_err;
+       }
+
+       tcp_ses->noblocksnd = volume_info->noblocksnd;
+       tcp_ses->noautotune = volume_info->noautotune;
+       atomic_set(&tcp_ses->inFlight, 0);
+       init_waitqueue_head(&tcp_ses->response_q);
+       init_waitqueue_head(&tcp_ses->request_q);
+       INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
+       mutex_init(&tcp_ses->srv_mutex);
+       memcpy(tcp_ses->workstation_RFC1001_name,
+               volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
+       memcpy(tcp_ses->server_RFC1001_name,
+               volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
+       tcp_ses->sequence_number = 0;
+       INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
+       INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
+
+       /*
+        * at this point we are the only ones with the pointer
+        * to the struct since the kernel thread not created yet
+        * no need to spinlock this init of tcpStatus or srv_count
+        */
+       tcp_ses->tcpStatus = CifsNew;
+       ++tcp_ses->srv_count;
+
+       if (addr.sa_family == AF_INET6) {
+               cFYI(1, ("attempting ipv6 connect"));
+               /* BB should we allow ipv6 on port 139? */
+               /* other OS never observed in Wild doing 139 with v6 */
+               memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
+                       sizeof(struct sockaddr_in6));
+               sin_server6->sin6_port = htons(volume_info->port);
+               rc = ipv6_connect(sin_server6, &tcp_ses->ssocket,
+                               volume_info->noblocksnd);
+       } else {
+               memcpy(&tcp_ses->addr.sockAddr, sin_server,
+                       sizeof(struct sockaddr_in));
+               sin_server->sin_port = htons(volume_info->port);
+               rc = ipv4_connect(sin_server, &tcp_ses->ssocket,
+                         volume_info->source_rfc1001_name,
+                         volume_info->target_rfc1001_name,
+                         volume_info->noblocksnd,
+                         volume_info->noautotune);
+       }
+       if (rc < 0) {
+               cERROR(1, ("Error connecting to socket. Aborting operation"));
+               goto out_err;
+       }
+
+       /*
+        * since we're in a cifs function already, we know that
+        * this will succeed. No need for try_module_get().
+        */
+       __module_get(THIS_MODULE);
+       tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
+                                 tcp_ses, "cifsd");
+       if (IS_ERR(tcp_ses->tsk)) {
+               rc = PTR_ERR(tcp_ses->tsk);
+               cERROR(1, ("error %d create cifsd thread", rc));
+               module_put(THIS_MODULE);
+               goto out_err;
+       }
+
+       /* thread spawned, put it on the list */
+       write_lock(&cifs_tcp_ses_lock);
+       list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
+       write_unlock(&cifs_tcp_ses_lock);
+
+       return tcp_ses;
+
+out_err:
+       if (tcp_ses) {
+               kfree(tcp_ses->hostname);
+               if (tcp_ses->ssocket)
+                       sock_release(tcp_ses->ssocket);
+               kfree(tcp_ses);
+       }
+       return ERR_PTR(rc);
+}
+
 static struct cifsSesInfo *
 cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
 {
@@ -2043,10 +2185,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 {
        int rc = 0;
        int xid;
-       struct socket *csocket = NULL;
-       struct sockaddr addr;
-       struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
-       struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
        struct smb_vol volume_info;
        struct cifsSesInfo *pSesInfo = NULL;
        struct cifsTconInfo *tcon = NULL;
@@ -2056,7 +2194,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 
 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
 
-       memset(&addr, 0, sizeof(struct sockaddr));
        memset(&volume_info, 0, sizeof(struct smb_vol));
        if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
                rc = -EINVAL;
@@ -2077,42 +2214,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                goto out;
        }
 
-       if (volume_info.UNCip && volume_info.UNC) {
-               rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
-                                   &sin_server->sin_addr.s_addr);
-
-               if (rc <= 0) {
-                       /* not ipv4 address, try ipv6 */
-                       rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
-                                           &sin_server6->sin6_addr.in6_u);
-                       if (rc > 0)
-                               addr.sa_family = AF_INET6;
-               } else {
-                       addr.sa_family = AF_INET;
-               }
-
-               if (rc <= 0) {
-                       /* we failed translating address */
-                       rc = -EINVAL;
-                       goto out;
-               }
-
-               cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
-               /* success */
-               rc = 0;
-       } else if (volume_info.UNCip) {
-               /* BB using ip addr as server name to connect to the
-                  DFS root below */
-               cERROR(1, ("Connecting to DFS root not implemented yet"));
-               rc = -EINVAL;
-               goto out;
-       } else /* which servers DFS root would we conect to */ {
-               cERROR(1,
-                      ("CIFS mount error: No UNC path (e.g. -o "
-                       "unc=//192.168.1.100/public) specified"));
-               rc = -EINVAL;
-               goto out;
-       }
 
        /* this is needed for ASCII cp to Unicode converts */
        if (volume_info.iocharset == NULL) {
@@ -2128,94 +2229,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                }
        }
 
-       srvTcp = cifs_find_tcp_session(&addr);
-       if (!srvTcp) { /* create socket */
-               if (addr.sa_family == AF_INET6) {
-                       cFYI(1, ("attempting ipv6 connect"));
-                       /* BB should we allow ipv6 on port 139? */
-                       /* other OS never observed in Wild doing 139 with v6 */
-                       sin_server6->sin6_port = htons(volume_info.port);
-                       rc = ipv6_connect(sin_server6, &csocket,
-                                       volume_info.noblocksnd);
-               } else {
-                       sin_server->sin_port = htons(volume_info.port);
-                       rc = ipv4_connect(sin_server, &csocket,
-                                 volume_info.source_rfc1001_name,
-                                 volume_info.target_rfc1001_name,
-                                 volume_info.noblocksnd,
-                                 volume_info.noautotune);
-               }
-               if (rc < 0) {
-                       cERROR(1, ("Error connecting to socket. "
-                                  "Aborting operation"));
-                       if (csocket != NULL)
-                               sock_release(csocket);
-                       goto out;
-               }
-
-               srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
-               if (!srvTcp) {
-                       rc = -ENOMEM;
-                       sock_release(csocket);
-                       goto out;
-               } else {
-                       srvTcp->noblocksnd = volume_info.noblocksnd;
-                       srvTcp->noautotune = volume_info.noautotune;
-                       if (addr.sa_family == AF_INET6)
-                               memcpy(&srvTcp->addr.sockAddr6, sin_server6,
-                                       sizeof(struct sockaddr_in6));
-                       else
-                               memcpy(&srvTcp->addr.sockAddr, sin_server,
-                                       sizeof(struct sockaddr_in));
-                       atomic_set(&srvTcp->inFlight, 0);
-                       /* BB Add code for ipv6 case too */
-                       srvTcp->ssocket = csocket;
-                       srvTcp->hostname = extract_hostname(volume_info.UNC);
-                       if (IS_ERR(srvTcp->hostname)) {
-                               rc = PTR_ERR(srvTcp->hostname);
-                               sock_release(csocket);
-                               goto out;
-                       }
-                       init_waitqueue_head(&srvTcp->response_q);
-                       init_waitqueue_head(&srvTcp->request_q);
-                       INIT_LIST_HEAD(&srvTcp->pending_mid_q);
-                       /* at this point we are the only ones with the pointer
-                       to the struct since the kernel thread not created yet
-                       so no need to spinlock this init of tcpStatus */
-                       srvTcp->tcpStatus = CifsNew;
-                       mutex_init(&srvTcp->srv_mutex);
-
-                       /*
-                        * since we're in a cifs function already, we know that
-                        * this will succeed. No need for try_module_get().
-                        */
-                       __module_get(THIS_MODULE);
-                       srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
-                       if (IS_ERR(srvTcp->tsk)) {
-                               rc = PTR_ERR(srvTcp->tsk);
-                               cERROR(1, ("error %d create cifsd thread", rc));
-                               module_put(THIS_MODULE);
-                               srvTcp->tsk = NULL;
-                               sock_release(csocket);
-                               kfree(srvTcp->hostname);
-                               goto out;
-                       }
-                       rc = 0;
-                       memcpy(srvTcp->workstation_RFC1001_name,
-                               volume_info.source_rfc1001_name,
-                               RFC1001_NAME_LEN_WITH_NULL);
-                       memcpy(srvTcp->server_RFC1001_name,
-                               volume_info.target_rfc1001_name,
-                               RFC1001_NAME_LEN_WITH_NULL);
-                       srvTcp->sequence_number = 0;
-                       INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
-                       INIT_LIST_HEAD(&srvTcp->smb_ses_list);
-                       ++srvTcp->srv_count;
-                       write_lock(&cifs_tcp_ses_lock);
-                       list_add(&srvTcp->tcp_ses_list,
-                                &cifs_tcp_ses_list);
-                       write_unlock(&cifs_tcp_ses_lock);
-               }
+       /* get a reference to a tcp session */
+       srvTcp = cifs_get_tcp_session(&volume_info);
+       if (IS_ERR(srvTcp)) {
+               rc = PTR_ERR(srvTcp);
+               goto out;
        }
 
        pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
@@ -2245,12 +2263,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 
                /* new SMB session uses our srvTcp ref */
                pSesInfo->server = srvTcp;
-               if (addr.sa_family == AF_INET6)
+               if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6)
                        sprintf(pSesInfo->serverName, NIP6_FMT,
-                               NIP6(sin_server6->sin6_addr));
+                               NIP6(srvTcp->addr.sockAddr6.sin6_addr));
                else
                        sprintf(pSesInfo->serverName, NIPQUAD_FMT,
-                               NIPQUAD(sin_server->sin_addr.s_addr));
+                               NIPQUAD(srvTcp->addr.sockAddr.sin_addr.s_addr));
 
                write_lock(&cifs_tcp_ses_lock);
                list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);