X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fcifs%2Ftransport.c;h=cdc7ed3424c772d1780cc079c01f98f710ae2d7a;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=aaa78992a045d38394036e6e1204f33e525abc26;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index aaa78992a..cdc7ed342 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -25,12 +25,13 @@ #include #include #include +#include #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 * @@ -47,8 +48,7 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) 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 { @@ -79,7 +79,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) 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 * @@ -120,20 +120,17 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, 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; + struct kvec iov; 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; smb_msg.msg_name = sin; smb_msg.msg_namelen = sizeof (struct sockaddr); - smb_msg.msg_iov = &iov; - smb_msg.msg_iovlen = 1; smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ @@ -147,11 +144,17 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, cFYI(1, ("Sending smb of length %d ", smb_buf_length)); dump_smb(smb_buffer, smb_buf_length + 4); - temp_fs = get_fs(); /* we must turn off socket api parm checking */ - set_fs(get_ds()); while(iov.iov_len > 0) { - rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4); + rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, 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; @@ -161,7 +164,6 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, iov.iov_base += rc; iov.iov_len -= rc; } - set_fs(temp_fs); if (rc < 0) { cERROR(1,("Error %d sending data on socket to server.", rc)); @@ -182,31 +184,78 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, 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 */ + if(long_op == -1) { + /* oplock breaks must not be held up */ + atomic_inc(&ses->server->inFlight); + } else { + spin_lock(&GlobalMid_Lock); + while(1) { + if(atomic_read(&ses->server->inFlight) >= CIFS_MAX_REQ){ + spin_unlock(&GlobalMid_Lock); + wait_event(ses->server->request_q, + atomic_read(&ses->server->inFlight) + < CIFS_MAX_REQ); + spin_lock(&GlobalMid_Lock); + } else { + if(ses->server->tcpStatus == CifsExiting) { + spin_unlock(&GlobalMid_Lock); + return -ENOENT; + } + + /* can not count locking commands against total since + they are allowed to block on server */ + + if(long_op < 3) { + /* update # of requests on the wire to server */ + atomic_inc(&ses->server->inFlight); + } + spin_unlock(&GlobalMid_Lock); + break; + } + } + } + /* 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) { @@ -215,6 +264,11 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ("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; } @@ -226,7 +280,17 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, 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 */ @@ -285,10 +349,14 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, } 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", @@ -338,8 +406,22 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, } } 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; }