Merge master.kernel.org:/home/rmk/linux-2.6-arm
[pandora-kernel.git] / fs / cifs / connect.c
index 419f145..2335f14 100644 (file)
@@ -116,7 +116,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
        spin_unlock(&GlobalMid_Lock);
        server->maxBuf = 0;
 
-       cFYI(1, ("Reconnecting tcp session "));
+       cFYI(1, ("Reconnecting tcp session"));
 
        /* before reconnecting the tcp session, mark the smb session (uid)
                and the tid bad so they are not used until reconnected */
@@ -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);
@@ -194,6 +193,121 @@ cifs_reconnect(struct TCP_Server_Info *server)
        return rc;
 }
 
+/* 
+       return codes:
+               0       not a transact2, or all data present
+               >0      transact2 with that much data missing
+               -EINVAL = invalid transact2
+
+ */
+static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
+{
+       struct smb_t2_rsp * pSMBt;
+        int total_data_size;
+       int data_in_this_rsp;
+       int remaining;
+
+       if(pSMB->Command != SMB_COM_TRANSACTION2)
+               return 0;
+
+        /* check for plausible wct, bcc and t2 data and parm sizes */
+        /* check for parm and data offset going beyond end of smb */
+       if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
+               cFYI(1,("invalid transact2 word count"));
+               return -EINVAL;
+       }
+
+       pSMBt = (struct smb_t2_rsp *)pSMB;
+
+       total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
+       data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
+
+       remaining = total_data_size - data_in_this_rsp;
+
+       if(remaining == 0)
+               return 0;
+       else if(remaining < 0) {
+               cFYI(1,("total data %d smaller than data in frame %d",
+                       total_data_size, data_in_this_rsp));
+               return -EINVAL;
+       } else {
+               cFYI(1,("missing %d bytes from transact2, check next response",
+                       remaining));
+               if(total_data_size > maxBufSize) {
+                       cERROR(1,("TotalDataSize %d is over maximum buffer %d",
+                               total_data_size,maxBufSize));
+                       return -EINVAL; 
+               }
+               return remaining;
+       }
+}
+
+static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
+{
+       struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
+       struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)pTargetSMB;
+       int total_data_size;
+       int total_in_buf;
+       int remaining;
+       int total_in_buf2;
+       char * data_area_of_target;
+       char * data_area_of_buf2;
+       __u16 byte_count;
+
+       total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
+
+       if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
+               cFYI(1,("total data sizes of primary and secondary t2 differ"));
+       }
+
+       total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
+
+       remaining = total_data_size - total_in_buf;
+       
+       if(remaining < 0)
+               return -EINVAL;
+
+       if(remaining == 0) /* nothing to do, ignore */
+               return 0;
+       
+       total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
+       if(remaining < total_in_buf2) {
+               cFYI(1,("transact2 2nd response contains too much data"));
+       }
+
+       /* find end of first SMB data area */
+       data_area_of_target = (char *)&pSMBt->hdr.Protocol + 
+                               le16_to_cpu(pSMBt->t2_rsp.DataOffset);
+       /* validate target area */
+
+       data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
+                                        le16_to_cpu(pSMB2->t2_rsp.DataOffset);
+
+       data_area_of_target += total_in_buf;
+
+       /* copy second buffer into end of first buffer */
+       memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
+       total_in_buf += total_in_buf2;
+       pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
+       byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
+       byte_count += total_in_buf2;
+       BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
+
+       byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
+       byte_count += total_in_buf2;
+
+       /* BB also add check that we are not beyond maximum buffer size */
+               
+       pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
+
+       if(remaining == total_in_buf2) {
+               cFYI(1,("found the last secondary response"));
+               return 0; /* we are done */
+       } else /* more responses to go */
+               return 1;
+
+}
+
 static int
 cifs_demultiplex_thread(struct TCP_Server_Info *server)
 {
@@ -211,6 +325,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        struct mid_q_entry *mid_entry;
        char *temp;
        int isLargeBuf = FALSE;
+       int isMultiRsp;
+       int reconnect;
 
        daemonize("cifsd");
        allow_signal(SIGKILL);
@@ -254,6 +370,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                        memset(smallbuf, 0, sizeof (struct smb_hdr));
 
                isLargeBuf = FALSE;
+               isMultiRsp = FALSE;
                smb_buffer = smallbuf;
                iov.iov_base = smb_buffer;
                iov.iov_len = 4;
@@ -266,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;
@@ -278,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,
@@ -289,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;
@@ -311,13 +429,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 
                temp = (char *) smb_buffer;
                if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
-                       cFYI(0,("Received 4 byte keep alive packet"));
+                       continue; 
                } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
