cifs: move allocation of new TCP_Server_Info into separate function

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>
This commit is contained in:
Jeff Layton 2008-12-01 18:41:46 -05:00 committed by Steve French
parent 8ecaf67a8e
commit 63c038c297

View 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,96 +2229,13 @@ 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);
/* get a reference to a tcp session */
srvTcp = cifs_get_tcp_session(&volume_info);
if (IS_ERR(srvTcp)) {
rc = PTR_ERR(srvTcp);
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);
}
}
pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
if (pSesInfo) {
cFYI(1, ("Existing smb sess found (status=%d)",
@ -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);