]> Pileus Git - ~andy/linux/blobdiff - fs/cifs/connect.c
Merge git://git.infradead.org/users/cbou/battery-3.1
[~andy/linux] / fs / cifs / connect.c
index e66297bad41231af902c99d386f654130b289020..633c246b67752efe0f7460cb01e8ac62309314e8 100644 (file)
@@ -319,25 +319,328 @@ requeue_echo:
        queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
 }
 
+static bool
+allocate_buffers(char **bigbuf, char **smallbuf, unsigned int size,
+                bool is_large_buf)
+{
+       char *bbuf = *bigbuf, *sbuf = *smallbuf;
+
+       if (bbuf == NULL) {
+               bbuf = (char *)cifs_buf_get();
+               if (!bbuf) {
+                       cERROR(1, "No memory for large SMB response");
+                       msleep(3000);
+                       /* retry will check if exiting */
+                       return false;
+               }
+       } else if (is_large_buf) {
+               /* we are reusing a dirty large buf, clear its start */
+               memset(bbuf, 0, size);
+       }
+
+       if (sbuf == NULL) {
+               sbuf = (char *)cifs_small_buf_get();
+               if (!sbuf) {
+                       cERROR(1, "No memory for SMB response");
+                       msleep(1000);
+                       /* retry will check if exiting */
+                       return false;
+               }
+               /* beginning of smb buffer is cleared in our buf_get */
+       } else {
+               /* if existing small buf clear beginning */
+               memset(sbuf, 0, size);
+       }
+
+       *bigbuf = bbuf;
+       *smallbuf = sbuf;
+
+       return true;
+}
+
+static int
+read_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg,
+                struct kvec *iov, unsigned int to_read,
+                unsigned int *ptotal_read, bool is_header_read)
+{
+       int length, rc = 0;
+       unsigned int total_read;
+       char *buf = iov->iov_base;
+
+       for (total_read = 0; total_read < to_read; total_read += length) {
+               length = kernel_recvmsg(server->ssocket, smb_msg, iov, 1,
+                                       to_read - total_read, 0);
+               if (server->tcpStatus == CifsExiting) {
+                       /* then will exit */
+                       rc = 2;
+                       break;
+               } else if (server->tcpStatus == CifsNeedReconnect) {
+                       cifs_reconnect(server);
+                       /* Reconnect wakes up rspns q */
+                       /* Now we will reread sock */
+                       rc = 1;
+                       break;
+               } else if (length == -ERESTARTSYS ||
+                          length == -EAGAIN ||
+                          length == -EINTR) {
+                       /*
+                        * Minimum sleep to prevent looping, allowing socket
+                        * to clear and app threads to set tcpStatus
+                        * CifsNeedReconnect if server hung.
+                        */
+                       usleep_range(1000, 2000);
+                       length = 0;
+                       if (!is_header_read)
+                               continue;
+                       /* Special handling for header read */
+                       if (total_read) {
+                               iov->iov_base = (to_read - total_read) +
+                                               buf;
+                               iov->iov_len = to_read - total_read;
+                               smb_msg->msg_control = NULL;
+                               smb_msg->msg_controllen = 0;
+                               rc = 3;
+                       } else
+                               rc = 1;
+                       break;
+               } else if (length <= 0) {
+                       cERROR(1, "Received no data, expecting %d",
+                              to_read - total_read);
+                       cifs_reconnect(server);
+                       rc = 1;
+                       break;
+               }
+       }
+
+       *ptotal_read = total_read;
+       return rc;
+}
+
+static bool
+check_rfc1002_header(struct TCP_Server_Info *server, char *buf)
+{
+       char temp = *buf;
+       unsigned int pdu_length = be32_to_cpu(
+                               ((struct smb_hdr *)buf)->smb_buf_length);
+
+       /*
+        * The first byte big endian of the length field,
+        * is actually not part of the length but the type
+        * with the most common, zero, as regular data.
+        */
+       if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
+               return false;
+       } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
+               cFYI(1, "Good RFC 1002 session rsp");
+               return false;
+       } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
+               /*
+                * We get this from Windows 98 instead of an error on
+                * SMB negprot response.
+                */
+               cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
+                       pdu_length);
+               /* give server a second to clean up */
+               msleep(1000);
+               /*
+                * Always try 445 first on reconnect since we get NACK
+                * on some if we ever connected to port 139 (the NACK
+                * is since we do not begin with RFC1001 session
+                * initialize frame).
+                */
+               cifs_set_port((struct sockaddr *)
+                               &server->dstaddr, CIFS_PORT);
+               cifs_reconnect(server);
+               wake_up(&server->response_q);
+               return false;
+       } else if (temp != (char) 0) {
+               cERROR(1, "Unknown RFC 1002 frame");
+               cifs_dump_mem(" Received Data: ", buf, 4);
+               cifs_reconnect(server);
+               return false;
+       }
+
+       /* else we have an SMB response */
+       if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
+           (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
+               cERROR(1, "Invalid size SMB length %d pdu_length %d",
+                      4, pdu_length+4);
+               cifs_reconnect(server);
+               wake_up(&server->response_q);
+               return false;
+       }
+
+       return true;
+}
+
+static struct mid_q_entry *
+find_cifs_mid(struct TCP_Server_Info *server, struct smb_hdr *buf,
+             int *length, bool is_large_buf, bool *is_multi_rsp, char **bigbuf)
+{
+       struct mid_q_entry *mid = NULL, *tmp_mid, *ret = NULL;
+
+       spin_lock(&GlobalMid_Lock);
+       list_for_each_entry_safe(mid, tmp_mid, &server->pending_mid_q, qhead) {
+               if (mid->mid != buf->Mid ||
+                   mid->midState != MID_REQUEST_SUBMITTED ||
+                   mid->command != buf->Command)
+                       continue;
+
+               if (*length == 0 && check2ndT2(buf, server->maxBuf) > 0) {
+                       /* We have a multipart transact2 resp */
+                       *is_multi_rsp = true;
+                       if (mid->resp_buf) {
+                               /* merge response - fix up 1st*/
+                               *length = coalesce_t2(buf, mid->resp_buf);
+                               if (*length > 0) {
+                                       *length = 0;
+                                       mid->multiRsp = true;
+                                       break;
+                               }
+                               /* All parts received or packet is malformed. */
+                               mid->multiEnd = true;
+                               goto multi_t2_fnd;
+                       }
+                       if (!is_large_buf) {
+                               /*FIXME: switch to already allocated largebuf?*/
+                               cERROR(1, "1st trans2 resp needs bigbuf");
+                       } else {
+                               /* Have first buffer */
+                               mid->resp_buf = buf;
+                               mid->largeBuf = true;
+                               *bigbuf = NULL;
+                       }
+                       break;
+               }
+               mid->resp_buf = buf;
+               mid->largeBuf = is_large_buf;
+multi_t2_fnd:
+               if (*length == 0)
+                       mid->midState = MID_RESPONSE_RECEIVED;
+               else
+                       mid->midState = MID_RESPONSE_MALFORMED;
+#ifdef CONFIG_CIFS_STATS2
+               mid->when_received = jiffies;
+#endif
+               list_del_init(&mid->qhead);
+               ret = mid;
+               break;
+       }
+       spin_unlock(&GlobalMid_Lock);
+
+       return ret;
+}
+
+static void clean_demultiplex_info(struct TCP_Server_Info *server)
+{
+       int length;
+
+       /* take it off the list, if it's not already */
+       spin_lock(&cifs_tcp_ses_lock);
+       list_del_init(&server->tcp_ses_list);
+       spin_unlock(&cifs_tcp_ses_lock);
+
+       spin_lock(&GlobalMid_Lock);
+       server->tcpStatus = CifsExiting;
+       spin_unlock(&GlobalMid_Lock);
+       wake_up_all(&server->response_q);
+
+       /*
+        * 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.
+        */
+       spin_lock(&GlobalMid_Lock);
+       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 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);
+       /* give those requests time to exit */
+       msleep(125);
+
+       if (server->ssocket) {
+               sock_release(server->ssocket);
+               server->ssocket = NULL;
+       }
+
+       if (!list_empty(&server->pending_mid_q)) {
+               struct list_head dispose_list;
+               struct mid_q_entry *mid_entry;
+               struct list_head *tmp, *tmp2;
+
+               INIT_LIST_HEAD(&dispose_list);
+               spin_lock(&GlobalMid_Lock);
+               list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
+                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+                       cFYI(1, "Clearing mid 0x%x", mid_entry->mid);
+                       mid_entry->midState = MID_SHUTDOWN;
+                       list_move(&mid_entry->qhead, &dispose_list);
+               }
+               spin_unlock(&GlobalMid_Lock);
+
+               /* now walk dispose list and issue callbacks */
+               list_for_each_safe(tmp, tmp2, &dispose_list) {
+                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+                       cFYI(1, "Callback mid 0x%x", mid_entry->mid);
+                       list_del_init(&mid_entry->qhead);
+                       mid_entry->callback(mid_entry);
+               }
+               /* 1/8th of sec is more than enough time for them to exit */
+               msleep(125);
+       }
+
+       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(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->hostname);
+       kfree(server);
+
+       length = atomic_dec_return(&tcpSesAllocCount);
+       if (length > 0)
+               mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
+                               GFP_KERNEL);
+}
+
 static int
 cifs_demultiplex_thread(void *p)
 {
        int length;
        struct TCP_Server_Info *server = p;
        unsigned int pdu_length, total_read;
+       char *buf = NULL, *bigbuf = NULL, *smallbuf = NULL;
        struct smb_hdr *smb_buffer = NULL;
-       struct smb_hdr *bigbuf = NULL;
-       struct smb_hdr *smallbuf = NULL;
        struct msghdr smb_msg;
        struct kvec iov;
-       struct socket *csocket = server->ssocket;
-       struct list_head *tmp, *tmp2;
        struct task_struct *task_to_wake = NULL;
        struct mid_q_entry *mid_entry;
-       char temp;
        bool isLargeBuf = false;
-       bool isMultiRsp;
-       int reconnect;
+       bool isMultiRsp = false;
+       int rc;
 
        current->flags |= PF_MEMALLOC;
        cFYI(1, "Demultiplex PID: %d", task_pid_nr(current));
@@ -351,35 +654,16 @@ cifs_demultiplex_thread(void *p)
        while (server->tcpStatus != CifsExiting) {
                if (try_to_freeze())
                        continue;
-               if (bigbuf == NULL) {
-                       bigbuf = cifs_buf_get();
-                       if (!bigbuf) {
-                               cERROR(1, "No memory for large SMB response");
-                               msleep(3000);
-                               /* retry will check if exiting */
-                               continue;
-                       }
-               } else if (isLargeBuf) {
-                       /* we are reusing a dirty large buf, clear its start */
-                       memset(bigbuf, 0, sizeof(struct smb_hdr));
-               }
 
-               if (smallbuf == NULL) {
-                       smallbuf = cifs_small_buf_get();
-                       if (!smallbuf) {
-                               cERROR(1, "No memory for SMB response");
-                               msleep(1000);
-                               /* retry will check if exiting */
-                               continue;
-                       }
-                       /* beginning of smb buffer is cleared in our buf_get */
-               } else /* if existing small buf clear beginning */
-                       memset(smallbuf, 0, sizeof(struct smb_hdr));
+               if (!allocate_buffers(&bigbuf, &smallbuf,
+                                     sizeof(struct smb_hdr), isLargeBuf))
+                       continue;
 
                isLargeBuf = false;
                isMultiRsp = false;
-               smb_buffer = smallbuf;
-               iov.iov_base = smb_buffer;
+               smb_buffer = (struct smb_hdr *)smallbuf;
+               buf = smallbuf;
+               iov.iov_base = buf;
                iov.iov_len = 4;
                smb_msg.msg_control = NULL;
                smb_msg.msg_controllen = 0;
@@ -393,158 +677,50 @@ incomplete_rcv:
                                  "Reconnecting...", server->hostname,
                                  (echo_retries * SMB_ECHO_INTERVAL / HZ));
                        cifs_reconnect(server);
-                       csocket = server->ssocket;
                        wake_up(&server->response_q);
                        continue;
                }
 
