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, ...@@ -1023,11 +1023,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
__u16 count; __u16 count;
cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock)); cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB, rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
(void **) &pSMBr);
if (rc) if (rc)
return rc; return rc;
pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) { if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
timeout = -1; /* no response expected */ timeout = -1; /* no response expected */
pSMB->Timeout = 0; pSMB->Timeout = 0;
...@@ -1065,7 +1067,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, ...@@ -1065,7 +1067,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
if (rc) { if (rc) {
cFYI(1, ("Send error in Lock = %d", 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 /* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */ since file handle passed in no longer valid */
......
...@@ -294,165 +294,168 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -294,165 +294,168 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
csocket = server->ssocket; csocket = server->ssocket;
wake_up(&server->response_q); wake_up(&server->response_q);
continue; continue;
} else if (length > 3) { } else if (length < 4) {
pdu_length = ntohl(smb_buffer->smb_buf_length); cFYI(1,
/* Only read pdu_length after below checks for too short (due ("Frame less than four bytes received %d bytes long.",
to e.g. int overflow) and too long ie beyond end of buf */ length));
cFYI(1,("rfc1002 length(big endian)0x%x)", cifs_reconnect(server);
pdu_length+4)); csocket = server->ssocket;
wake_up(&server->response_q);
temp = (char *) smb_buffer; continue;
if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { }
cFYI(0,("Received 4 byte keep alive packet"));
} else if (temp[0] == /* the right amount was read from socket - 4 bytes */
(char) RFC1002_POSITIVE_SESSION_RESPONSE) {
cFYI(1,("Good RFC 1002 session rsp")); pdu_length = ntohl(smb_buffer->smb_buf_length);
} else if (temp[0] == cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
(char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
/* we get this from Windows 98 instead of temp = (char *) smb_buffer;
an error on SMB negprot response */ if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); cFYI(0,("Received 4 byte keep alive packet"));
if(server->tcpStatus == CifsNew) { } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
/* if nack on negprot (rather than cFYI(1,("Good RFC 1002 session rsp"));
ret of smb negprot error) reconnecting } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
not going to help, ret error to mount */ /* we get this from Windows 98 instead of
break; an error on SMB negprot response */
} else { cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
/* give server a second to if(server->tcpStatus == CifsNew) {
clean up before reconnect attempt */ /* if nack on negprot (rather than
msleep(1000); ret of smb negprot error) reconnecting
/* always try 445 first on reconnect not going to help, ret error to mount */
since we get NACK on some if we ever break;
connected to port 139 (the NACK is } else {
since we do not begin with RFC1001 /* give server a second to
session initialize frame) */ clean up before reconnect attempt */
server->addr.sockAddr.sin_port = msleep(1000);
htons(CIFS_PORT); /* always try 445 first on reconnect
cifs_reconnect(server); since we get NACK on some if we ever
csocket = server->ssocket; connected to port 139 (the NACK is
wake_up(&server->response_q); since we do not begin with RFC1001
continue; session initialize frame) */
} server->addr.sockAddr.sin_port =
} else if (temp[0] != (char) 0) { htons(CIFS_PORT);
cERROR(1,("Unknown RFC 1002 frame"));
cifs_dump_mem(" Received Data: ", temp, length);
cifs_reconnect(server); cifs_reconnect(server);
csocket = server->ssocket; csocket = server->ssocket;
wake_up(&server->response_q);
continue; continue;
} else { }
if((pdu_length > CIFSMaxBufSize + } else if (temp[0] != (char) 0) {
MAX_CIFS_HDR_SIZE - 4) || cERROR(1,("Unknown RFC 1002 frame"));
(pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { cifs_dump_mem(" Received Data: ", temp, length);
cERROR(1, cifs_reconnect(server);
("Invalid size SMB length %d and pdu_length %d", csocket = server->ssocket;
length, pdu_length+4)); continue;
cifs_reconnect(server); } else { /* we have an SMB response */
csocket = server->ssocket; if((pdu_length > CIFSMaxBufSize +
wake_up(&server->response_q); MAX_CIFS_HDR_SIZE - 4) ||
continue; (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
} else { /* length ok */ cERROR(1,
if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { ("Invalid size SMB length %d and pdu_length %d",
isLargeBuf = TRUE; length, pdu_length+4));
memcpy(bigbuf, smallbuf, 4); cifs_reconnect(server);
smb_buffer = bigbuf; csocket = server->ssocket;
} wake_up(&server->response_q);
length = 0; continue;
iov.iov_base = 4 + (char *)smb_buffer; } else { /* length ok */
iov.iov_len = pdu_length; int reconnect = 0;
for (total_read = 0;
total_read < pdu_length; if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
total_read += length) { isLargeBuf = TRUE;
length = kernel_recvmsg(csocket, &smb_msg, memcpy(bigbuf, smallbuf, 4);
&iov, 1, smb_buffer = bigbuf;
pdu_length - total_read, 0); }
if((server->tcpStatus == CifsExiting) || length = 0;
(length == -EINTR)) { iov.iov_base = 4 + (char *)smb_buffer;
/* then will exit */ iov.iov_len = pdu_length;
goto dmx_loop_end; for (total_read = 0;
} else if (server->tcpStatus == total_read < pdu_length;
CifsNeedReconnect) { total_read += length) {
cifs_reconnect(server); length = kernel_recvmsg(csocket, &smb_msg,
csocket = server->ssocket; &iov, 1,
/* Reconnect wakes up rspns q */ 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 */ /* Now we will reread sock */
goto dmx_loop_end; reconnect = 1;
} else if ((length == -ERESTARTSYS) || break;
(length == -EAGAIN)) { } else if ((length == -ERESTARTSYS) ||
msleep(1); /* minimum sleep to prevent looping (length == -EAGAIN)) {
allowing socket to clear and app threads to set msleep(1); /* minimum sleep to prevent looping
tcpStatus CifsNeedReconnect if server hung */ allowing socket to clear and app threads to set
continue; tcpStatus CifsNeedReconnect if server hung */
} else if (length <= 0) { continue;
cERROR(1, } else if (length <= 0) {
("Received no data, expecting %d", cERROR(1,("Received no data, expecting %d",
pdu_length - total_read)); pdu_length - total_read));
cifs_reconnect(server); cifs_reconnect(server);
csocket = server->ssocket; csocket = server->ssocket;
goto dmx_loop_end; reconnect = 1;
} break;
} }
length += 4; /* account for rfc1002 hdr */
} }
if(reconnect == 2)
break;
else if(reconnect == 1)
continue;
dump_smb(smb_buffer, length); length += 4; /* account for rfc1002 hdr */
if (checkSMB }
(smb_buffer, smb_buffer->Mid, total_read+4)) {
cERROR(1, ("Bad SMB Received "));
continue;
}
/* BB FIXME - add checkTrans2SMBSecondary() */ dump_smb(smb_buffer, length);
if (checkSMB
task_to_wake = NULL; (smb_buffer, smb_buffer->Mid, total_read+4)) {
spin_lock(&GlobalMid_Lock); cERROR(1, ("Bad SMB Received "));
list_for_each(tmp, &server->pending_mid_q) { continue;
mid_entry = list_entry(tmp, struct }
mid_q_entry,
qhead);
task_to_wake = NULL;
if ((mid_entry->mid == smb_buffer->Mid) spin_lock(&GlobalMid_Lock);
&& (mid_entry->midState == list_for_each(tmp, &server->pending_mid_q) {
MID_REQUEST_SUBMITTED) mid_entry = list_entry(tmp, struct mid_q_entry,
&& (mid_entry->command == qhead);
smb_buffer->Command)) {
cFYI(1,("Found Mid 0x%x wake up" if ((mid_entry->mid == smb_buffer->Mid)
,mid_entry->mid)); && (mid_entry->midState ==
task_to_wake = mid_entry->tsk; MID_REQUEST_SUBMITTED)
mid_entry->resp_buf = && (mid_entry->command ==
smb_buffer; smb_buffer->Command)) {
mid_entry->midState = cFYI(1,("Found Mid 0x%x wake up"
MID_RESPONSE_RECEIVED; ,mid_entry->mid));
if(isLargeBuf) /* BB FIXME - missing code here BB */
mid_entry->largeBuf = 1; /* check_2nd_t2(smb_buffer); */
else task_to_wake = mid_entry->tsk;
mid_entry->largeBuf = 0; mid_entry->resp_buf =
} smb_buffer;
} mid_entry->midState =
spin_unlock(&GlobalMid_Lock); MID_RESPONSE_RECEIVED;
if (task_to_wake) {
if(isLargeBuf) if(isLargeBuf)
bigbuf = NULL; mid_entry->largeBuf = 1;
else else
smallbuf = NULL; mid_entry->largeBuf = 0;
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 { spin_unlock(&GlobalMid_Lock);
cFYI(1, if (task_to_wake) {
("Frame less than four bytes received %d bytes long.", if(isLargeBuf)
length)); bigbuf = NULL;
cifs_reconnect(server); else
csocket = server->ssocket; smallbuf = NULL;
wake_up(&server->response_q); smb_buffer = NULL; /* will be freed by users thread after he is done */
continue; 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); spin_lock(&GlobalMid_Lock);
server->tcpStatus = CifsExiting; 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