-                               cFYI(1,("Good RFC 1002 session rsp"));
+                       cFYI(1,("Good RFC 1002 session rsp"));
+                       continue;
                } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
                        /* we get this from Windows 98 instead of 
                           an error on SMB negprot response */
-                       cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
+                       cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
+                               temp[4]));
                        if(server->tcpStatus == CifsNew) {
                                /* if nack on negprot (rather than 
                                ret of smb negprot error) reconnecting
@@ -345,122 +465,151 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                        cifs_reconnect(server);
                        csocket = server->ssocket;
                        continue;
-               } else { /* we have an SMB response */
-                       if((pdu_length > CIFSMaxBufSize + 
-                               MAX_CIFS_HDR_SIZE - 4) ||
+               }
+
+               /* 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 and pdu_length %d",
+                       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_HDR_SIZE - 4) {
+                       isLargeBuf = TRUE;
+                       memcpy(bigbuf, smallbuf, 4);
+                       smb_buffer = bigbuf;
+               }
+               length = 0;
+               iov.iov_base = 4 + (char *)smb_buffer;
+               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) ||
+                           (length == -EINTR)) {
+                               /* then will exit */
+                               reconnect = 2;
+                               break;
+                       } else if (server->tcpStatus == CifsNeedReconnect) {
                                cifs_reconnect(server);
                                csocket = server->ssocket;
-                               wake_up(&server->response_q);
+                               /* Reconnect wakes up rspns q */
+                               /* Now we will reread sock */
+                               reconnect = 1;
+                               break;
+                       } else if ((length == -ERESTARTSYS) || 
+                                  (length == -EAGAIN)) {
+                               msleep(1); /* minimum sleep to prevent looping,
+                                              allowing socket to clear and app 
+                                             threads to set tcpStatus
+                                             CifsNeedReconnect if server hung*/
                                continue;
-                       } else { /* length ok */
-                               int reconnect = 0;
-
-                               if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
-                                       isLargeBuf = TRUE;
-                                       memcpy(bigbuf, smallbuf, 4);
-                                       smb_buffer = bigbuf;
-                               }
-                               length = 0;
-                               iov.iov_base = 4 + (char *)smb_buffer;
-                               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) ||
-                                           (length == -EINTR)) {
-                                               /* 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)) {
-                                               msleep(1); /* minimum sleep to prevent looping
-                                                              allowing socket to clear and app threads to set
-                                                              tcpStatus CifsNeedReconnect if server hung */
-                                               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)
-                                   break;
-                               else if(reconnect == 1)
-                                   continue;
-
-                               length += 4; /* account for rfc1002 hdr */
+                       } 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)
+                       break;
+               else if(reconnect == 1)
+                       continue;
 
-                       dump_smb(smb_buffer, length);
-                       if (checkSMB
-                           (smb_buffer, smb_buffer->Mid, total_read+4)) {
-                               cERROR(1, ("Bad SMB Received "));
-                               continue;
-                       }
+               length += 4; /* account for rfc1002 hdr */
+       
 
+               dump_smb(smb_buffer, length);
+               if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
+                       cERROR(1, ("Bad SMB Received "));
+                       continue;
+               }
 