-               length =
-                   kernel_recvmsg(csocket, &smb_msg,
-                               &iov, 1, pdu_length, 0 /* BB other flags? */);
-
-               if (server->tcpStatus == CifsExiting) {
+               rc = read_from_socket(server, &smb_msg, &iov, pdu_length,
+                                     &total_read, true /* header read */);
+               if (rc == 3)
+                       goto incomplete_rcv;
+               else if (rc == 2)
                        break;
-               } else if (server->tcpStatus == CifsNeedReconnect) {
-                       cFYI(1, "Reconnect after server stopped responding");
-                       cifs_reconnect(server);
-                       cFYI(1, "call to reconnect done");
-                       csocket = server->ssocket;
-                       continue;
-               } else if (length == -ERESTARTSYS ||
-                          length == -EAGAIN ||
-                          length == -EINTR) {
-                       msleep(1); /* minimum sleep to prevent looping
-                               allowing socket to clear and app threads to set
-                               tcpStatus CifsNeedReconnect if server hung */
-                       if (pdu_length < 4) {
-                               iov.iov_base = (4 - pdu_length) +
-                                                       (char *)smb_buffer;
-                               iov.iov_len = pdu_length;
-                               smb_msg.msg_control = NULL;
-                               smb_msg.msg_controllen = 0;
-                               goto incomplete_rcv;
-                       } else
-                               continue;
-               } else if (length <= 0) {
-                       cFYI(1, "Reconnect after unexpected peek error %d",
-                               length);
-                       cifs_reconnect(server);
-                       csocket = server->ssocket;
-                       wake_up(&server->response_q);
+               else if (rc == 1)
                        continue;
-               } else if (length < pdu_length) {
-                       cFYI(1, "requested %d bytes but only got %d bytes",
-                                 pdu_length, length);
-                       pdu_length -= length;
-                       msleep(1);
-                       goto incomplete_rcv;
-               }
-
-               /* The right amount was read from socket - 4 bytes */
-               /* so we can now interpret the length field */
 
