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 serverhifive-unleashed-5.1
commit
5f66d2b58c
|
@ -87,9 +87,15 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
|
||||||
if ((cifs_pdu == NULL) || (server == NULL))
|
if ((cifs_pdu == NULL) || (server == NULL))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
|
if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
|
||||||
|
server->tcpStatus == CifsNeedNegotiate)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
if (!server->session_estab) {
|
||||||
|
strncpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
cifs_pdu->Signature.Sequence.SequenceNumber =
|
cifs_pdu->Signature.Sequence.SequenceNumber =
|
||||||
cpu_to_le32(server->sequence_number);
|
cpu_to_le32(server->sequence_number);
|
||||||
cifs_pdu->Signature.Sequence.Reserved = 0;
|
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))
|
if ((cifs_pdu == NULL) || (server == NULL))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
|
if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
|
||||||
|
server->tcpStatus == CifsNeedNegotiate)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
if (!server->session_estab) {
|
||||||
|
strncpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
cifs_pdu->Signature.Sequence.SequenceNumber =
|
cifs_pdu->Signature.Sequence.SequenceNumber =
|
||||||
cpu_to_le32(server->sequence_number);
|
cpu_to_le32(server->sequence_number);
|
||||||
cifs_pdu->Signature.Sequence.Reserved = 0;
|
cifs_pdu->Signature.Sequence.Reserved = 0;
|
||||||
|
|
|
@ -86,24 +86,6 @@ extern mempool_t *cifs_sm_req_poolp;
|
||||||
extern mempool_t *cifs_req_poolp;
|
extern mempool_t *cifs_req_poolp;
|
||||||
extern mempool_t *cifs_mid_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
|
static int
|
||||||
cifs_read_super(struct super_block *sb)
|
cifs_read_super(struct super_block *sb)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
extern const struct address_space_operations cifs_addr_ops_smallbuf;
|
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 */
|
/* Functions related to inodes */
|
||||||
extern const struct inode_operations cifs_dir_inode_ops;
|
extern const struct inode_operations cifs_dir_inode_ops;
|
||||||
extern struct inode *cifs_root_iget(struct super_block *);
|
extern struct inode *cifs_root_iget(struct super_block *);
|
||||||
|
|
|
@ -942,8 +942,6 @@ GLOBAL_EXTERN spinlock_t siduidlock;
|
||||||
GLOBAL_EXTERN spinlock_t sidgidlock;
|
GLOBAL_EXTERN spinlock_t sidgidlock;
|
||||||
|
|
||||||
void cifs_oplock_break(struct work_struct *work);
|
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;
|
extern const struct slow_work_ops cifs_oplock_break_ops;
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ static void mark_open_files_invalid(struct cifs_tcon *pTcon)
|
||||||
static int
|
static int
|
||||||
cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc;
|
||||||
struct cifs_ses *ses;
|
struct cifs_ses *ses;
|
||||||
struct TCP_Server_Info *server;
|
struct TCP_Server_Info *server;
|
||||||
struct nls_table *nls_codepage;
|
struct nls_table *nls_codepage;
|
||||||
|
@ -5720,6 +5720,7 @@ CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
|
||||||
char *temp_ptr;
|
char *temp_ptr;
|
||||||
char *end_of_smb;
|
char *end_of_smb;
|
||||||
__u16 params, byte_count, data_offset;
|
__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);
|
cFYI(1, "In Query All EAs path %s", searchName);
|
||||||
QAllEAsRetry:
|
QAllEAsRetry:
|
||||||
|
@ -5837,7 +5838,8 @@ QAllEAsRetry:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ea_name) {
|
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;
|
temp_ptr += name_len + 1;
|
||||||
rc = value_len;
|
rc = value_len;
|
||||||
if (buf_size == 0)
|
if (buf_size == 0)
|
||||||
|
|
|
@ -319,344 +319,221 @@ requeue_echo:
|
||||||
queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
|
queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static bool
|
||||||
cifs_demultiplex_thread(void *p)
|
allocate_buffers(char **bigbuf, char **smallbuf, unsigned int size,
|
||||||
|
bool is_large_buf)
|
||||||
{
|
{
|
||||||
int length;
|
char *bbuf = *bigbuf, *sbuf = *smallbuf;
|
||||||
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;
|
|
||||||
|
|
||||||
current->flags |= PF_MEMALLOC;
|
if (bbuf == NULL) {
|
||||||
cFYI(1, "Demultiplex PID: %d", task_pid_nr(current));
|
bbuf = (char *)cifs_buf_get();
|
||||||
|
if (!bbuf) {
|
||||||
length = atomic_inc_return(&tcpSesAllocCount);
|
cERROR(1, "No memory for large SMB response");
|
||||||
if (length > 1)
|
msleep(3000);
|
||||||
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
|
/* retry will check if exiting */
|
||||||
GFP_KERNEL);
|
return false;
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
} else if (is_large_buf) {
|
||||||
|
/* we are reusing a dirty large buf, clear its start */
|
||||||
|
memset(bbuf, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
if (smallbuf == NULL) {
|
if (sbuf == NULL) {
|
||||||
smallbuf = cifs_small_buf_get();
|
sbuf = (char *)cifs_small_buf_get();
|
||||||
if (!smallbuf) {
|
if (!sbuf) {
|
||||||
cERROR(1, "No memory for SMB response");
|
cERROR(1, "No memory for SMB response");
|
||||||
msleep(1000);
|
msleep(1000);
|
||||||
/* retry will check if exiting */
|
/* retry will check if exiting */
|
||||||
continue;
|
return false;
|
||||||
}
|
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
/* beginning of smb buffer is cleared in our buf_get */
|
||||||
|
} else {
|
||||||
|
/* if existing small buf clear beginning */
|
||||||
|
memset(sbuf, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
length =
|
*bigbuf = bbuf;
|
||||||
kernel_recvmsg(csocket, &smb_msg,
|
*smallbuf = sbuf;
|
||||||
&iov, 1, pdu_length, 0 /* BB other flags? */);
|
|
||||||
|
|
||||||
|
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) {
|
if (server->tcpStatus == CifsExiting) {
|
||||||
|
/* then will exit */
|
||||||
|
rc = 2;
|
||||||
break;
|
break;
|
||||||
} else if (server->tcpStatus == CifsNeedReconnect) {
|
} else if (server->tcpStatus == CifsNeedReconnect) {
|
||||||
cFYI(1, "Reconnect after server stopped responding");
|
|
||||||
cifs_reconnect(server);
|
cifs_reconnect(server);
|
||||||
cFYI(1, "call to reconnect done");
|
/* Reconnect wakes up rspns q */
|
||||||
csocket = server->ssocket;
|
/* Now we will reread sock */
|
||||||
continue;
|
rc = 1;
|
||||||
|
break;
|
||||||
} else if (length == -ERESTARTSYS ||
|
} else if (length == -ERESTARTSYS ||
|
||||||
length == -EAGAIN ||
|
length == -EAGAIN ||
|
||||||
length == -EINTR) {
|
length == -EINTR) {
|
||||||
msleep(1); /* minimum sleep to prevent looping
|
/*
|
||||||
allowing socket to clear and app threads to set
|
* Minimum sleep to prevent looping, allowing socket
|
||||||
tcpStatus CifsNeedReconnect if server hung */
|
* to clear and app threads to set tcpStatus
|
||||||
if (pdu_length < 4) {
|
* CifsNeedReconnect if server hung.
|
||||||
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)
|
|
||||||
*/
|
*/
|
||||||
cifs_set_port((struct sockaddr *)
|
usleep_range(1000, 2000);
|
||||||
&server->dstaddr, CIFS_PORT);
|
length = 0;
|
||||||
cifs_reconnect(server);
|
if (!is_header_read)
|
||||||
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;
|
|
||||||
continue;
|
continue;
|
||||||
} else if (length <= 0) {
|
/* Special handling for header read */
|
||||||
cERROR(1, "Received no data, expecting %d",
|
if (total_read) {
|
||||||
pdu_length - total_read);
|
iov->iov_base = (to_read - total_read) +
|
||||||
cifs_reconnect(server);
|
buf;
|
||||||
csocket = server->ssocket;
|
iov->iov_len = to_read - total_read;
|
||||||
reconnect = 1;
|
smb_msg->msg_control = NULL;
|
||||||
break;
|
smb_msg->msg_controllen = 0;
|
||||||
}
|
rc = 3;
|
||||||
}
|
} else
|
||||||
if (reconnect == 2)
|
rc = 1;
|
||||||
break;
|
break;
|
||||||
else if (reconnect == 1)
|
} else if (length <= 0) {
|
||||||
continue;
|
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
|
* We get this from Windows 98 instead of an error on
|
||||||
* checked the pdu_length earlier. Now check to see
|
* SMB negprot response.
|
||||||
* 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);
|
cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
|
||||||
if (length != 0)
|
pdu_length);
|
||||||
cifs_dump_mem("Bad SMB: ", smb_buffer,
|
/* give server a second to clean up */
|
||||||
min_t(unsigned int, total_read, 48));
|
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;
|
/* else we have an SMB response */
|
||||||
server->lstrp = jiffies;
|
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);
|
return true;
|
||||||
list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
|
}
|
||||||
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
|
|
||||||
|
|
||||||
if (mid_entry->mid != smb_buffer->Mid ||
|
static struct mid_q_entry *
|
||||||
mid_entry->midState != MID_REQUEST_SUBMITTED ||
|
find_cifs_mid(struct TCP_Server_Info *server, struct smb_hdr *buf,
|
||||||
mid_entry->command != smb_buffer->Command) {
|
int *length, bool is_large_buf, bool *is_multi_rsp, char **bigbuf)
|
||||||
mid_entry = NULL;
|
{
|
||||||
continue;
|
struct mid_q_entry *mid = NULL, *tmp_mid, *ret = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
if (length == 0 &&
|
spin_lock(&GlobalMid_Lock);
|
||||||
check2ndT2(smb_buffer, server->maxBuf) > 0) {
|
list_for_each_entry_safe(mid, tmp_mid, &server->pending_mid_q, qhead) {
|
||||||
/* We have a multipart transact2 resp */
|
if (mid->mid != buf->Mid ||
|
||||||
isMultiRsp = true;
|
mid->midState != MID_REQUEST_SUBMITTED ||
|
||||||
if (mid_entry->resp_buf) {
|
mid->command != buf->Command)
|
||||||
/* merge response - fix up 1st*/
|
continue;
|
||||||
length = coalesce_t2(smb_buffer,
|
|
||||||
mid_entry->resp_buf);
|
if (*length == 0 && check2ndT2(buf, server->maxBuf) > 0) {
|
||||||
if (length > 0) {
|
/* We have a multipart transact2 resp */
|
||||||
length = 0;
|
*is_multi_rsp = true;
|
||||||
mid_entry->multiRsp = true;
|
if (mid->resp_buf) {
|
||||||
break;
|
/* merge response - fix up 1st*/
|
||||||
} else {
|
*length = coalesce_t2(buf, mid->resp_buf);
|
||||||
/* all parts received or
|
if (*length > 0) {
|
||||||
* packet is malformed
|
*length = 0;
|
||||||
*/
|
mid->multiRsp = true;
|
||||||
mid_entry->multiEnd = true;
|
break;
|
||||||
goto multi_t2_fnd;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!isLargeBuf) {
|
|
||||||
/*
|
|
||||||
* FIXME: switch to already
|
|
||||||
* allocated largebuf?
|
|
||||||
*/
|
|
||||||
cERROR(1, "1st trans2 resp "
|
|
||||||
"needs bigbuf");
|
|
||||||
} else {
|
|
||||||
/* Have first buffer */
|
|
||||||
mid_entry->resp_buf =
|
|
||||||
smb_buffer;
|
|
||||||
mid_entry->largeBuf = true;
|
|
||||||
bigbuf = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
/* 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;
|
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) {
|
return ret;
|
||||||
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 */
|
|
||||||
|
|
||||||
}
|
static void clean_demultiplex_info(struct TCP_Server_Info *server)
|
||||||
} /* end while !EXITING */
|
{
|
||||||
|
int length;
|
||||||
|
|
||||||
/* take it off the list, if it's not already */
|
/* take it off the list, if it's not already */
|
||||||
spin_lock(&cifs_tcp_ses_lock);
|
spin_lock(&cifs_tcp_ses_lock);
|
||||||
|
@ -668,35 +545,39 @@ multi_t2_fnd:
|
||||||
spin_unlock(&GlobalMid_Lock);
|
spin_unlock(&GlobalMid_Lock);
|
||||||
wake_up_all(&server->response_q);
|
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
|
* Check if we have blocked requests that need to free. Note that
|
||||||
can be set at module install time to as little as two */
|
* cifs_max_pending is normally 50, but can be set at module install
|
||||||
|
* time to as little as two.
|
||||||
|
*/
|
||||||
spin_lock(&GlobalMid_Lock);
|
spin_lock(&GlobalMid_Lock);
|
||||||
if (atomic_read(&server->inFlight) >= cifs_max_pending)
|
if (atomic_read(&server->inFlight) >= cifs_max_pending)
|
||||||
atomic_set(&server->inFlight, cifs_max_pending - 1);
|
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);
|
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
|
* Although there should not be any requests blocked on this queue it
|
||||||
that may haven been blocked when more than 50 at time were on the wire
|
* can not hurt to be paranoid and try to wake up requests that may
|
||||||
to the same server - they now will see the session is in exit state
|
* haven been blocked when more than 50 at time were on the wire to the
|
||||||
and get out of SendReceive. */
|
* same server - they now will see the session is in exit state and get
|
||||||
|
* out of SendReceive.
|
||||||
|
*/
|
||||||
wake_up_all(&server->request_q);
|
wake_up_all(&server->request_q);
|
||||||
/* give those requests time to exit */
|
/* give those requests time to exit */
|
||||||
msleep(125);
|
msleep(125);
|
||||||
|
|
||||||
if (server->ssocket) {
|
if (server->ssocket) {
|
||||||
sock_release(csocket);
|
sock_release(server->ssocket);
|
||||||
server->ssocket = NULL;
|
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)) {
|
if (!list_empty(&server->pending_mid_q)) {
|
||||||
struct list_head dispose_list;
|
struct list_head dispose_list;
|
||||||
|
struct mid_q_entry *mid_entry;
|
||||||
|
struct list_head *tmp, *tmp2;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&dispose_list);
|
INIT_LIST_HEAD(&dispose_list);
|
||||||
spin_lock(&GlobalMid_Lock);
|
spin_lock(&GlobalMid_Lock);
|
||||||
|
@ -720,26 +601,184 @@ multi_t2_fnd:
|
||||||
}
|
}
|
||||||
|
|
||||||
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 */
|
* mpx threads have not exited yet give them at least the smb
|
||||||
/* due to delays on oplock break requests, we need
|
* send timeout time for long ops.
|
||||||
to wait at least 45 seconds before giving up
|
*
|
||||||
on a request getting a response and going ahead
|
* Due to delays on oplock break requests, we need to wait at
|
||||||
and killing cifsd */
|
* 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");
|
cFYI(1, "Wait for exit from demultiplex thread");
|
||||||
msleep(46000);
|
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);
|
kfree(server->hostname);
|
||||||
task_to_wake = xchg(&server->tsk, NULL);
|
|
||||||
kfree(server);
|
kfree(server);
|
||||||
|
|
||||||
length = atomic_dec_return(&tcpSesAllocCount);
|
length = atomic_dec_return(&tcpSesAllocCount);
|
||||||
if (length > 0)
|
if (length > 0)
|
||||||
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
|
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
|
||||||
GFP_KERNEL);
|
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 server->tsk was NULL then wait for a signal before exiting */
|
||||||
if (!task_to_wake) {
|
if (!task_to_wake) {
|
||||||
|
@ -3193,15 +3232,9 @@ mount_fail_check:
|
||||||
else
|
else
|
||||||
cifs_put_tcp_session(srvTcp);
|
cifs_put_tcp_session(srvTcp);
|
||||||
bdi_destroy(&cifs_sb->bdi);
|
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:
|
out:
|
||||||
/* zero out password before freeing */
|
|
||||||
FreeXid(xid);
|
FreeXid(xid);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -314,6 +314,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
||||||
}
|
}
|
||||||
spin_unlock(&cifs_file_list_lock);
|
spin_unlock(&cifs_file_list_lock);
|
||||||
|
|
||||||
|
cancel_work_sync(&cifs_file->oplock_break);
|
||||||
|
|
||||||
if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
|
if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
|
||||||
int xid, rc;
|
int xid, rc;
|
||||||
|
|
||||||
|
@ -2418,31 +2420,6 @@ void cifs_oplock_break(struct work_struct *work)
|
||||||
cinode->clientCanCacheRead ? 1 : 0);
|
cinode->clientCanCacheRead ? 1 : 0);
|
||||||
cFYI(1, "Oplock release rc = %d", rc);
|
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 = {
|
const struct address_space_operations cifs_addr_ops = {
|
||||||
|
|
|
@ -585,15 +585,8 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
|
||||||
|
|
||||||
cifs_set_oplock_level(pCifsInode,
|
cifs_set_oplock_level(pCifsInode,
|
||||||
pSMB->OplockLevel ? OPLOCK_READ : 0);
|
pSMB->OplockLevel ? OPLOCK_READ : 0);
|
||||||
/*
|
queue_work(system_nrt_wq,
|
||||||
* cifs_oplock_break_put() can't be called
|
&netfile->oplock_break);
|
||||||
* 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);
|
|
||||||
netfile->oplock_break_cancelled = false;
|
netfile->oplock_break_cancelled = false;
|
||||||
|
|
||||||
spin_unlock(&cifs_file_list_lock);
|
spin_unlock(&cifs_file_list_lock);
|
||||||
|
|
|
@ -124,7 +124,8 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
|
||||||
/* that we use in next few lines */
|
/* that we use in next few lines */
|
||||||
/* Note that header is initialized to zero in header_assemble */
|
/* Note that header is initialized to zero in header_assemble */
|
||||||
pSMB->req.AndXCommand = 0xFF;
|
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.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
|
||||||
pSMB->req.VcNumber = get_next_vcnum(ses);
|
pSMB->req.VcNumber = get_next_vcnum(ses);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue