Merge to Fedora kernel-2.6.7-1.441
[linux-2.6.git] / fs / cifs / connect.c
index 3f1261a..befbff5 100644 (file)
@@ -95,9 +95,15 @@ cifs_reconnect(struct TCP_Server_Info *server)
        struct cifsTconInfo *tcon;
        struct mid_q_entry * mid_entry;
        
-       if(server->tcpStatus == CifsExiting)
+       spin_lock(&GlobalMid_Lock);
+       if(server->tcpStatus == CifsExiting) {
+               /* the demux thread will exit normally 
+               next time through the loop */
+               spin_unlock(&GlobalMid_Lock);
                return rc;
-       server->tcpStatus = CifsNeedReconnect;
+       } else
+               server->tcpStatus = CifsNeedReconnect;
+       spin_unlock(&GlobalMid_Lock);
        server->maxBuf = 0;
 
        cFYI(1, ("Reconnecting tcp session "));
@@ -122,7 +128,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
                }
        }
        read_unlock(&GlobalSMBSeslock);
-
+       /* do not want to be sending data on a socket we are freeing */
+       down(&server->tcpSem); 
        if(server->ssocket) {
                cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
                        server->ssocket->flags));
@@ -148,7 +155,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
                }
        }
        spin_unlock(&GlobalMid_Lock);
-
+       up(&server->tcpSem); 
 
        while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
        {
@@ -164,7 +171,10 @@ cifs_reconnect(struct TCP_Server_Info *server)
                        schedule_timeout(3 * HZ);
                } else {
                        atomic_inc(&tcpSesReconnectCount);
-                       server->tcpStatus = CifsGood;
+                       spin_lock(&GlobalMid_Lock);
+                       if(server->tcpStatus != CifsExiting)
+                               server->tcpStatus = CifsGood;
+                       spin_unlock(&GlobalMid_Lock);
                        atomic_set(&server->inFlight,0);
                        wake_up(&server->response_q);
                }
@@ -243,12 +253,14 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                /* some servers kill tcp session rather than returning
                                        smb negprot error in which case reconnecting here is
                                        not going to help - return error to mount */
+                               spin_lock(&GlobalMid_Lock);
                                server->tcpStatus = CifsExiting;
+                               spin_unlock(&GlobalMid_Lock);
                                wake_up(&server->response_q);
                                break;
                        }
 
-                       cFYI(1,("Reconnecting after unexpected rcvmsg error "));
+                       cFYI(1,("Reconnecting after unexpected peek error %d",length));
                        cifs_reconnect(server);
                        csocket = server->ssocket;
                        wake_up(&server->response_q);
@@ -268,7 +280,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                length = sock_recvmsg(csocket, &smb_msg, 4, 0);
                                cFYI(0,("Received 4 byte keep alive packet"));
                        } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
-                               iov.iov_base = smb_buffer;
+                                       iov.iov_base = smb_buffer;
                                        iov.iov_len = 4;
                                        length = sock_recvmsg(csocket, &smb_msg, 4, 0);
                                        cFYI(1,("Good RFC 1002 session rsp"));
@@ -280,7 +292,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                        /* if nack on negprot (rather than 
                                        ret of smb negprot error) reconnecting
                                        not going to help, ret error to mount */
+                                       spin_lock(&GlobalMid_Lock);
                                        server->tcpStatus = CifsExiting;
+                                       spin_unlock(&GlobalMid_Lock);
                                        /* wake up thread doing negprot */
                                        wake_up(&server->response_q);
                                        break;
@@ -391,7 +405,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                        }
                }
        }
+       spin_lock(&GlobalMid_Lock);
        server->tcpStatus = CifsExiting;
+       spin_unlock(&GlobalMid_Lock);
        atomic_set(&server->inFlight, 0);
        /* Although there should not be any requests blocked on 
        this queue it can not hurt to be paranoid and try to wake up requests
@@ -595,6 +611,8 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
                        }
                        if ((temp_len = strnlen(value, 300)) < 300) {
                                vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
+                               if(vol->UNC == NULL)
+                                       return 1;
                                strcpy(vol->UNC,value);
                                if (strncmp(vol->UNC, "//", 2) == 0) {
                                        vol->UNC[0] = '\\';
@@ -742,6 +760,8 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
                }
                if ((temp_len = strnlen(devname, 300)) < 300) {
                        vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
+                       if(vol->UNC == NULL)
+                               return 1;
                        strcpy(vol->UNC,devname);
                        if (strncmp(vol->UNC, "//", 2) == 0) {
                                vol->UNC[0] = '\\';
@@ -1030,7 +1050,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
                } else {
                /* BB other socket options to set KEEPALIVE, NODELAY? */
                         cFYI(1,("ipv6 Socket created"));
-                        (*csocket)->sk->sk_allocation = GFP_NOFS;
+                       (*csocket)->sk->sk_allocation = GFP_NOFS;
                }
        }
 
@@ -1226,6 +1246,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        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;
                        init_MUTEX(&srvTcp->tcpSem);
                        kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
@@ -1342,9 +1365,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 
 /* on error free sesinfo and tcon struct if needed */
        if (rc) {
-               if(atomic_read(&srvTcp->socketUseCount) == 0)
-                       srvTcp->tcpStatus = CifsExiting;
-                          /* If find_unc succeeded then rc == 0 so we can not end */
+               if(atomic_read(&srvTcp->socketUseCount) == 0) {
+                       spin_lock(&GlobalMid_Lock);
+                       srvTcp->tcpStatus = CifsExiting;
+                       spin_unlock(&GlobalMid_Lock);
+               }
+                /* If find_unc succeeded then rc == 0 so we can not end */
                if (tcon)  /* up here accidently freeing someone elses tcon struct */
                        tconInfoFree(tcon);
                if (existingCifsSes == 0) {
@@ -1534,7 +1560,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        bcc_ptr +=
                                            pSMBr->resp.SecurityBlobLength;
 
-                               if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
+                               if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
                                        if ((long) (bcc_ptr) % 2) {
                                                remaining_words =
                                                    (BCC(smb_buffer_response)
@@ -1787,7 +1813,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                              pSMBr->resp.SecurityBlobLength));
                                }
 
-                               if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
+                               if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
                                        if ((long) (bcc_ptr) % 2) {
                                                remaining_words =
                                                    (BCC(smb_buffer_response)
@@ -2098,7 +2124,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                ses->server->secMode |= 
                                                        SECMODE_SIGN_ENABLED;
 
-                               if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
+                               if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
                                        if ((long) (bcc_ptr) % 2) {
                                                remaining_words =
                                                    (BCC(smb_buffer_response)
@@ -2494,7 +2520,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                cFYI(1,
                                     ("NTLMSSP response to Authenticate "));
 
-                               if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
+                               if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
                                        if ((long) (bcc_ptr) % 2) {
                                                remaining_words =
                                                    (BCC(smb_buffer_response)
@@ -2693,7 +2719,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
         /* skip service field (NB: this field is always ASCII) */
                bcc_ptr += length + 1;  
                strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
-               if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
+               if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
                        length = UniStrnlen((wchar_t *) bcc_ptr, 512);
                        if (((long) bcc_ptr + (2 * length)) -
                            (long) pByteArea(smb_buffer_response) <=
@@ -2791,7 +2817,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
        char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
        int ntlmv2_flag = FALSE;
 
-    /* what if server changes its buffer size after dropping the session? */
+       /* what if server changes its buffer size after dropping the session? */
        if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
                rc = CIFSSMBNegotiate(xid, pSesInfo);
                if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
@@ -2799,8 +2825,15 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        if(rc == -EAGAIN) 
                                rc = -EHOSTDOWN;
                }
-               if(rc == 0)
-                       pSesInfo->server->tcpStatus = CifsGood;
+               if(rc == 0) {
+                       spin_lock(&GlobalMid_Lock);
+                       if(pSesInfo->server->tcpStatus != CifsExiting)
+                               pSesInfo->server->tcpStatus = CifsGood;
+                       else
+                               rc = -EHOSTDOWN;
+                       spin_unlock(&GlobalMid_Lock);
+
+               }
        }
        if (!rc) {
                pSesInfo->capabilities = pSesInfo->server->capabilities;