-               /* the first byte big endian of the length field,
-               is actually not part of the length but the type
-               with the most common, zero, as regular data */
-               temp = *((char *) smb_buffer);
+               /*
+                * The right amount was read from socket - 4 bytes,
+                * so we can now interpret the length field.
+                */
 
-               /* Note that FC 1001 length is big endian on the wire,
-               but we convert it here so it is always manipulated
-               as host byte order */
+               /*
+                * Note that RFC 1001 length is big endian on the wire,
+                * but we convert it here so it is always manipulated
+                * as host byte order.
+                */
                pdu_length = be32_to_cpu(smb_buffer->smb_buf_length);
 
                cFYI(1, "rfc1002 length 0x%x", pdu_length+4);
-
-               if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
-                       continue;
-               } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
-                       cFYI(1, "Good RFC 1002 session rsp");
-                       continue;
-               } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
-                       /* we get this from Windows 98 instead of
-                          an error on SMB negprot response */
-                       cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
-                               pdu_length);
-                       /* give server a second to clean up  */
-                       msleep(1000);
-                       /* always try 445 first on reconnect since we get NACK
-                        * on some if we ever connected to port 139 (the NACK
-                        * is since we do not begin with RFC1001 session
-                        * initialize frame)
-                        */
-                       cifs_set_port((struct sockaddr *)
-                                       &server->dstaddr, CIFS_PORT);
-                       cifs_reconnect(server);
-                       csocket = server->ssocket;
-                       wake_up(&server->response_q);
-                       continue;
-               } else if (temp != (char) 0) {
-                       cERROR(1, "Unknown RFC 1002 frame");
-                       cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
-                                     length);
-                       cifs_reconnect(server);
-                       csocket = server->ssocket;
+               if (!check_rfc1002_header(server, buf))
                        continue;
