diff options
Diffstat (limited to 'fs/cifs/transport.c')
-rw-r--r-- | fs/cifs/transport.c | 95 |
1 files changed, 55 insertions, 40 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 9e8e85a8d18..38b3b2463ae 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -147,16 +147,19 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, Flags2 is converted in SendReceive */ smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); - cFYI(1, ("Sending smb of length %d ", smb_buf_length)); + cFYI(1, ("Sending smb of length %d", smb_buf_length)); dump_smb(smb_buffer, len); while (len > 0) { rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); if ((rc == -ENOSPC) || (rc == -EAGAIN)) { i++; - if(i > 60) { + /* smaller timeout here than send2 since smaller size */ + /* Although it may not be required, this also is smaller + oplock break time */ + if(i > 30) { cERROR(1, - ("sends on sock %p stuck for 30 seconds", + ("sends on sock %p stuck for 15 seconds", ssocket)); rc = -EAGAIN; break; @@ -172,7 +175,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, } if (rc < 0) { - cERROR(1,("Error %d sending data on socket to server.", rc)); + cERROR(1,("Error %d sending data on socket to server", rc)); } else { rc = 0; } @@ -182,22 +185,20 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, #ifdef CONFIG_CIFS_EXPERIMENTAL static int -smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer, - unsigned int smb_hdr_length, const char * data, unsigned int datalen, - struct sockaddr *sin) +smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, + struct sockaddr *sin) { int rc = 0; int i = 0; struct msghdr smb_msg; - struct kvec iov[2]; - unsigned len = smb_hdr_length + 4; + struct smb_hdr *smb_buffer = iov[0].iov_base; + unsigned int len = iov[0].iov_len; + unsigned int total_len; + int first_vec = 0; if(ssocket == NULL) return -ENOTSOCK; /* BB eventually add reconnect code here */ - iov[0].iov_base = smb_buffer; - iov[0].iov_len = len; - iov[1].iov_base = data; - iov[1].iov_len = datalen; + smb_msg.msg_name = sin; smb_msg.msg_namelen = sizeof (struct sockaddr); smb_msg.msg_control = NULL; @@ -209,18 +210,23 @@ smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer, cifssmb.c and RFC1001 len is converted to bigendian in smb_send Flags2 is converted in SendReceive */ + + total_len = 0; + for (i = 0; i < n_vec; i++) + total_len += iov[i].iov_len; + smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); - cFYI(1, ("Sending smb: hdrlen %d datalen %d", - smb_hdr_length,datalen)); + cFYI(1, ("Sending smb: total_len %d", total_len)); dump_smb(smb_buffer, len); - while (len + datalen > 0) { - rc = kernel_sendmsg(ssocket, &smb_msg, iov, 2, len); + while (total_len) { + rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec], + n_vec - first_vec, total_len); if ((rc == -ENOSPC) || (rc == -EAGAIN)) { i++; - if(i > 60) { + if(i > 40) { cERROR(1, - ("sends on sock %p stuck for 30 seconds", + ("sends on sock %p stuck for 20 seconds", ssocket)); rc = -EAGAIN; break; @@ -230,43 +236,52 @@ smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer, } if (rc < 0) break; - if(iov[0].iov_len > 0) { - if(rc >= len) { - iov[0].iov_len = 0; - rc -= len; - len = 0; - } else { /* some of hdr was not sent */ - len -= rc; - iov[0].iov_len -= rc; - iov[0].iov_base += rc; - continue; - } + + if (rc >= total_len) { + WARN_ON(rc > total_len); + break; + } + if(rc == 0) { + /* should never happen, letting socket clear before + retrying is our only obvious option here */ + cERROR(1,("tcp sent no data"); + msleep(500); + continue; } - if((iov[0].iov_len == 0) && (rc > 0)){ - iov[1].iov_base += rc; - iov[1].iov_len -= rc; - datalen -= rc; + total_len -= rc; + for (i = first_vec; i < n_vec; i++) { + if (iov[i].iov_len) { + if (rc > iov[i].iov_len) { + rc -= iov[i].iov_len; + iov[i].iov_len = 0; + } else { + iov[i].iov_base += rc; + iov[i].iov_len -= rc; + first_vec = i; + break; + } + } } } if (rc < 0) { - cERROR(1,("Error %d sending data on socket to server.", rc)); - } else { + cERROR(1,("Error %d sending data on socket to server", rc)); + } else rc = 0; - } return rc; } int SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, - struct smb_hdr *in_buf, int hdrlen, const char * data, - int datalen, int *pbytes_returned, const int long_op) + struct kvec *iov, int n_vec, int *pbytes_returned, + const int long_op) { int rc = 0; unsigned int receive_len; unsigned long timeout; struct mid_q_entry *midQ; + struct smb_hdr *in_buf = iov[0].iov_base; if (ses == NULL) { cERROR(1,("Null smb session")); @@ -364,7 +379,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, /* rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */ midQ->midState = MID_REQUEST_SUBMITTED; - rc = smb_send2(ses->server->ssocket, in_buf, hdrlen, data, datalen, + rc = smb_send2(ses->server->ssocket, iov, n_vec, (struct sockaddr *) &(ses->server->addr.sockAddr)); if(rc < 0) { DeleteMidQEntry(midQ); |