#include <linux/net.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
+#include <linux/mempool.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
-extern kmem_cache_t *cifs_mid_cachep;
+extern mempool_t *cifs_mid_poolp;
extern kmem_cache_t *cifs_oplock_cachep;
struct mid_q_entry *
return NULL;
}
- temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep,
- SLAB_KERNEL);
+ temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,SLAB_KERNEL | SLAB_NOFS);
if (temp == NULL)
return temp;
else {
atomic_dec(&midCount);
spin_unlock(&GlobalMid_Lock);
cifs_buf_release(midEntry->resp_buf);
- kmem_cache_free(cifs_mid_cachep, midEntry);
+ mempool_free(midEntry, cifs_mid_poolp);
}
struct oplock_q_entry *
unsigned int smb_buf_length, struct sockaddr *sin)
{
int rc = 0;
+ int i = 0;
struct msghdr smb_msg;
struct iovec iov;
mm_segment_t temp_fs;
if(ssocket == NULL)
return -ENOTSOCK; /* BB eventually add reconnect code here */
-/* ssocket->sk->allocation = GFP_BUFFER; *//* BB is this spurious? */
iov.iov_base = smb_buffer;
iov.iov_len = smb_buf_length + 4;
while(iov.iov_len > 0) {
rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4);
if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
+ i++;
+ if(i > 60) {
+ cERROR(1,
+ ("sends on sock %p stuck for 30 seconds",
+ ssocket));
+ rc = -EAGAIN;
+ break;
+ }
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ/2);
continue;
long timeout;
struct mid_q_entry *midQ;
- if ((ses == NULL) || (ses->server == NULL)) {
- cERROR(1,("Null tcp session or smb session: %p",ses));
+ if (ses == NULL) {
+ cERROR(1,("Null smb session"));
+ return -EIO;
+ }
+ if(ses->server == NULL) {
+ cERROR(1,("Null tcp session"));
return -EIO;
}
+ /* Ensure that we do not send more than 50 overlapping requests
+ to the same server. We may make this configurable later or
+ use ses->maxReq */
+
+ /* can not count locking commands against the total since
+ they are allowed to block on server */
+ if(long_op < 3) {
+ /* update # of requests on the wire to this server */
+ atomic_inc(&ses->server->inFlight);
+ }
+
+ if(atomic_read(&ses->server->inFlight) > CIFS_MAX_REQ) {
+ wait_event(ses->server->request_q,atomic_read(&ses->server->inFlight) <= CIFS_MAX_REQ);
+ }
+
+ /* make sure that we sign in the same order that we send on this socket
+ and avoid races inside tcp sendmsg code that could cause corruption
+ of smb data */
+
+ down(&ses->server->tcpSem);
+
if (ses->server->tcpStatus == CifsExiting) {
- return -ENOENT;
+ rc = -ENOENT;
+ goto out_unlock;
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
cFYI(1,("tcp session dead - return to caller to retry"));
- return -EAGAIN;
+ rc = -EAGAIN;
+ goto out_unlock;
} else if (ses->status != CifsGood) {
/* check if SMB session is bad because we are setting it up */
if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
(in_buf->Command != SMB_COM_NEGOTIATE)) {
- return -EAGAIN;
+ rc = -EAGAIN;
+ goto out_unlock;
} /* else ok - we are setting up session */
}
- /* make sure that we sign in the same order that we send on this socket
- and avoid races inside tcp sendmsg code that could cause corruption
- of smb data */
- down(&ses->server->tcpSem);
midQ = AllocMidQEntry(in_buf, ses);
if (midQ == NULL) {
up(&ses->server->tcpSem);
- return -EIO;
+ /* If not lock req, update # of requests on wire to server */
+ if(long_op < 3) {
+ atomic_dec(&ses->server->inFlight);
+ wake_up(&ses->server->request_q);
+ }
+ return -ENOMEM;
}
if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) {
("Illegal length, greater than maximum frame, %d ",
in_buf->smb_buf_length));
DeleteMidQEntry(midQ);
+ /* If not lock req, update # of requests on wire to server */
+ if(long_op < 3) {
+ atomic_dec(&ses->server->inFlight);
+ wake_up(&ses->server->request_q);
+ }
return -EIO;
}
midQ->midState = MID_REQUEST_SUBMITTED;
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
(struct sockaddr *) &(ses->server->addr.sockAddr));
- up(&ses->server->tcpSem);
+ if(rc < 0) {
+ DeleteMidQEntry(midQ);
+ up(&ses->server->tcpSem);
+ /* If not lock req, update # of requests on wire to server */
+ if(long_op < 3) {
+ atomic_dec(&ses->server->inFlight);
+ wake_up(&ses->server->request_q);
+ }
+ return rc;
+ } else
+ up(&ses->server->tcpSem);
if (long_op == -1)
goto cifs_no_response_exit;
else if (long_op == 2) /* writes past end of file can take looooong time */
}
spin_unlock(&GlobalMid_Lock);
DeleteMidQEntry(midQ);
+ /* If not lock req, update # of requests on wire to server */
+ if(long_op < 3) {
+ atomic_dec(&ses->server->inFlight);
+ wake_up(&ses->server->request_q);
+ }
return rc;
}
-
if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
cERROR(1,
("Frame too large received. Length: %d Xid: %d",
}
}
cifs_no_response_exit:
- DeleteMidQEntry(midQ); /* BB what if process is killed?
- - BB add background daemon to clean up Mid entries from
- killed processes & test killing process with active mid */
+ DeleteMidQEntry(midQ);
+
+ if(long_op < 3) {
+ atomic_dec(&ses->server->inFlight);
+ wake_up(&ses->server->request_q);
+ }
+
+ return rc;
+
+out_unlock:
+ up(&ses->server->tcpSem);
+ /* If not lock req, update # of requests on wire to server */
+ if(long_op < 3) {
+ atomic_dec(&ses->server->inFlight);
+ wake_up(&ses->server->request_q);
+ }
+
return rc;
}