-               }
-
-               /* else we have an SMB response */
-               if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
-                           (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
-                       cERROR(1, "Invalid size SMB length %d pdu_length %d",
-                                       length, pdu_length+4);
-                       cifs_reconnect(server);
-                       csocket = server->ssocket;
-                       wake_up(&server->response_q);
-                       continue;
-               }
 
                /* else length ok */
-               reconnect = 0;
-
                if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
                        isLargeBuf = true;
                        memcpy(bigbuf, smallbuf, 4);
-                       smb_buffer = bigbuf;
+                       smb_buffer = (struct smb_hdr *)bigbuf;
+                       buf = bigbuf;
                }
-               length = 0;
-               iov.iov_base = 4 + (char *)smb_buffer;
+
+               iov.iov_base = 4 + buf;
                iov.iov_len = pdu_length;
-               for (total_read = 0; total_read < pdu_length;
-                    total_read += length) {
-                       length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
-                                               pdu_length - total_read, 0);
-                       if (server->tcpStatus == CifsExiting) {
-                               /* then will exit */
-                               reconnect = 2;
-                               break;
-                       } else if (server->tcpStatus == CifsNeedReconnect) {
-                               cifs_reconnect(server);
-                               csocket = server->ssocket;
-                               /* Reconnect wakes up rspns q */
-                               /* Now we will reread sock */
-                               reconnect = 1;
-                               break;
-                       } else if (length == -ERESTARTSYS ||
-                                  length == -EAGAIN ||
-                                  length == -EINTR) {
-                               msleep(1); /* minimum sleep to prevent looping,
-                                             allowing socket to clear and app
-                                             threads to set tcpStatus
-                                             CifsNeedReconnect if server hung*/
-                               length = 0;
-                               continue;
-                       } else if (length <= 0) {
-                               cERROR(1, "Received no data, expecting %d",
-                                             pdu_length - total_read);
-                               cifs_reconnect(server);
-                               csocket = server->ssocket;
-                               reconnect = 1;
-                               break;
-                       }
-               }
-               if (reconnect == 2)
+               rc = read_from_socket(server, &smb_msg, &iov, pdu_length,
+                                     &total_read, false);
+               if (rc == 2)
                        break;
