/*
* fs/cifs/connect.c
*
- * Copyright (C) International Business Machines Corp., 2002,2004
+ * Copyright (C) International Business Machines Corp., 2002,2005
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
#include <linux/ctype.h>
#include <linux/utsname.h>
#include <linux/mempool.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/pagevec.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include "cifspdu.h"
#define CIFS_PORT 445
#define RFC1001_PORT 139
+static DECLARE_COMPLETION(cifsd_complete);
+
extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
char *in6_addr; /* ipv6 address as human readable form of in6_addr */
char *iocharset; /* local code page for mapping to and from Unicode */
char source_rfc1001_name[16]; /* netbios name of client */
+ char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
uid_t linux_uid;
gid_t linux_gid;
mode_t file_mode;
unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
unsigned direct_io:1;
unsigned remap:1; /* set to remap seven reserved chars in filenames */
+ unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
+ unsigned sfu_emul:1;
+ unsigned nocase; /* request case insensitive filenames */
+ unsigned nobrl; /* disable sending byte range locks to srv */
unsigned int rsize;
unsigned int wsize;
unsigned int sockopt;
static int ipv4_connect(struct sockaddr_in *psin_server,
struct socket **csocket,
- char * netb_name);
+ char * netb_name,
+ char * server_netb_name);
static int ipv6_connect(struct sockaddr_in6 *psin_server,
struct socket **csocket);
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 */
qhead);
if(mid_entry) {
if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
- /* Mark other intransit requests as needing retry so
- we do not immediately mark the session bad again
- (ie after we reconnect below) as they timeout too */
+ /* Mark other intransit requests as needing
+ retry so we do not immediately mark the
+ session bad again (ie after we reconnect
+ below) as they timeout too */
mid_entry->midState = MID_RETRY_NEEDED;
}
}
} else {
rc = ipv4_connect(&server->addr.sockAddr,
&server->ssocket,
- server->workstation_RFC1001_name);
+ server->workstation_RFC1001_name,
+ server->server_RFC1001_name);
}
if(rc) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(3 * HZ);
+ cFYI(1,("reconnect error %d",rc));
+ msleep(3000);
} else {
atomic_inc(&tcpSesReconnectCount);
spin_lock(&GlobalMid_Lock);
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 = 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 = 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)
{
int length;
unsigned int pdu_length, total_read;
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 cifsSesInfo *ses;
struct task_struct *task_to_wake = NULL;
struct mid_q_entry *mid_entry;
- char *temp;
+ char temp;
+ int isLargeBuf = FALSE;
+ int isMultiRsp;
+ int reconnect;
daemonize("cifsd");
allow_signal(SIGKILL);
atomic_inc(&tcpSesAllocCount);
length = tcpSesAllocCount.counter;
write_unlock(&GlobalSMBSeslock);
+ complete(&cifsd_complete);
if(length > 1) {
mempool_resize(cifs_req_poolp,
length + cifs_min_rcv,
}
while (server->tcpStatus != CifsExiting) {
- if (smb_buffer == NULL)
- smb_buffer = cifs_buf_get();
- else
- memset(smb_buffer, 0, sizeof (struct smb_hdr));
-
- if (smb_buffer == NULL) {
- cERROR(1,("Can not get memory for SMB response"));
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ * 3); /* give system time to free memory */
+ if (try_to_freeze())
continue;
+ if (bigbuf == NULL) {
+ bigbuf = cifs_buf_get();
+ if(bigbuf == NULL) {
+ cERROR(1,("No memory for large SMB response"));
+ msleep(3000);
+ /* retry will check if exiting */
+ continue;
+ }
+ } else if(isLargeBuf) {
+ /* we are reusing a dirtry large buf, clear its start */
+ memset(bigbuf, 0, sizeof (struct smb_hdr));
}
+
+ if (smallbuf == NULL) {
+ smallbuf = cifs_small_buf_get();
+ if(smallbuf == NULL) {
+ 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));
+
+ isLargeBuf = FALSE;
+ isMultiRsp = FALSE;
+ smb_buffer = smallbuf;
iov.iov_base = smb_buffer;
iov.iov_len = 4;
smb_msg.msg_control = NULL;
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;
continue;
} else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1); /* minimum sleep to prevent looping
+ 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) {
if(server->tcpStatus == CifsNew) {
- cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
- /* some servers kill tcp session rather than returning
- smb negprot error in which case reconnecting here is
- not going to help - return error to mount */
+ 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,
+ and so simply return error to mount */
break;
}
if(length == -EINTR) {
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 > 3) {
- pdu_length = ntohl(smb_buffer->smb_buf_length);
- /* Only read pdu_length after below checks for too short (due
- to e.g. int overflow) and too long ie beyond end of buf */
- cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
-
- temp = (char *) smb_buffer;
- if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
- cFYI(0,("Received 4 byte keep alive packet"));
- } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
- cFYI(1,("Good RFC 1002 session rsp"));
- } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
- /* we get this from Windows 98 instead of error on SMB negprot response */
- cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
- if(server->tcpStatus == CifsNew) {
- /* if nack on negprot (rather than
- ret of smb negprot error) reconnecting
- not going to help, ret error to mount */
- break;
- } else {
- /* give server a second to
- clean up before reconnect attempt */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ);
- /* 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) */
- server->addr.sockAddr.sin_port = htons(CIFS_PORT);
- cifs_reconnect(server);
- csocket = server->ssocket;
- wake_up(&server->response_q);
- continue;
- }
- } else if (temp[0] != (char) 0) {
- cERROR(1,("Unknown RFC 1002 frame"));
- cifs_dump_mem(" Received Data: ", temp, length);
+ } else if (length < 4) {
+ cFYI(1,
+ ("Frame under four bytes received (%d bytes long)",
+ length));
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ wake_up(&server->response_q);
+ continue;
+ }
+
+ /* 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);
+
+ /* 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 */
+ pdu_length = ntohl(smb_buffer->smb_buf_length);
+ smb_buffer->smb_buf_length = pdu_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));
+ if(server->tcpStatus == CifsNew) {
+ /* if nack on negprot (rather than
+ ret of smb negprot error) reconnecting
+ not going to help, ret error to mount */
+ break;
+ } else {
+ /* give server a second to
+ clean up before reconnect attempt */
+ 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) */
+ server->addr.sockAddr.sin_port =
+ htons(CIFS_PORT);
cifs_reconnect(server);
csocket = server->ssocket;
+ wake_up(&server->response_q);
continue;
- } else {
- 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",
- length, pdu_length+4));
- cifs_reconnect(server);
- csocket = server->ssocket;
- wake_up(&server->response_q);
- continue;
- } else { /* length ok */
- 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 (length == 0) {
- cERROR(1,
- ("Zero length receive when expecting %d ",
- pdu_length - total_read));
- cifs_reconnect(server);
- csocket = server->ssocket;
- wake_up(&server->response_q);
- 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));
- task_to_wake = mid_entry->tsk;
- mid_entry->resp_buf =
- smb_buffer;
- mid_entry->midState =
- MID_RESPONSE_RECEIVED;
- }
- }
- spin_unlock(&GlobalMid_Lock);
- if (task_to_wake) {
- 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));
- }
}
- } else {
- cFYI(1,
- ("Frame less than four bytes received %d bytes long.",
- length));
+ } 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;
+ 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_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 */
+
+
+ dump_smb(smb_buffer, length);
+ if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
+ cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
+ 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)) {
+ 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)
+ mid_entry->largeBuf = 1;
+ else
+ mid_entry->largeBuf = 0;
+multi_t2_fnd:
+ task_to_wake = mid_entry->tsk;
+ mid_entry->midState = MID_RESPONSE_RECEIVED;
+#ifdef CONFIG_CIFS_STATS2
+ mid_entry->when_received = jiffies;
+#endif
+ 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;
+ }
+ 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: ",(char *)smb_buffer,
+ 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
- that may haven been blocked when more than 50 at time were on the wire
+ 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 */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/8);
-
+ msleep(125);
+
if(server->ssocket) {
sock_release(csocket);
server->ssocket = NULL;
}
- if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */
- cifs_buf_release(smb_buffer);
+ /* buffer usuallly freed in free_mid - need to free it here on exit */
+ if (bigbuf != NULL)
+ cifs_buf_release(bigbuf);
+ if (smallbuf != NULL)
+ cifs_small_buf_release(smallbuf);
read_lock(&GlobalSMBSeslock);
if (list_empty(&server->pending_mid_q)) {
- /* loop through server session structures attached to this and mark them dead */
+ /* loop through server session structures attached to this and
+ mark them dead */
list_for_each(tmp, &GlobalSMBSessionList) {
ses =
list_entry(tmp, struct cifsSesInfo,
}
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);
if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
cFYI(1,
- (" Clearing Mid 0x%x - waking up ",mid_entry->mid));
+ ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
task_to_wake = mid_entry->tsk;
if(task_to_wake) {
wake_up_process(task_to_wake);
}
spin_unlock(&GlobalMid_Lock);
read_unlock(&GlobalSMBSeslock);
- set_current_state(TASK_INTERRUPTIBLE);
/* 1/8th of sec is more than enough time for them to exit */
- schedule_timeout(HZ/8);
+ msleep(125);
}
- if (list_empty(&server->pending_mid_q)) {
+ 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"));
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(46 * HZ);
+ 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,
GFP_KERNEL);
}
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/4);
+
+ complete_and_exit(&cifsd_complete, 0);
return 0;
}
-static void *
-cifs_kcalloc(size_t size, unsigned int __nocast type)
-{
- void *addr;
- addr = kmalloc(size, type);
- if (addr)
- memset(addr, 0, size);
- return addr;
-}
-
static int
cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
{
/* does not have to be a perfect mapping since the field is
informational, only used for servers that do not support
port 445 and it can be overridden at mount time */
- vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]);
+ vol->source_rfc1001_name[i] =
+ toupper(system_utsname.nodename[i]);
}
vol->source_rfc1001_name[15] = 0;
-
+ /* null target name indicates to use *SMBSERVR default called name
+ if we end up sending RFC1001 session initialize */
+ vol->target_rfc1001_name[0] = 0;
vol->linux_uid = current->uid; /* current->euid instead? */
vol->linux_gid = current->gid;
vol->dir_mode = S_IRWXUGO;
/* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
vol->rw = TRUE;
+ /* default is always to request posix paths. */
+ vol->posix_paths = 1;
+
if (!options)
return 1;
/* NB: password legally can have multiple commas and
the only illegal character in a password is null */
- if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) {
+ if ((value[temp_len] == 0) &&
+ (value[temp_len+1] == separator[0])) {
/* reinsert comma */
value[temp_len] = separator[0];
temp_len+=2; /* move after the second comma */
while(value[temp_len] != 0) {
if (value[temp_len] == separator[0]) {
- if (value[temp_len+1] == separator[0]) {
- temp_len++; /* skip second comma */
+ if (value[temp_len+1] ==
+ separator[0]) {
+ /* skip second comma */
+ temp_len++;
} else {
/* single comma indicating start
of next parm */
/* 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 = cifs_kcalloc(temp_len, GFP_KERNEL);
+ vol->password = kzalloc(temp_len, GFP_KERNEL);
+ if(vol->password == NULL) {
+ printk("CIFS: no memory for pass\n");
+ return 1;
+ }
for(i=0,j=0;i<temp_len;i++,j++) {
vol->password[j] = value[i];
- if(value[i] == separator[0] && value[i+1] == separator[0]) {
+ if(value[i] == separator[0]
+ && value[i+1] == separator[0]) {
/* skip second comma */
i++;
}
}
vol->password[j] = 0;
} else {
- vol->password = cifs_kcalloc(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;
+ }
strcpy(vol->password, value);
}
} else if (strnicmp(data, "ip", 2) == 0) {
/* The string has 16th byte zero still from
set at top of the function */
if((i==15) && (value[i] != 0))
- printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
+ printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
+ }
+ } else if (strnicmp(data, "servern", 7) == 0) {
+ /* servernetbiosname specified override *SMBSERVER */
+ if (!value || !*value || (*value == ' ')) {
+ cFYI(1,("empty server netbiosname specified"));
+ } else {
+ /* last byte, type, is 0x20 for servr type */
+ memset(vol->target_rfc1001_name,0x20,16);
+
+ for(i=0;i<15;i++) {
+ /* BB are there cases in which a comma can be
+ valid in this workstation netbios name (and need
+ special handling)? */
+
+ /* user or mount helper must uppercase netbiosname */
+ if (value[i]==0)
+ break;
+ else
+ vol->target_rfc1001_name[i] = value[i];
+ }
+ /* The string has 16th byte zero still from
+ set at top of the function */
+ if((i==15) && (value[i] != 0))
+ printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
}
} else if (strnicmp(data, "credentials", 4) == 0) {
/* ignore */
vol->remap = 1;
} else if (strnicmp(data, "nomapchars", 10) == 0) {
vol->remap = 0;
+ } else if (strnicmp(data, "sfu", 3) == 0) {
+ vol->sfu_emul = 1;
+ } else if (strnicmp(data, "nosfu", 5) == 0) {
+ vol->sfu_emul = 0;
+ } else if (strnicmp(data, "posixpaths", 10) == 0) {
+ vol->posix_paths = 1;
+ } else if (strnicmp(data, "noposixpaths", 12) == 0) {
+ vol->posix_paths = 0;
+ } else if ((strnicmp(data, "nocase", 6) == 0) ||
+ (strnicmp(data, "ignorecase", 10) == 0)) {
+ vol->nocase = 1;
+ } else if (strnicmp(data, "brl", 3) == 0) {
+ vol->nobrl = 0;
+ } else if ((strnicmp(data, "nobrl", 5) == 0) ||
+ (strnicmp(data, "nolock", 6) == 0)) {
+ vol->nobrl = 1;
+ /* turn off mandatory locking in mode
+ if remote locking is turned off since the
+ local vfs will do advisory */
+ if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
+ vol->file_mode = S_IALLUGO;
} else if (strnicmp(data, "setuids", 7) == 0) {
vol->setuids = 1;
} else if (strnicmp(data, "nosetuids", 9) == 0) {
static int
ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
- char * netbios_name)
+ char * netbios_name, char * target_name)
{
int rc = 0;
int connected = 0;
/* Eventually check for other socket options to change from
the default. sock_setsockopt not used because it expects
user space buffer */
+ cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
+ (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
+ /* make the bufsizes depend on wsize/rsize and max requests */
+ if((*csocket)->sk->sk_sndbuf < (200 * 1024))
+ (*csocket)->sk->sk_sndbuf = 200 * 1024;
+ if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
+ (*csocket)->sk->sk_rcvbuf = 140 * 1024;
/* send RFC1001 sessinit */
-
if(psin_server->sin_port == htons(RFC1001_PORT)) {
/* some servers require RFC1001 sessinit before sending
negprot - BB check reconnection in case where second
sessinit is sent but no second negprot */
struct rfc1002_session_packet * ses_init_buf;
struct smb_hdr * smb_buf;
- ses_init_buf = cifs_kcalloc(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,
- DEFAULT_CIFS_CALLED_NAME,16);
+ if(target_name && (target_name[0] != 0)) {
+ rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
+ target_name, 16);
+ } else {
+ rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
+ DEFAULT_CIFS_CALLED_NAME,16);
+ }
+
ses_init_buf->trailer.session_req.calling_len = 32;
/* calling name ends in null (byte 16) from old smb
convention. */
sin_server.sin_port = htons(volume_info.port);
else
sin_server.sin_port = 0;
- rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
+ rc = ipv4_connect(&sin_server,&csocket,
+ volume_info.source_rfc1001_name,
+ volume_info.target_rfc1001_name);
if (rc < 0) {
cERROR(1,
("Error connecting to IPv4 socket. Aborting operation"));
kfree(volume_info.password);
FreeXid(xid);
return rc;
- } else
- rc = 0;
+ }
+ wait_for_completion(&cifsd_complete);
+ rc = 0;
memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
+ memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
srvTcp->sequence_number = 0;
}
}
/* search for existing tcon to this server share */
if (!rc) {
- if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
+ if(volume_info.rsize > CIFSMaxBufSize) {
+ cERROR(1,("rsize %d too large, using MaxBufSize",
+ volume_info.rsize));
+ cifs_sb->rsize = CIFSMaxBufSize;
+ } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
cifs_sb->rsize = volume_info.rsize;
- else
- cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
- if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
+ else /* default */
+ cifs_sb->rsize = CIFSMaxBufSize;
+
+ if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
+ cERROR(1,("wsize %d too large using 4096 instead",
+ volume_info.wsize));
+ cifs_sb->wsize = 4096;
+ } else if(volume_info.wsize)
cifs_sb->wsize = volume_info.wsize;
else
cifs_sb->wsize = CIFSMaxBufSize; /* default */
if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
- cifs_sb->rsize = PAGE_CACHE_SIZE;
- cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
+ cifs_sb->rsize = PAGE_CACHE_SIZE;
+ /* Windows ME does this */
+ cFYI(1,("Attempt to set readsize for mount to less than one page (4096)"));
}
cifs_sb->mnt_uid = volume_info.linux_uid;
cifs_sb->mnt_gid = volume_info.linux_gid;
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
if(volume_info.no_xattr)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
+ if(volume_info.sfu_emul)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
+ if(volume_info.nobrl)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
+
if(volume_info.direct_io) {
- cERROR(1,("mounting share using direct i/o"));
+ cFYI(1,("mounting share using direct i/o"));
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
}
to the same server share the last value passed in
for the retry flag is used */
tcon->retry = volume_info.retry;
+ tcon->nocase = volume_info.nocase;
} else {
tcon = tconInfoAlloc();
if (tcon == NULL)
if (!rc) {
atomic_inc(&pSesInfo->inUse);
tcon->retry = volume_info.retry;
+ tcon->nocase = volume_info.nocase;
}
}
}
spin_lock(&GlobalMid_Lock);
srvTcp->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock);
- if(srvTcp->tsk)
+ if(srvTcp->tsk) {
send_sig(SIGKILL,srvTcp->tsk,1);
+ wait_for_completion(&cifsd_complete);
+ }
}
/* If find_unc succeeded then rc == 0 so we can not end */
if (tcon) /* up accidently freeing someone elses tcon struct */
temp_rc = CIFSSMBLogoff(xid, pSesInfo);
/* if the socketUseCount is now zero */
if((temp_rc == -ESHUTDOWN) &&
- (pSesInfo->server->tsk))
+ (pSesInfo->server->tsk)) {
send_sig(SIGKILL,pSesInfo->server->tsk,1);
+ wait_for_completion(&cifsd_complete);
+ }
} else
cFYI(1, ("No session or bad tcon"));
sesInfoFree(pSesInfo);
cFYI(1,("server negotiated posix acl support"));
sb->s_flags |= MS_POSIXACL;
}
+
+ /* Try and negotiate POSIX pathnames if we can. */
+ if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
+ le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+ if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
+ cFYI(1,("negotiated posix pathnames support"));
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
+ } else {
+ cFYI(1,("posix pathnames support requested but not supported"));
+ }
+ }
}
}
+ if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
+ cifs_sb->wsize = min(cifs_sb->wsize,
+ (tcon->ses->server->maxBuf -
+ MAX_CIFS_HDR_SIZE));
+ if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
+ cifs_sb->rsize = min(cifs_sb->rsize,
+ (tcon->ses->server->maxBuf -
+ MAX_CIFS_HDR_SIZE));
}
/* volume_info.password is freed above when existing session found
header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
NULL /* no tCon exists yet */ , 13 /* wct */ );
+ smb_buffer->Mid = GetNextMid(ses->server);
pSMB->req_no_secext.AndXCommand = 0xFF;
pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
/* 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 = cifs_kcalloc(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,
(wchar_t *)bcc_ptr, len,nls_codepage);
bcc_ptr += 2 * (len + 1);
if (remaining_words > 0) {
len = UniStrnlen((wchar_t *)bcc_ptr,
remaining_words-1);
- ses->serverNOS =cifs_kcalloc(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,
(wchar_t *)bcc_ptr,len,nls_codepage);
bcc_ptr += 2 * (len + 1);
}
remaining_words -= len + 1;
if (remaining_words > 0) {
- len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
+ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */
ses->serverDomain =
- cifs_kcalloc(2*(len+1),GFP_KERNEL);
+ kzalloc(2*(len+1),GFP_KERNEL);
+ if(ses->serverDomain == NULL)
+ goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverDomain,
(wchar_t *)bcc_ptr,len,nls_codepage);
bcc_ptr += 2 * (len + 1);
ses->serverDomain[1+(2*len)] = 0;
} /* else no more room so create dummy domain string */
else
- ses->serverDomain =
- cifs_kcalloc(2,
- GFP_KERNEL);
+ ses->serverDomain =
+ 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 =
- cifs_kcalloc(2, GFP_KERNEL);
+ kzalloc(2, GFP_KERNEL);
ses->serverNOS =
- cifs_kcalloc(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 = cifs_kcalloc(len + 1,GFP_KERNEL);
+ ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
+ if(ses->serverOS == NULL)
+ goto sesssetup_nomem;
strncpy(ses->serverOS,bcc_ptr, len);
bcc_ptr += len;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+ ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
+ if(ses->serverNOS == NULL)
+ goto sesssetup_nomem;
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL);
+ ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
+ if(ses->serverDomain == NULL)
+ goto sesssetup_nomem;
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
smb_buffer_response->WordCount));
rc = -EIO;
}
-
+sesssetup_nomem: /* do not return an error on nomem for the info strings,
+ since that could make reconnection harder, and
+ reconnection might be needed to free memory */
if (smb_buffer)
cifs_buf_release(smb_buffer);
/* send SMBsessionSetup here */
header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+ smb_buffer->Mid = GetNextMid(ses->server);
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
pSMB->req.AndXCommand = 0xFF;
pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
ses->serverOS =
- cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ kzalloc(2 * (len + 1), GFP_KERNEL);
cifs_strfromUCS_le(ses->serverOS,
(wchar_t *)
bcc_ptr, len,
remaining_words
- 1);
ses->serverNOS =
- cifs_kcalloc(2 * (len + 1),
+ kzalloc(2 * (len + 1),
GFP_KERNEL);
cifs_strfromUCS_le(ses->serverNOS,
(wchar_t *)bcc_ptr,
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 = cifs_kcalloc(2*(len+1),GFP_KERNEL);
+ ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
cifs_strfromUCS_le(ses->serverDomain,
(wchar_t *)bcc_ptr,
len,
} /* else no more room so create dummy domain string */
else
ses->serverDomain =
- cifs_kcalloc(2,GFP_KERNEL);
+ kzalloc(2,GFP_KERNEL);
} else { /* no room so create dummy domain and NOS string */
- ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
- ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
+ ses->serverDomain = kzalloc(2, GFP_KERNEL);
+ ses->serverNOS = kzalloc(2, GFP_KERNEL);
}
} else { /* ASCII */
if (((long) bcc_ptr + len) - (long)
pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
- ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL);
+ ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
strncpy(ses->serverOS, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverNOS = cifs_kcalloc(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 = cifs_kcalloc(len + 1, GFP_KERNEL);
+ ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
/* send SMBsessionSetup here */
header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+ smb_buffer->Mid = GetNextMid(ses->server);
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
ses->serverOS =
- cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ kzalloc(2 * (len + 1), GFP_KERNEL);
cifs_strfromUCS_le(ses->serverOS,
(wchar_t *)
bcc_ptr, len,
remaining_words
- 1);
ses->serverNOS =
- cifs_kcalloc(2 * (len + 1),
+ kzalloc(2 * (len + 1),
GFP_KERNEL);
cifs_strfromUCS_le(ses->
serverNOS,
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */
ses->serverDomain =
- cifs_kcalloc(2 *
+ kzalloc(2 *
(len +
1),
GFP_KERNEL);
} /* else no more room so create dummy domain string */
else
ses->serverDomain =
- cifs_kcalloc(2,
+ kzalloc(2,
GFP_KERNEL);
} else { /* no room so create dummy domain and NOS string */
ses->serverDomain =
- cifs_kcalloc(2, GFP_KERNEL);
+ kzalloc(2, GFP_KERNEL);
ses->serverNOS =
- cifs_kcalloc(2, GFP_KERNEL);
+ kzalloc(2, GFP_KERNEL);
}
} else { /* ASCII */
len = strnlen(bcc_ptr, 1024);
pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
ses->serverOS =
- cifs_kcalloc(len + 1,
+ kzalloc(len + 1,
GFP_KERNEL);
strncpy(ses->serverOS,
bcc_ptr, len);
len = strnlen(bcc_ptr, 1024);
ses->serverNOS =
- cifs_kcalloc(len + 1,
+ kzalloc(len + 1,
GFP_KERNEL);
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len;
len = strnlen(bcc_ptr, 1024);
ses->serverDomain =
- cifs_kcalloc(len + 1,
+ kzalloc(len + 1,
GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
/* send SMBsessionSetup here */
header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+ smb_buffer->Mid = GetNextMid(ses->server);
pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
pSMB->req.AndXCommand = 0xFF;
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
ses->serverOS =
- cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ kzalloc(2 * (len + 1), GFP_KERNEL);
cifs_strfromUCS_le(ses->serverOS,
(wchar_t *)
bcc_ptr, len,
remaining_words
- 1);
ses->serverNOS =
- cifs_kcalloc(2 * (len + 1),
+ kzalloc(2 * (len + 1),
GFP_KERNEL);
cifs_strfromUCS_le(ses->
serverNOS,
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string not always null terminated (e.g. for Windows XP & 2000) */
ses->serverDomain =
- cifs_kcalloc(2 *
+ kzalloc(2 *
(len +
1),
GFP_KERNEL);
= 0;
} /* else no more room so create dummy domain string */
else
- ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
+ ses->serverDomain = kzalloc(2,GFP_KERNEL);
} else { /* no room so create dummy domain and NOS string */
- ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
- ses->serverNOS = cifs_kcalloc(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 = cifs_kcalloc(len + 1,GFP_KERNEL);
+ ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
strncpy(ses->serverOS,bcc_ptr, len);
bcc_ptr += len;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverNOS = cifs_kcalloc(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 = cifs_kcalloc(len+1,GFP_KERNEL);
+ ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
NULL /*no tid */ , 4 /*wct */ );
+
+ smb_buffer->Mid = GetNextMid(ses->server);
smb_buffer->Uid = ses->Suid;
pSMB = (TCONX_REQ *) smb_buffer;
pSMBr = (TCONX_RSP *) smb_buffer_response;
if(tcon->nativeFileSystem)
kfree(tcon->nativeFileSystem);
tcon->nativeFileSystem =
- cifs_kcalloc(length + 2, GFP_KERNEL);
+ kzalloc(length + 2, GFP_KERNEL);
cifs_strfromUCS_le(tcon->nativeFileSystem,
(wchar_t *) bcc_ptr,
length, nls_codepage);
if(tcon->nativeFileSystem)
kfree(tcon->nativeFileSystem);
tcon->nativeFileSystem =
- cifs_kcalloc(length + 1, GFP_KERNEL);
+ kzalloc(length + 1, GFP_KERNEL);
strncpy(tcon->nativeFileSystem, bcc_ptr,
length);
}
return 0;
} else if (rc == -ESHUTDOWN) {
cFYI(1,("Waking up socket by sending it signal"));
- if(cifsd_task)
+ if(cifsd_task) {
send_sig(SIGKILL,cifsd_task,1);
+ wait_for_completion(&cifsd_complete);
+ }
rc = 0;
} /* else - we have an smb session
left on this socket do not kill cifsd */
}
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);