1
0
Fork 0

Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  CIFS: Cleanup demupltiplex thread exiting code
  CIFS: Move mid search to a separate function
  CIFS: Move RFC1002 check to a separate function
  CIFS: Simplify socket reading in demultiplex thread
  CIFS: Move buffer allocation to a separate function
  cifs: remove unneeded variable initialization in cifs_reconnect_tcon
  cifs: simplify refcounting for oplock breaks
  cifs: fix compiler warning in CIFSSMBQAllEAs
  cifs: fix name parsing in CIFSSMBQAllEAs
  cifs: don't start signing too early
  cifs: trivial: goto out here is unnecessary
  cifs: advertise the right receive buffer size to the server
hifive-unleashed-5.1
Linus Torvalds 2011-08-01 06:14:25 -10:00
commit 5f66d2b58c
9 changed files with 394 additions and 400 deletions

View File

@ -87,9 +87,15 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
if ((cifs_pdu == NULL) || (server == NULL))
return -EINVAL;
if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
server->tcpStatus == CifsNeedNegotiate)
return rc;
if (!server->session_estab) {
strncpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
return rc;
}
cifs_pdu->Signature.Sequence.SequenceNumber =
cpu_to_le32(server->sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0;
@ -178,9 +184,15 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
if ((cifs_pdu == NULL) || (server == NULL))
return -EINVAL;
if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
server->tcpStatus == CifsNeedNegotiate)
return rc;
if (!server->session_estab) {
strncpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
return rc;
}
cifs_pdu->Signature.Sequence.SequenceNumber =
cpu_to_le32(server->sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0;

View File

@ -86,24 +86,6 @@ extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
extern mempool_t *cifs_mid_poolp;
void
cifs_sb_active(struct super_block *sb)
{
struct cifs_sb_info *server = CIFS_SB(sb);
if (atomic_inc_return(&server->active) == 1)
atomic_inc(&sb->s_active);
}
void
cifs_sb_deactive(struct super_block *sb)
{
struct cifs_sb_info *server = CIFS_SB(sb);
if (atomic_dec_and_test(&server->active))
deactivate_super(sb);
}
static int
cifs_read_super(struct super_block *sb)
{

View File

@ -41,10 +41,6 @@ extern struct file_system_type cifs_fs_type;
extern const struct address_space_operations cifs_addr_ops;
extern const struct address_space_operations cifs_addr_ops_smallbuf;
/* Functions related to super block operations */
extern void cifs_sb_active(struct super_block *sb);
extern void cifs_sb_deactive(struct super_block *sb);
/* Functions related to inodes */
extern const struct inode_operations cifs_dir_inode_ops;
extern struct inode *cifs_root_iget(struct super_block *);

View File

@ -942,8 +942,6 @@ GLOBAL_EXTERN spinlock_t siduidlock;
GLOBAL_EXTERN spinlock_t sidgidlock;
void cifs_oplock_break(struct work_struct *work);
void cifs_oplock_break_get(struct cifsFileInfo *cfile);
void cifs_oplock_break_put(struct cifsFileInfo *cfile);
extern const struct slow_work_ops cifs_oplock_break_ops;

View File

@ -107,7 +107,7 @@ static void mark_open_files_invalid(struct cifs_tcon *pTcon)
static int
cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
{
int rc = 0;
int rc;
struct cifs_ses *ses;
struct TCP_Server_Info *server;
struct nls_table *nls_codepage;
@ -5720,6 +5720,7 @@ CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
char *temp_ptr;
char *end_of_smb;
__u16 params, byte_count, data_offset;
unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
cFYI(1, "In Query All EAs path %s", searchName);
QAllEAsRetry:
@ -5837,7 +5838,8 @@ QAllEAsRetry:
}
if (ea_name) {
if (strncmp(ea_name, temp_ptr, name_len) == 0) {
if (ea_name_len == name_len &&
strncmp(ea_name, temp_ptr, name_len) == 0) {
temp_ptr += name_len + 1;
rc = value_len;
if (buf_size == 0)

View File

@ -319,344 +319,221 @@ requeue_echo:
queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
}
static int
cifs_demultiplex_thread(void *p)
static bool
allocate_buffers(char **bigbuf, char **smallbuf, unsigned int size,
bool is_large_buf)
{
int length;
struct TCP_Server_Info *server = p;
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 list_head *tmp, *tmp2;
struct task_struct *task_to_wake = NULL;
struct mid_q_entry *mid_entry;
char temp;
bool isLargeBuf = false;
bool isMultiRsp;
int reconnect;
char *bbuf = *bigbuf, *sbuf = *smallbuf;
current->flags |= PF_MEMALLOC;
cFYI(1, "Demultiplex PID: %d", task_pid_nr(current));
length = atomic_inc_return(&tcpSesAllocCount);
if (length > 1)
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
GFP_KERNEL);
set_freezable();
while (server->tcpStatus != CifsExiting) {
if (try_to_freeze())
continue;
if (bigbuf == NULL) {
bigbuf = cifs_buf_get();
if (!bigbuf) {
cERROR(1, "No memory for large SMB response");
msleep(3000);
/* retry will check if exiting */
continue;
}
} else if (isLargeBuf) {
/* we are reusing a dirty large buf, clear its start */
memset(bigbuf, 0, sizeof(struct smb_hdr));
if (bbuf == NULL) {
bbuf = (char *)cifs_buf_get();
if (!bbuf) {
cERROR(1, "No memory for large SMB response");
msleep(3000);
/* retry will check if exiting */
return false;
}
} else if (is_large_buf) {
/* we are reusing a dirty large buf, clear its start */
memset(bbuf, 0, size);
}
if (smallbuf == NULL) {
smallbuf = cifs_small_buf_get();
if (!smallbuf) {
cERROR(1, "No memory for SMB response");
msleep(1000);
/* retry will check if exiting */
continue;
}
/* beginning of smb buffer is cleared in our buf_get */
} else /* if existing small buf clear beginning */
memset(smallbuf, 0, sizeof(struct smb_hdr));
isLargeBuf = false;
isMultiRsp = false;
smb_buffer = smallbuf;
iov.iov_base = smb_buffer;
iov.iov_len = 4;
smb_msg.msg_control = NULL;
smb_msg.msg_controllen = 0;
pdu_length = 4; /* enough to get RFC1001 header */
incomplete_rcv:
if (echo_retries > 0 && server->tcpStatus == CifsGood &&
time_after(jiffies, server->lstrp +
(echo_retries * SMB_ECHO_INTERVAL))) {
cERROR(1, "Server %s has not responded in %d seconds. "
"Reconnecting...", server->hostname,
(echo_retries * SMB_ECHO_INTERVAL / HZ));
cifs_reconnect(server);
csocket = server->ssocket;
wake_up(&server->response_q);
continue;
if (sbuf == NULL) {
sbuf = (char *)cifs_small_buf_get();
if (!sbuf) {
cERROR(1, "No memory for SMB response");
msleep(1000);
/* retry will check if exiting */
return false;
}
/* beginning of smb buffer is cleared in our buf_get */
} else {
/* if existing small buf clear beginning */
memset(sbuf, 0, size);
}
length =
kernel_recvmsg(csocket, &smb_msg,
&iov, 1, pdu_length, 0 /* BB other flags? */);
*bigbuf = bbuf;
*smallbuf = sbuf;
return true;
}
static int
read_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg,
struct kvec *iov, unsigned int to_read,
unsigned int *ptotal_read, bool is_header_read)
{
int length, rc = 0;
unsigned int total_read;
char *buf = iov->iov_base;
for (total_read = 0; total_read < to_read; total_read += length) {
length = kernel_recvmsg(server->ssocket, smb_msg, iov, 1,
to_read - total_read, 0);
if (server->tcpStatus == CifsExiting) {
/* then will exit */
rc = 2;
break;
} else if (server->tcpStatus == CifsNeedReconnect) {
cFYI(1, "Reconnect after server stopped responding");
cifs_reconnect(server);
cFYI(1, "call to reconnect done");
csocket = server->ssocket;
continue;
/* Reconnect wakes up rspns q */
/* Now we will reread sock */
rc = 1;
break;
} else if (length == -ERESTARTSYS ||
length == -EAGAIN ||
length == -EINTR) {
msleep(1); /* minimum sleep to prevent looping
allowing socket to clear and app threads to set
tcpStatus CifsNeedReconnect if server hung */
if (pdu_length < 4) {
iov.iov_base = (4 - pdu_length) +
(char *)smb_buffer;
iov.iov_len = pdu_length;
smb_msg.msg_control = NULL;
smb_msg.msg_controllen = 0;
goto incomplete_rcv;
} else
continue;
} else if (length <= 0) {
cFYI(1, "Reconnect after unexpected peek error %d",
length);
cifs_reconnect(server);
csocket = server->ssocket;
wake_up(&server->response_q);
continue;
} else if (length < pdu_length) {
cFYI(1, "requested %d bytes but only got %d bytes",
pdu_length, length);
pdu_length -= length;
msleep(1);
goto incomplete_rcv;
}
/* The right amount was read from socket - 4 bytes */
/* so we can now interpret the length field */
/* the first byte big endian of the length field,
is actually not part of the length but the type
with the most common, zero, as regular data */
temp = *((char *) smb_buffer);
/* 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 = be32_to_cpu(smb_buffer->smb_buf_length);
cFYI(1, "rfc1002 length 0x%x", pdu_length+4);
if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
continue;
} else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
cFYI(1, "Good RFC 1002 session rsp");
continue;
} else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
/* we get this from Windows 98 instead of
an error on SMB negprot response */
cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
pdu_length);
/* give server a second to clean up */
msleep(1000);
/* always try 445 first on reconnect since we get NACK
* on some if we ever connected to port 139 (the NACK
* is since we do not begin with RFC1001 session
* initialize frame)
/*
* Minimum sleep to prevent looping, allowing socket
* to clear and app threads to set tcpStatus
* CifsNeedReconnect if server hung.
*/
cifs_set_port((struct sockaddr *)
&server->dstaddr, CIFS_PORT);
cifs_reconnect(server);
csocket = server->ssocket;
wake_up(&server->response_q);
continue;
} else if (temp != (char) 0) {
cERROR(1, "Unknown RFC 1002 frame");
cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
length);
cifs_reconnect(server);
csocket = server->ssocket;
continue;
}
/* else we have an SMB response */
if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
(pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
cERROR(1, "Invalid size SMB length %d pdu_length %d",
length, pdu_length+4);
cifs_reconnect(server);
csocket = server->ssocket;
wake_up(&server->response_q);
continue;
}
/* else length ok */
reconnect = 0;
if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
isLargeBuf = true;
memcpy(bigbuf, smallbuf, 4);
smb_buffer = bigbuf;
}
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) {
/* then will exit */
reconnect = 2;
break;
} else if (server->tcpStatus == CifsNeedReconnect) {
cifs_reconnect(server);
csocket = server->ssocket;
/* Reconnect wakes up rspns q */
/* Now we will reread sock */
reconnect = 1;
break;
} else if (length == -ERESTARTSYS ||
length == -EAGAIN ||
length == -EINTR) {
msleep(1); /* minimum sleep to prevent looping,
allowing socket to clear and app
threads to set tcpStatus
CifsNeedReconnect if server hung*/
length = 0;
usleep_range(1000, 2000);
length = 0;
if (!is_header_read)
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)
/* Special handling for header read */
if (total_read) {
iov->iov_base = (to_read - total_read) +
buf;
iov->iov_len = to_read - total_read;
smb_msg->msg_control = NULL;
smb_msg->msg_controllen = 0;
rc = 3;
} else
rc = 1;
break;
else if (reconnect == 1)
continue;
} else if (length <= 0) {
cERROR(1, "Received no data, expecting %d",
to_read - total_read);
cifs_reconnect(server);
rc = 1;
break;
}
}
total_read += 4; /* account for rfc1002 hdr */
*ptotal_read = total_read;
return rc;
}
dump_smb(smb_buffer, total_read);
static bool
check_rfc1002_header(struct TCP_Server_Info *server, char *buf)
{
char temp = *buf;
unsigned int pdu_length = be32_to_cpu(
((struct smb_hdr *)buf)->smb_buf_length);
/*
* The first byte big endian of the length field,
* is actually not part of the length but the type
* with the most common, zero, as regular data.
*/
if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
return false;
} else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
cFYI(1, "Good RFC 1002 session rsp");
return false;
} else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
/*
* We know that we received enough to get to the MID as we
* checked the pdu_length earlier. Now check to see
* if the rest of the header is OK. We borrow the length
* var for the rest of the loop to avoid a new stack var.
*
* 48 bytes is enough to display the header and a little bit
* into the payload for debugging purposes.
* We get this from Windows 98 instead of an error on
* SMB negprot response.
*/
length = checkSMB(smb_buffer, smb_buffer->Mid, total_read);
if (length != 0)
cifs_dump_mem("Bad SMB: ", smb_buffer,
min_t(unsigned int, total_read, 48));
cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
pdu_length);
/* give server a second to clean up */
msleep(1000);
/*
* Always try 445 first on reconnect since we get NACK
* on some if we ever connected to port 139 (the NACK
* is since we do not begin with RFC1001 session
* initialize frame).
*/
cifs_set_port((struct sockaddr *)
&server->dstaddr, CIFS_PORT);
cifs_reconnect(server);
wake_up(&server->response_q);
return false;
} else if (temp != (char) 0) {
cERROR(1, "Unknown RFC 1002 frame");
cifs_dump_mem(" Received Data: ", buf, 4);
cifs_reconnect(server);
return false;
}
mid_entry = NULL;
server->lstrp = jiffies;
/* else we have an SMB response */
if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
(pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
cERROR(1, "Invalid size SMB length %d pdu_length %d",
4, pdu_length+4);
cifs_reconnect(server);
wake_up(&server->response_q);
return false;
}
spin_lock(&GlobalMid_Lock);
list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
return true;
}
if (mid_entry->mid != smb_buffer->Mid ||
mid_entry->midState != MID_REQUEST_SUBMITTED ||
mid_entry->command != smb_buffer->Command) {
mid_entry = NULL;
continue;
}
static struct mid_q_entry *
find_cifs_mid(struct TCP_Server_Info *server, struct smb_hdr *buf,
int *length, bool is_large_buf, bool *is_multi_rsp, char **bigbuf)
{
struct mid_q_entry *mid = NULL, *tmp_mid, *ret = NULL;
if (length == 0 &&
check2ndT2(smb_buffer, server->maxBuf) > 0) {
/* We have a multipart transact2 resp */
isMultiRsp = true;
if (mid_entry->resp_buf) {
/* merge response - fix up 1st*/
length = coalesce_t2(smb_buffer,
mid_entry->resp_buf);
if (length > 0) {
length = 0;
mid_entry->multiRsp = true;
break;
} else {
/* all parts received or
* packet is malformed
*/
mid_entry->multiEnd = true;
goto multi_t2_fnd;
}
} else {
if (!isLargeBuf) {
/*
* FIXME: switch to already
* allocated largebuf?
*/
cERROR(1, "1st trans2 resp "
"needs bigbuf");
} else {
/* Have first buffer */
mid_entry->resp_buf =
smb_buffer;
mid_entry->largeBuf = true;
bigbuf = NULL;
}
spin_lock(&GlobalMid_Lock);
list_for_each_entry_safe(mid, tmp_mid, &server->pending_mid_q, qhead) {
if (mid->mid != buf->Mid ||
mid->midState != MID_REQUEST_SUBMITTED ||
mid->command != buf->Command)
continue;
if (*length == 0 && check2ndT2(buf, server->maxBuf) > 0) {
/* We have a multipart transact2 resp */
*is_multi_rsp = true;
if (mid->resp_buf) {
/* merge response - fix up 1st*/
*length = coalesce_t2(buf, mid->resp_buf);
if (*length > 0) {
*length = 0;
mid->multiRsp = true;
break;
}
break;
/* All parts received or packet is malformed. */
mid->multiEnd = true;
goto multi_t2_fnd;
}
if (!is_large_buf) {
/*FIXME: switch to already allocated largebuf?*/
cERROR(1, "1st trans2 resp needs bigbuf");
} else {
/* Have first buffer */
mid->resp_buf = buf;
mid->largeBuf = true;
*bigbuf = NULL;
}
mid_entry->resp_buf = smb_buffer;
mid_entry->largeBuf = isLargeBuf;
multi_t2_fnd:
if (length == 0)
mid_entry->midState = MID_RESPONSE_RECEIVED;
else
mid_entry->midState = MID_RESPONSE_MALFORMED;
#ifdef CONFIG_CIFS_STATS2
mid_entry->when_received = jiffies;
#endif
list_del_init(&mid_entry->qhead);
break;
}
spin_unlock(&GlobalMid_Lock);
mid->resp_buf = buf;
mid->largeBuf = is_large_buf;
multi_t2_fnd:
if (*length == 0)
mid->midState = MID_RESPONSE_RECEIVED;
else
mid->midState = MID_RESPONSE_MALFORMED;
#ifdef CONFIG_CIFS_STATS2
mid->when_received = jiffies;
#endif
list_del_init(&mid->qhead);
ret = mid;
break;
}
spin_unlock(&GlobalMid_Lock);
if (mid_entry != NULL) {
mid_entry->callback(mid_entry);
/* 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;
}
} else if (length != 0) {
/* response sanity checks failed */
continue;
} else if (!is_valid_oplock_break(smb_buffer, server) &&
!isMultiRsp) {
cERROR(1, "No task to wake, unknown frame received! "
"NumMids %d", atomic_read(&midCount));
cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
sizeof(struct smb_hdr));
#ifdef CONFIG_CIFS_DEBUG2
cifs_dump_detail(smb_buffer);
cifs_dump_mids(server);
#endif /* CIFS_DEBUG2 */
return ret;
}
}
} /* end while !EXITING */
static void clean_demultiplex_info(struct TCP_Server_Info *server)
{
int length;
/* take it off the list, if it's not already */
spin_lock(&cifs_tcp_ses_lock);
@ -668,35 +545,39 @@ multi_t2_fnd:
spin_unlock(&GlobalMid_Lock);
wake_up_all(&server->response_q);
/* check if we have blocked requests that need to free */
/* Note that cifs_max_pending is normally 50, but
can be set at module install time to as little as two */
/*
* Check if we have blocked requests that need to free. Note that
* cifs_max_pending is normally 50, but can be set at module install
* time to as little as two.
*/
spin_lock(&GlobalMid_Lock);
if (atomic_read(&server->inFlight) >= cifs_max_pending)
atomic_set(&server->inFlight, cifs_max_pending - 1);
/* We do not want to set the max_pending too low or we
could end up with the counter going negative */
/*
* We do not want to set the max_pending too low or we could end up
* with the counter going negative.
*/
spin_unlock(&GlobalMid_Lock);
/* Although there should not be any requests blocked on
this queue it can not hurt to be paranoid and try to wake up requests
that may haven been blocked when more than 50 at time were on the wire
to the same server - they now will see the session is in exit state
and get out of SendReceive. */
/*
* Although there should not be any requests blocked on this queue it
* can not hurt to be paranoid and try to wake up requests that may
* haven been blocked when more than 50 at time were on the wire to the
* same server - they now will see the session is in exit state and get
* out of SendReceive.
*/
wake_up_all(&server->request_q);
/* give those requests time to exit */
msleep(125);
if (server->ssocket) {
sock_release(csocket);
sock_release(server->ssocket);
server->ssocket = NULL;
}
/* buffer usually freed in free_mid - need to free it here on exit */
cifs_buf_release(bigbuf);
if (smallbuf) /* no sense logging a debug message if NULL */
cifs_small_buf_release(smallbuf);
if (!list_empty(&server->pending_mid_q)) {
struct list_head dispose_list;
struct mid_q_entry *mid_entry;
struct list_head *tmp, *tmp2;
INIT_LIST_HEAD(&dispose_list);
spin_lock(&GlobalMid_Lock);
@ -720,26 +601,184 @@ multi_t2_fnd:
}
if (!list_empty(&server->pending_mid_q)) {
/* mpx threads have not exited yet give them
at least the smb send timeout time for long ops */
/* due to delays on oplock break requests, we need
to wait at least 45 seconds before giving up
on a request getting a response and going ahead
and killing cifsd */
/*
* mpx threads have not exited yet give them at least the smb
* send timeout time for long ops.
*
* Due to delays on oplock break requests, we need to wait at
* least 45 seconds before giving up on a request getting a
* response and going ahead and killing cifsd.
*/
cFYI(1, "Wait for exit from demultiplex thread");
msleep(46000);
/* if threads still have not exited they are probably never
coming home not much else we can do but free the memory */
/*
* If threads still have not exited they are probably never
* coming home not much else we can do but free the memory.
*/
}
kfree(server->hostname);
task_to_wake = xchg(&server->tsk, NULL);
kfree(server);
length = atomic_dec_return(&tcpSesAllocCount);
if (length > 0)
if (length > 0)
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
GFP_KERNEL);
}
static int
cifs_demultiplex_thread(void *p)
{
int length;
struct TCP_Server_Info *server = p;
unsigned int pdu_length, total_read;
char *buf = NULL, *bigbuf = NULL, *smallbuf = NULL;
struct smb_hdr *smb_buffer = NULL;
struct msghdr smb_msg;
struct kvec iov;
struct task_struct *task_to_wake = NULL;
struct mid_q_entry *mid_entry;
bool isLargeBuf = false;
bool isMultiRsp = false;
int rc;
current->flags |= PF_MEMALLOC;
cFYI(1, "Demultiplex PID: %d", task_pid_nr(current));
length = atomic_inc_return(&tcpSesAllocCount);
if (length > 1)
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
GFP_KERNEL);
set_freezable();
while (server->tcpStatus != CifsExiting) {
if (try_to_freeze())
continue;
if (!allocate_buffers(&bigbuf, &smallbuf,
sizeof(struct smb_hdr), isLargeBuf))
continue;
isLargeBuf = false;
isMultiRsp = false;
smb_buffer = (struct smb_hdr *)smallbuf;
buf = smallbuf;
iov.iov_base = buf;
iov.iov_len = 4;
smb_msg.msg_control = NULL;
smb_msg.msg_controllen = 0;
pdu_length = 4; /* enough to get RFC1001 header */
incomplete_rcv:
if (echo_retries > 0 && server->tcpStatus == CifsGood &&
time_after(jiffies, server->lstrp +
(echo_retries * SMB_ECHO_INTERVAL))) {
cERROR(1, "Server %s has not responded in %d seconds. "
"Reconnecting...", server->hostname,
(echo_retries * SMB_ECHO_INTERVAL / HZ));
cifs_reconnect(server);
wake_up(&server->response_q);
continue;
}
rc = read_from_socket(server, &smb_msg, &iov, pdu_length,
&total_read, true /* header read */);
if (rc == 3)
goto incomplete_rcv;
else if (rc == 2)
break;
else if (rc == 1)
continue;
/*
* The right amount was read from socket - 4 bytes,
* so we can now interpret the length field.
*/
/*
* Note that RFC 1001 length is big endian on the wire,
* but we convert it here so it is always manipulated
* as host byte order.
*/
pdu_length = be32_to_cpu(smb_buffer->smb_buf_length);
cFYI(1, "rfc1002 length 0x%x", pdu_length+4);
if (!check_rfc1002_header(server, buf))
continue;
/* else length ok */
if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
isLargeBuf = true;
memcpy(bigbuf, smallbuf, 4);
smb_buffer = (struct smb_hdr *)bigbuf;
buf = bigbuf;
}
iov.iov_base = 4 + buf;
iov.iov_len = pdu_length;
rc = read_from_socket(server, &smb_msg, &iov, pdu_length,
&total_read, false);
if (rc == 2)
break;
else if (rc == 1)
continue;
total_read += 4; /* account for rfc1002 hdr */
dump_smb(smb_buffer, total_read);
/*
* We know that we received enough to get to the MID as we
* checked the pdu_length earlier. Now check to see
* if the rest of the header is OK. We borrow the length
* var for the rest of the loop to avoid a new stack var.
*
* 48 bytes is enough to display the header and a little bit
* into the payload for debugging purposes.
*/
length = checkSMB(smb_buffer, smb_buffer->Mid, total_read);
if (length != 0)
cifs_dump_mem("Bad SMB: ", buf,
min_t(unsigned int, total_read, 48));
server->lstrp = jiffies;
mid_entry = find_cifs_mid(server, smb_buffer, &length,
isLargeBuf, &isMultiRsp, &bigbuf);
if (mid_entry != NULL) {
mid_entry->callback(mid_entry);
/* Was previous buf put in mpx struct for multi-rsp? */
if (!isMultiRsp) {
/* smb buffer will be freed by user thread */
if (isLargeBuf)
bigbuf = NULL;
else
smallbuf = NULL;
}
} else if (length != 0) {
/* response sanity checks failed */
continue;
} else if (!is_valid_oplock_break(smb_buffer, server) &&
!isMultiRsp) {
cERROR(1, "No task to wake, unknown frame received! "
"NumMids %d", atomic_read(&midCount));
cifs_dump_mem("Received Data is: ", buf,
sizeof(struct smb_hdr));
#ifdef CONFIG_CIFS_DEBUG2
cifs_dump_detail(smb_buffer);
cifs_dump_mids(server);
#endif /* CIFS_DEBUG2 */
}
} /* end while !EXITING */
/* buffer usually freed in free_mid - need to free it here on exit */
cifs_buf_release(bigbuf);
if (smallbuf) /* no sense logging a debug message if NULL */
cifs_small_buf_release(smallbuf);
task_to_wake = xchg(&server->tsk, NULL);
clean_demultiplex_info(server);
/* if server->tsk was NULL then wait for a signal before exiting */
if (!task_to_wake) {
@ -3193,15 +3232,9 @@ mount_fail_check:
else
cifs_put_tcp_session(srvTcp);
bdi_destroy(&cifs_sb->bdi);
goto out;
}
/* volume_info->password is freed above when existing session found
(in which case it is not needed anymore) but when new sesion is created
the password ptr is put in the new session structure (in which case the
password will be freed at unmount time) */
out:
/* zero out password before freeing */
FreeXid(xid);
return rc;
}