-               else if (reconnect == 1)
+               else if (rc == 1)
                        continue;
 
                total_read += 4; /* account for rfc1002 hdr */
@@ -562,75 +738,13 @@ incomplete_rcv:
                 */
                length = checkSMB(smb_buffer, smb_buffer->Mid, total_read);
                if (length != 0)
-                       cifs_dump_mem("Bad SMB: ", smb_buffer,
-                                       min_t(unsigned int, total_read, 48));
+                       cifs_dump_mem("Bad SMB: ", buf,
+                                     min_t(unsigned int, total_read, 48));
 
-               mid_entry = NULL;
                server->lstrp = jiffies;
 
-               spin_lock(&GlobalMid_Lock);
-               list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
-                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-
-                       if (mid_entry->mid != smb_buffer->Mid ||
-                           mid_entry->midState != MID_REQUEST_SUBMITTED ||
-                           mid_entry->command != smb_buffer->Command) {
-                               mid_entry = NULL;
-                               continue;
-                       }
-
-                       if (length == 0 &&
-                           check2ndT2(smb_buffer, server->maxBuf) > 0) {
-                               /* We have a multipart transact2 resp */
-                               isMultiRsp = true;
-                               if (mid_entry->resp_buf) {
-                                       /* merge response - fix up 1st*/
-                                       length = coalesce_t2(smb_buffer,
-                                                       mid_entry->resp_buf);
-                                       if (length > 0) {
-                                               length = 0;
-                                               mid_entry->multiRsp = true;
-                                               break;
-                                       } else {
-                                               /* all parts received or
-                                                * packet is malformed
-                                                */
-                                               mid_entry->multiEnd = true;
-                                               goto multi_t2_fnd;
-                                       }
-                               } else {
-                                       if (!isLargeBuf) {
-                                               /*
-                                                * FIXME: switch to already
-                                                *        allocated largebuf?
-                                                */
-                                               cERROR(1, "1st trans2 resp "
-                                                         "needs bigbuf");
-                                       } else {
-                                               /* Have first buffer */
-                                               mid_entry->resp_buf =
-                                                        smb_buffer;
-                                               mid_entry->largeBuf = true;
-                                               bigbuf = NULL;
-                                       }
-                               }
-                               break;
-                       }
-                       mid_entry->resp_buf = smb_buffer;
-                       mid_entry->largeBuf = isLargeBuf;
-multi_t2_fnd:
-                       if (length == 0)
-                               mid_entry->midState = MID_RESPONSE_RECEIVED;
-                       else
-                               mid_entry->midState = MID_RESPONSE_MALFORMED;
-#ifdef CONFIG_CIFS_STATS2
-                       mid_entry->when_received = jiffies;
-#endif
-                       list_del_init(&mid_entry->qhead);
-                       break;
-               }
-               spin_unlock(&GlobalMid_Lock);
-
+               mid_entry = find_cifs_mid(server, smb_buffer, &length,
+                                         isLargeBuf, &isMultiRsp, &bigbuf);
                if (mid_entry != NULL) {
                        mid_entry->callback(mid_entry);
                        /* Was previous buf put in mpx struct for multi-rsp? */
@@ -648,7 +762,7 @@ multi_t2_fnd:
                           !isMultiRsp) {
                        cERROR(1, "No task to wake, unknown frame received! "
                                   "NumMids %d", atomic_read(&midCount));
-                       cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
+                       cifs_dump_mem("Received Data is: ", buf,
                                      sizeof(struct smb_hdr));
 #ifdef CONFIG_CIFS_DEBUG2
                        cifs_dump_detail(smb_buffer);
@@ -658,88 +772,13 @@ multi_t2_fnd:
                }
        } /* end while !EXITING */
 
