Commit 46810cbf authored by Steve French's avatar Steve French Committed by Linus Torvalds

[PATCH] cifs: Ease memory pressure, do not use large buffers in byte range lock requests.

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 79944bf7
......@@ -1023,11 +1023,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
__u16 count;
cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB,
(void **) &pSMBr);
rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
if (rc)
return rc;
pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
timeout = -1; /* no response expected */
pSMB->Timeout = 0;
......@@ -1065,7 +1067,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
if (rc) {
cFYI(1, ("Send error in Lock = %d", rc));
}
cifs_buf_release(pSMB);
cifs_small_buf_release(pSMB);
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
......
......@@ -294,165 +294,168 @@ cifs_demultiplex_thread(struct TCP_Server_Info *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
an 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 */
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 (temp[0] != (char) 0) {
cERROR(1,("Unknown RFC 1002 frame"));
cifs_dump_mem(" Received Data: ", temp, length);
} else if (length < 4) {
cFYI(1,
("Frame less than 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 */
pdu_length = ntohl(smb_buffer->smb_buf_length);
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
an 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 */
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 */
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 */
goto dmx_loop_end;
} else if (server->tcpStatus ==
CifsNeedReconnect) {
cifs_reconnect(server);
csocket = server->ssocket;
/* Reconnect wakes up rspns q */
}
} else if (temp[0] != (char) 0) {
cERROR(1,("Unknown RFC 1002 frame"));
cifs_dump_mem(" Received Data: ", temp, 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 and pdu_length %d",
length, pdu_length+4));
cifs_reconnect(server);
csocket = server->ssocket;
wake_up(&server->response_q);
continue;
} else { /* length ok */
int reconnect = 0;
if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
isLargeBuf = TRUE;
memcpy(bigbuf, smallbuf, 4);
smb_buffer = bigbuf;
}
length = 0;
iov.iov_base = 4 + (char *)smb_buffer;
iov.iov_len = pdu_length;
for (total_read = 0;
total_read < pdu_length;
total_read += length) {
length = kernel_recvmsg(csocket, &smb_msg,
&iov, 1,
pdu_length - total_read, 0);
if((server->tcpStatus == CifsExiting) ||
(length == -EINTR)) {
/* then will exit */
reconnect = 2;
break;
} else if (server->tcpStatus ==
CifsNeedReconnect) {
cifs_reconnect(server);
csocket = server->ssocket;
/* Reconnect wakes up rspns q */
/* Now we will reread sock */
goto dmx_loop_end;
} 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;
goto dmx_loop_end;
}
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;
}
length += 4; /* account for rfc1002 hdr */
}
if(reconnect == 2)
break;
else if(reconnect == 1)
continue;
dump_smb(smb_buffer, length);
if (checkSMB
(smb_buffer, smb_buffer->Mid, total_read+4)) {
cERROR(1, ("Bad SMB Received "));
continue;
}
length += 4; /* account for rfc1002 hdr */
}
/* BB FIXME - add checkTrans2SMBSecondary() */
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;
if(isLargeBuf)
mid_entry->largeBuf = 1;
else
mid_entry->largeBuf = 0;
}
}
spin_unlock(&GlobalMid_Lock);
if (task_to_wake) {
dump_smb(smb_buffer, length);
if (checkSMB
(smb_buffer, smb_buffer->Mid, total_read+4)) {
cERROR(1, ("Bad SMB Received "));
continue;
}
task_to_wake = NULL;
spin_lock(&GlobalMid_Lock);
list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry,
qhead);
if ((mid_entry->mid == smb_buffer->Mid)
&& (mid_entry->midState ==
MID_REQUEST_SUBMITTED)
&& (mid_entry->command ==
smb_buffer->Command)) {
cFYI(1,("Found Mid 0x%x wake up"
,mid_entry->mid));
/* BB FIXME - missing code here BB */
/* check_2nd_t2(smb_buffer); */
task_to_wake = mid_entry->tsk;
mid_entry->resp_buf =
smb_buffer;
mid_entry->midState =
MID_RESPONSE_RECEIVED;
if(isLargeBuf)
bigbuf = NULL;
mid_entry->largeBuf = 1;
else
smallbuf = NULL;
smb_buffer = NULL; /* will be freed by users thread after he is done */
wake_up_process(task_to_wake);
} else if (is_valid_oplock_break(smb_buffer) == FALSE) {
cERROR(1, ("No task to wake, unknown frame rcvd!"));
cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
mid_entry->largeBuf = 0;
}
}
} else {
cFYI(1,
("Frame less than four bytes received %d bytes long.",
length));
cifs_reconnect(server);
csocket = server->ssocket;
wake_up(&server->response_q);
continue;
spin_unlock(&GlobalMid_Lock);
if (task_to_wake) {
if(isLargeBuf)
bigbuf = NULL;
else
smallbuf = NULL;
smb_buffer = NULL; /* will be freed by users thread after he is done */
wake_up_process(task_to_wake);
} else if (is_valid_oplock_break(smb_buffer) == FALSE) {
cERROR(1, ("No task to wake, unknown frame rcvd!"));
cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
}
}
dmx_loop_end:
cFYI(1,("Exiting cifsd loop"));
}
spin_lock(&GlobalMid_Lock);
server->tcpStatus = CifsExiting;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment