patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / fs / cifs / connect.c
index b36e95a..befbff5 100644 (file)
@@ -63,6 +63,7 @@ struct smb_vol {
        mode_t dir_mode;
        int rw:1;
        int retry:1;
+       int intr:1;
        unsigned int rsize;
        unsigned int wsize;
        unsigned int sockopt;
@@ -94,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 "));
@@ -121,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));
@@ -147,7 +155,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
                }
        }
        spin_unlock(&GlobalMid_Lock);
-
+       up(&server->tcpSem); 
 
        while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
        {
@@ -163,7 +171,11 @@ 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);
                }
        }
@@ -241,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);
@@ -266,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"));
@@ -278,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;
@@ -389,8 +405,16 @@ 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
+       that may haven been blocked when more than 50 at time were on the wire 
+       to the same server - they now will see the session is in exit state
+       and get out of SendReceive.  */
+       wake_up_all(&server->request_q);   
        server->tsk = NULL;
        if(server->ssocket) {
                sock_release(csocket);
@@ -587,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] = '\\';
@@ -699,6 +725,7 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
                                   (strnicmp(data, "exec", 4) == 0) ||
                                   (strnicmp(data, "noexec", 6) == 0) ||
                                   (strnicmp(data, "nodev", 5) == 0) ||
+                                  (strnicmp(data, "noauto", 6) == 0) ||
                                   (strnicmp(data, "dev", 3) == 0)) {
                        /*  The mount tool or mount.cifs helper (if present)
                                uses these opts to set flags, and the flags are read
@@ -717,6 +744,12 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
                        vol->retry = 0;
                } else if (strnicmp(data, "nosoft", 6) == 0) {
                        vol->retry = 1;
+               } else if (strnicmp(data, "nointr", 6) == 0) {
+                       vol->intr = 0;
+               } else if (strnicmp(data, "intr", 4) == 0) {
+                       vol->intr = 1;
+               } else if (strnicmp(data, "noac", 4) == 0) {
+                       printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
                } else
                        printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
        }
@@ -727,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] = '\\';
@@ -908,7 +943,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
                } else {
                /* BB other socket options to set KEEPALIVE, NODELAY? */
                        cFYI(1,("Socket created"));
-       /*              (*csocket)->sk->allocation = GFP_NOFS; */ /* BB is there equivalent in 2.6 */
+                       (*csocket)->sk->sk_allocation = GFP_NOFS; 
                }
        }
 
@@ -1015,6 +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;
                }
        }
 
@@ -1202,12 +1238,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        return rc;
                } else {
                        memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
-                       memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));       
-            /* BB Add code for ipv6 case too */
+                       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->protocolType = IPV4;
                        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,
@@ -1324,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) {
@@ -1516,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)
@@ -1769,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)
@@ -2080,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)
@@ -2476,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)
@@ -2675,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) <=
@@ -2743,6 +2787,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
                                FreeXid(xid);
                                return 0;
                        }
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule_timeout(HZ / 4);       /* give captive thread time to exit */
                        if((ses->server) && (ses->server->ssocket)) {            
@@ -2772,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 */ {
@@ -2780,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;