View File

@ -314,6 +314,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
}
spin_unlock(&cifs_file_list_lock);
cancel_work_sync(&cifs_file->oplock_break);
if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
int xid, rc;
@ -2418,31 +2420,6 @@ void cifs_oplock_break(struct work_struct *work)
cinode->clientCanCacheRead ? 1 : 0);
cFYI(1, "Oplock release rc = %d", rc);
}
/*
* We might have kicked in before is_valid_oplock_break()
* finished grabbing reference for us. Make sure it's done by
* waiting for cifs_file_list_lock.
*/
spin_lock(&cifs_file_list_lock);
spin_unlock(&cifs_file_list_lock);
cifs_oplock_break_put(cfile);
}
/* must be called while holding cifs_file_list_lock */
void cifs_oplock_break_get(struct cifsFileInfo *cfile)
{
cifs_sb_active(cfile->dentry->d_sb);
cifsFileInfo_get(cfile);
}
void cifs_oplock_break_put(struct cifsFileInfo *cfile)
{
struct super_block *sb = cfile->dentry->d_sb;
cifsFileInfo_put(cfile);
cifs_sb_deactive(sb);
}
const struct address_space_operations cifs_addr_ops = {

View File

@ -585,15 +585,8 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
cifs_set_oplock_level(pCifsInode,
pSMB->OplockLevel ? OPLOCK_READ : 0);
/*
* cifs_oplock_break_put() can't be called
* from here. Get reference after queueing
* succeeded. cifs_oplock_break() will
* synchronize using cifs_file_list_lock.
*/
if (queue_work(system_nrt_wq,
&netfile->oplock_break))
cifs_oplock_break_get(netfile);
queue_work(system_nrt_wq,
&netfile->oplock_break);
netfile->oplock_break_cancelled = false;
spin_unlock(&cifs_file_list_lock);

View File

@ -124,7 +124,8 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
/* that we use in next few lines */
/* Note that header is initialized to zero in header_assemble */
pSMB->req.AndXCommand = 0xFF;
pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
pSMB->req.MaxBufferSize = cpu_to_le16(min_t(u32, CIFSMaxBufSize - 4,
USHRT_MAX));
pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
pSMB->req.VcNumber = get_next_vcnum(ses);