-                       task_to_wake = NULL;
-                       spin_lock(&GlobalMid_Lock);
-                       list_for_each(tmp, &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)) {
-                                       cFYI(1,("Found Mid 0x%x wake up"
-                                               ,mid_entry->mid));
-                                       /* BB FIXME - missing code here BB */
-                                       /* check_2nd_t2(smb_buffer); */
-                                       task_to_wake = mid_entry->tsk;
-                                       mid_entry->resp_buf =
-                                           smb_buffer;
-                                       mid_entry->midState =
-                                           MID_RESPONSE_RECEIVED;
-                                       if(isLargeBuf)
-                                               mid_entry->largeBuf = 1;
-                                       else
-                                               mid_entry->largeBuf = 0;
-                               }
-                       }
-                       spin_unlock(&GlobalMid_Lock);
-                       if (task_to_wake) {
+
+               task_to_wake = NULL;
+               spin_lock(&GlobalMid_Lock);
+               list_for_each(tmp, &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)) {
+                               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)) {
+                                                       break;
+                                               } else {
+                                                       /* all parts received */
+                                                       goto multi_t2_fnd; 
+                                               }
+                                       } else {
+                                               if(!isLargeBuf) {
+                                                       cERROR(1,("1st trans2 resp needs bigbuf"));
+                                       /* 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;
+                                                       bigbuf = NULL;
+                                               }
+                                       }
+                                       break;
+                               } 
+                               mid_entry->resp_buf = smb_buffer;
                                if(isLargeBuf)
-                                       bigbuf = NULL;
+                                       mid_entry->largeBuf = 1;
                                else
+                                       mid_entry->largeBuf = 0;
+multi_t2_fnd:
+                               task_to_wake = mid_entry->tsk;
+                               mid_entry->midState = MID_RESPONSE_RECEIVED;
+                               break;
+                       }
+               }
+               spin_unlock(&GlobalMid_Lock);
+               if (task_to_wake) {
+                       /* 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;
-                               smb_buffer = NULL; /* will be freed by users thread after he is done */
-                               wake_up_process(task_to_wake);
-                       } else if (is_valid_oplock_break(smb_buffer) == FALSE) {                          
-                               cERROR(1, ("No task to wake, unknown frame rcvd!"));
-                               cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
                        }
+                       wake_up_process(task_to_wake);
+               } 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));
                }
-       }
+       } /* end while !EXITING */
+
        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
@@ -496,6 +645,17 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                }
                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);
@@ -517,17 +677,34 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        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,
@@ -659,7 +836,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                /* go from value to value + temp_len condensing 
                                double commas to singles. Note that this ends up
                                allocating a few bytes too many, which is ok */
-                               vol->password = kcalloc(1, temp_len, GFP_KERNEL);
+                               vol->password = kzalloc(temp_len, GFP_KERNEL);
                                if(vol->password == NULL) {
                                        printk("CIFS: no memory for pass\n");
                                        return 1;
@@ -674,7 +851,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                }
                                vol->password[j] = 0;
                        } else {
-                               vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
+                               vol->password = kzalloc(temp_len+1, GFP_KERNEL);
                                if(vol->password == NULL) {
                                        printk("CIFS: no memory for pass\n");
                                        return 1;
@@ -1140,7 +1317,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
                sessinit is sent but no second negprot */
                struct rfc1002_session_packet * ses_init_buf;
                struct smb_hdr * smb_buf;
-               ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
+               ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
                if(ses_init_buf) {
                        ses_init_buf->trailer.session_req.called_len = 32;
                        rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
@@ -1787,7 +1964,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 /* We look for obvious messed up bcc or strings in response so we do not go off
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
-                               ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+                               ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
                                if(ses->serverOS == NULL)
                                        goto sesssetup_nomem;
                                cifs_strfromUCS_le(ses->serverOS,
@@ -1799,7 +1976,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                if (remaining_words > 0) {
                                        len = UniStrnlen((wchar_t *)bcc_ptr,
                                                         remaining_words-1);
-                                       ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
+                                       ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
                                        if(ses->serverNOS == NULL)
                                                goto sesssetup_nomem;
                                        cifs_strfromUCS_le(ses->serverNOS,
@@ -1817,7 +1994,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
           /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
                                                ses->serverDomain =
-                                                   kcalloc(1, 2*(len+1),GFP_KERNEL);
+                                                   kzalloc(2*(len+1),GFP_KERNEL);
                                                if(ses->serverDomain == NULL)
                                                        goto sesssetup_nomem;
                                                cifs_strfromUCS_le(ses->serverDomain,
@@ -1828,22 +2005,22 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        } /* else no more room so create dummy domain string */
                                        else
                                                ses->serverDomain = 
-                                                       kcalloc(1, 2, GFP_KERNEL);
+                                                       kzalloc(2, GFP_KERNEL);
                                } else {        /* no room so create dummy domain and NOS string */
                                        /* if these kcallocs fail not much we
                                           can do, but better to not fail the
                                           sesssetup itself */
                                        ses->serverDomain =
-                                           kcalloc(1, 2, GFP_KERNEL);
+                                           kzalloc(2, GFP_KERNEL);
                                        ses->serverNOS =
-                                           kcalloc(1, 2, GFP_KERNEL);
+                                           kzalloc(2, GFP_KERNEL);
                                }
                        } else {        /* ASCII */
                                len = strnlen(bcc_ptr, 1024);
                                if (((long) bcc_ptr + len) - (long)
                                    pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
-                                       ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
+                                       ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverOS == NULL)
                                                goto sesssetup_nomem;
                                        strncpy(ses->serverOS,bcc_ptr, len);
@@ -1853,7 +2030,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        bcc_ptr++;
 
                                        len = strnlen(bcc_ptr, 1024);
-                                       ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
+                                       ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverNOS == NULL)
                                                goto sesssetup_nomem;
                                        strncpy(ses->serverNOS, bcc_ptr, len);
@@ -1862,7 +2039,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        bcc_ptr++;
 
                                        len = strnlen(bcc_ptr, 1024);
-                                       ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
+                                       ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverDomain == NULL)
                                                goto sesssetup_nomem;
                                        strncpy(ses->serverDomain, bcc_ptr, len);
