]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/cifs/connect.c
Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6-omap-h63xx.git] / fs / cifs / connect.c
index a8d592bc33fe25c8bef37ff9d16353a30fa26aa7..e568cc47a7f93005518d1470696f89ee1444a1ae 100644 (file)
@@ -178,8 +178,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
                                        server->workstation_RFC1001_name);
                }
                if(rc) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(3 * HZ);
+                       msleep(3000);
                } else {
                        atomic_inc(&tcpSesReconnectCount);
                        spin_lock(&GlobalMid_Lock);
@@ -384,7 +383,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                if(server->tcpStatus == CifsExiting) {
                        break;
                } else if (server->tcpStatus == CifsNeedReconnect) {
-                       cFYI(1,("Reconnecting after server stopped responding"));
+                       cFYI(1,("Reconnect after server stopped responding"));
                        cifs_reconnect(server);
                        cFYI(1,("call to reconnect done"));
                        csocket = server->ssocket;
@@ -396,7 +395,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                        continue;
                } else if (length <= 0) {
                        if(server->tcpStatus == CifsNew) {
-                               cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
+                               cFYI(1,("tcp session abend after SMBnegprot"));
                                /* some servers kill the TCP session rather than
                                   returning an SMB negprot error, in which
                                   case reconnecting here is not going to help,
@@ -407,14 +406,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                cFYI(1,("cifsd thread killed"));
                                break;
                        }
-                       cFYI(1,("Reconnecting after unexpected peek error %d",length));
+                       cFYI(1,("Reconnect after unexpected peek error %d",
+                               length));
                        cifs_reconnect(server);
                        csocket = server->ssocket;
                        wake_up(&server->response_q);
                        continue;
                } else if (length < 4) {
                        cFYI(1,
-                           ("Frame less than four bytes received  %d bytes long.",
+                           ("Frame under four bytes received (%d bytes long)",
                              length));
                        cifs_reconnect(server);
                        csocket = server->ssocket;
@@ -544,15 +544,13 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                        if ((mid_entry->mid == smb_buffer->Mid) && 
                            (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
                            (mid_entry->command == smb_buffer->Command)) {
-                               cFYI(1,("Found Mid 0x%x wake", mid_entry->mid));
-                                       
                                if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
                                        /* We have a multipart transact2 resp */
+                                       isMultiRsp = TRUE;
                                        if(mid_entry->resp_buf) {
                                                /* merge response - fix up 1st*/
                                                if(coalesce_t2(smb_buffer, 
                                                        mid_entry->resp_buf)) {
-                                                       isMultiRsp = TRUE;
                                                        break;
                                                } else {
                                                        /* all parts received */
@@ -564,10 +562,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                        /* BB maybe we can fix this up,  switch
                                           to already allocated large buffer? */
                                                } else {
+                                                       /* Have first buffer */
                                                        mid_entry->resp_buf =
                                                                 smb_buffer;
                                                        mid_entry->largeBuf = 1;
-                                                       isMultiRsp = TRUE;
                                                        bigbuf = NULL;
                                                }
                                        }
@@ -586,13 +584,16 @@ multi_t2_fnd:
                }
                spin_unlock(&GlobalMid_Lock);
                if (task_to_wake) {
-                       if(isLargeBuf)
-                               bigbuf = NULL;
-                       else
-                               smallbuf = NULL;
-                       /* smb buffer freed by user thread when done */
+                       /* Was previous buf put in mpx struct for multi-rsp? */
+                       if(!isMultiRsp) {
+                               /* smb buffer will be freed by user thread */
+                               if(isLargeBuf) {
+                                       bigbuf = NULL;
+                               } else
+                                       smallbuf = NULL;
+                       }
                        wake_up_process(task_to_wake);
-               } else if ((is_valid_oplock_break(smb_buffer) == FALSE) 
+               } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
                    && (isMultiRsp == FALSE)) {                          
                        cERROR(1, ("No task to wake, unknown frame rcvd!"));
                        cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
@@ -602,7 +603,13 @@ multi_t2_fnd:
        spin_lock(&GlobalMid_Lock);
        server->tcpStatus = CifsExiting;
        server->tsk = NULL;
-       atomic_set(&server->inFlight, 0);
+       /* check if we have blocked requests that need to free */
+       /* Note that cifs_max_pending is normally 50, but
+       can be set at module install time to as little as two */
+       if(atomic_read(&server->inFlight) >= cifs_max_pending)
+               atomic_set(&server->inFlight, cifs_max_pending - 1);
+       /* We do not want to set the max_pending too low or we
+       could end up with the counter going negative */
        spin_unlock(&GlobalMid_Lock);
        /* Although there should not be any requests blocked on 
        this queue it can not hurt to be paranoid and try to wake up requests
@@ -638,6 +645,17 @@ multi_t2_fnd:
                }
                read_unlock(&GlobalSMBSeslock);
        } else {
+               /* although we can not zero the server struct pointer yet,
+               since there are active requests which may depnd on them,
+               mark the corresponding SMB sessions as exiting too */
+               list_for_each(tmp, &GlobalSMBSessionList) {
+                       ses = list_entry(tmp, struct cifsSesInfo,
+                                        cifsSessionList);
+                       if (ses->server == server) {
+                               ses->status = CifsExiting;
+                       }
+               }
+
                spin_lock(&GlobalMid_Lock);
                list_for_each(tmp, &server->pending_mid_q) {
                mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
@@ -659,17 +677,34 @@ multi_t2_fnd:
        if (list_empty(&server->pending_mid_q)) {
                /* mpx threads have not exited yet give them 
                at least the smb send timeout time for long ops */
+               /* due to delays on oplock break requests, we need
+               to wait at least 45 seconds before giving up
+               on a request getting a response and going ahead
+               and killing cifsd */
                cFYI(1, ("Wait for exit from demultiplex thread"));
-               msleep(46);
+               msleep(46000);
                /* if threads still have not exited they are probably never
                coming home not much else we can do but free the memory */
        }
-       kfree(server);
 
        write_lock(&GlobalSMBSeslock);
        atomic_dec(&tcpSesAllocCount);
        length = tcpSesAllocCount.counter;
+
+       /* last chance to mark ses pointers invalid
+       if there are any pointing to this (e.g
+       if a crazy root user tried to kill cifsd 
+       kernel thread explicitly this might happen) */
+       list_for_each(tmp, &GlobalSMBSessionList) {
+               ses = list_entry(tmp, struct cifsSesInfo,
+                               cifsSessionList);
+               if (ses->server == server) {
+                       ses->server = NULL;
+               }
+       }
        write_unlock(&GlobalSMBSeslock);
+
+       kfree(server);
        if(length  > 0) {
                mempool_resize(cifs_req_poolp,
                        length + cifs_min_rcv,