-       /* take it off the list, if it's not already */
-       spin_lock(&cifs_tcp_ses_lock);
-       list_del_init(&server->tcp_ses_list);
-       spin_unlock(&cifs_tcp_ses_lock);
-
-       spin_lock(&GlobalMid_Lock);
-       server->tcpStatus = CifsExiting;
-       spin_unlock(&GlobalMid_Lock);
-       wake_up_all(&server->response_q);
-
-       /* 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 */
-       spin_lock(&GlobalMid_Lock);
-       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
-       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);
-       /* give those requests time to exit */
-       msleep(125);
-
-       if (server->ssocket) {
-               sock_release(csocket);
-               server->ssocket = NULL;
-       }
        /* buffer usually freed in free_mid - need to free it here on exit */
        cifs_buf_release(bigbuf);
        if (smallbuf) /* no sense logging a debug message if NULL */
                cifs_small_buf_release(smallbuf);
 
-       if (!list_empty(&server->pending_mid_q)) {
-               struct list_head dispose_list;
-
-               INIT_LIST_HEAD(&dispose_list);
-               spin_lock(&GlobalMid_Lock);
-               list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
-                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-                       cFYI(1, "Clearing mid 0x%x", mid_entry->mid);
-                       mid_entry->midState = MID_SHUTDOWN;
-                       list_move(&mid_entry->qhead, &dispose_list);
-               }
-               spin_unlock(&GlobalMid_Lock);
-
-               /* now walk dispose list and issue callbacks */
-               list_for_each_safe(tmp, tmp2, &dispose_list) {
-                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-                       cFYI(1, "Callback mid 0x%x", mid_entry->mid);
-                       list_del_init(&mid_entry->qhead);
-                       mid_entry->callback(mid_entry);
-               }
-               /* 1/8th of sec is more than enough time for them to exit */
-               msleep(125);
-       }
-
-       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(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->hostname);
        task_to_wake = xchg(&server->tsk, NULL);
-       kfree(server);
-
-       length = atomic_dec_return(&tcpSesAllocCount);
-       if (length  > 0)
-               mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
-                               GFP_KERNEL);
+       clean_demultiplex_info(server);
 
        /* if server->tsk was NULL then wait for a signal before exiting */
        if (!task_to_wake) {
@@ -2839,7 +2878,8 @@ cleanup_volume_info_contents(struct smb_vol *volume_info)
        kfree(volume_info->username);
        kzfree(volume_info->password);
        kfree(volume_info->UNC);
-       kfree(volume_info->UNCip);
+       if (volume_info->UNCip != volume_info->UNC + 2)
+               kfree(volume_info->UNCip);
        kfree(volume_info->domainname);
        kfree(volume_info->iocharset);
        kfree(volume_info->prepath);
@@ -3193,15 +3233,9 @@ mount_fail_check:
                else
                        cifs_put_tcp_session(srvTcp);
                bdi_destroy(&cifs_sb->bdi);
-               goto out;
        }
 
-       /* volume_info->password is freed above when existing session found
-       (in which case it is not needed anymore) but when new sesion is created
-       the password ptr is put in the new session structure (in which case the
-       password will be freed at unmount time) */
 out:
-       /* zero out password before freeing */
        FreeXid(xid);
        return rc;
 }