@@ -2063,7 +2240,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
                                        ses->serverOS =
-                                           kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+                                           kzalloc(2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
                                                           (wchar_t *)
                                                           bcc_ptr, len,
@@ -2077,7 +2254,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                 remaining_words
                                                                 - 1);
                                                ses->serverNOS =
-                                                   kcalloc(1, 2 * (len + 1),
+                                                   kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
                                                cifs_strfromUCS_le(ses->serverNOS,
                                                                   (wchar_t *)bcc_ptr,
@@ -2090,7 +2267,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                if (remaining_words > 0) {
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
                             /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
-                                                       ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
+                                                       ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
                                                        cifs_strfromUCS_le(ses->serverDomain,
                                                             (wchar_t *)bcc_ptr, 
                                  len,
@@ -2101,10 +2278,10 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                } /* else no more room so create dummy domain string */
                                                else
                                                        ses->serverDomain =
-                                                           kcalloc(1, 2,GFP_KERNEL);
+                                                           kzalloc(2,GFP_KERNEL);
                                        } else {        /* no room so create dummy domain and NOS string */
-                                               ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
-                                               ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
+                                               ses->serverDomain = kzalloc(2, GFP_KERNEL);
+                                               ses->serverNOS = kzalloc(2, GFP_KERNEL);
                                        }
                                } else {        /* ASCII */
 
@@ -2112,7 +2289,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        if (((long) bcc_ptr + len) - (long)
                                            pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
-                                               ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
+                                               ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
                                                strncpy(ses->serverOS, bcc_ptr, len);
 
                                                bcc_ptr += len;
@@ -2120,14 +2297,14 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
+                                               ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
                                                strncpy(ses->serverNOS, bcc_ptr, len);
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
+                                               ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
                                                strncpy(ses->serverDomain, bcc_ptr, len);
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
@@ -2377,7 +2554,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
                                        ses->serverOS =
-                                           kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+                                           kzalloc(2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
                                                           (wchar_t *)
                                                           bcc_ptr, len,
@@ -2392,7 +2569,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                                 remaining_words
                                                                 - 1);
                                                ses->serverNOS =
-                                                   kcalloc(1, 2 * (len + 1),
+                                                   kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
                                                cifs_strfromUCS_le(ses->
                                                                   serverNOS,
@@ -2409,7 +2586,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
                                                        ses->serverDomain =
-                                                           kcalloc(1, 2 *
+                                                           kzalloc(2 *
                                                                    (len +
                                                                     1),
                                                                    GFP_KERNEL);
@@ -2435,13 +2612,13 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                } /* else no more room so create dummy domain string */
                                                else
                                                        ses->serverDomain =
-                                                           kcalloc(1, 2,
+                                                           kzalloc(2,
                                                                    GFP_KERNEL);
                                        } else {        /* no room so create dummy domain and NOS string */
                                                ses->serverDomain =
-                                                   kcalloc(1, 2, GFP_KERNEL);
+                                                   kzalloc(2, GFP_KERNEL);
                                                ses->serverNOS =
-                                                   kcalloc(1, 2, GFP_KERNEL);
+                                                   kzalloc(2, GFP_KERNEL);
                                        }
                                } else {        /* ASCII */
                                        len = strnlen(bcc_ptr, 1024);
@@ -2449,7 +2626,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                            pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
                                                ses->serverOS =
-                                                   kcalloc(1, len + 1,
+                                                   kzalloc(len + 1,
                                                            GFP_KERNEL);
                                                strncpy(ses->serverOS,
                                                        bcc_ptr, len);
@@ -2460,7 +2637,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 
                                                len = strnlen(bcc_ptr, 1024);
                                                ses->serverNOS =
-                                                   kcalloc(1, len + 1,
+                                                   kzalloc(len + 1,
                                                            GFP_KERNEL);
                                                strncpy(ses->serverNOS, bcc_ptr, len);
                                                bcc_ptr += len;
@@ -2469,7 +2646,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 
                                                len = strnlen(bcc_ptr, 1024);
                                                ses->serverDomain =
-                                                   kcalloc(1, len + 1,
+                                                   kzalloc(len + 1,
                                                            GFP_KERNEL);
                                                strncpy(ses->serverDomain, bcc_ptr, len);       
                                                bcc_ptr += len;
@@ -2771,7 +2948,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
   the end since (at least) WIN2K and Windows XP have a major bug in not null
   terminating last Unicode string in response  */
                                        ses->serverOS =
-                                           kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+                                           kzalloc(2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
                                                           (wchar_t *)
                                                           bcc_ptr, len,
@@ -2786,7 +2963,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                 remaining_words
                                                                 - 1);
                                                ses->serverNOS =
-                                                   kcalloc(1, 2 * (len + 1),
+                                                   kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
                                                cifs_strfromUCS_le(ses->
                                                                   serverNOS,
@@ -2802,7 +2979,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
      /* last string not always null terminated (e.g. for Windows XP & 2000) */
                                                        ses->serverDomain =
-                                                           kcalloc(1, 2 *
+                                                           kzalloc(2 *
                                                                    (len +
                                                                     1),
                                                                    GFP_KERNEL);
@@ -2827,17 +3004,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                            = 0;
                                                } /* else no more room so create dummy domain string */
                                                else
-                                                       ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
+                                                       ses->serverDomain = kzalloc(2,GFP_KERNEL);
                                        } else {  /* no room so create dummy domain and NOS string */
-                                               ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
-                                               ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
+                                               ses->serverDomain = kzalloc(2, GFP_KERNEL);
+                                               ses->serverNOS = kzalloc(2, GFP_KERNEL);
                                        }
                                } else {        /* ASCII */
                                        len = strnlen(bcc_ptr, 1024);
                                        if (((long) bcc_ptr + len) - 
                         (long) pByteArea(smb_buffer_response) 
                             <= BCC(smb_buffer_response)) {
-                                               ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
+                                               ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
                                                strncpy(ses->serverOS,bcc_ptr, len);
 
                                                bcc_ptr += len;
@@ -2845,14 +3022,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
+                                               ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
                                                strncpy(ses->serverNOS, bcc_ptr, len);  
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
+                                               ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
                                                strncpy(ses->serverDomain, bcc_ptr, len);
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
@@ -2964,7 +3141,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                                if(tcon->nativeFileSystem)
                                        kfree(tcon->nativeFileSystem);
                                tcon->nativeFileSystem =
-                                   kcalloc(1, length + 2, GFP_KERNEL);
+                                   kzalloc(length + 2, GFP_KERNEL);
                                cifs_strfromUCS_le(tcon->nativeFileSystem,
                                                   (wchar_t *) bcc_ptr,
                                                   length, nls_codepage);
@@ -2982,7 +3159,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                                if(tcon->nativeFileSystem)
                                        kfree(tcon->nativeFileSystem);
                                tcon->nativeFileSystem =
-                                   kcalloc(1, length + 1, GFP_KERNEL);
+                                   kzalloc(length + 1, GFP_KERNEL);
                                strncpy(tcon->nativeFileSystem, bcc_ptr,
                                        length);
                        }
@@ -3038,10 +3215,8 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
        }
        
        cifs_sb->tcon = NULL;
-       if (ses) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ / 2);
-       }
+       if (ses)
+               schedule_timeout_interruptible(msecs_to_jiffies(500));
        if (ses)
                sesInfoFree(ses);