Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 326289
b: refs/heads/master
c: 6f49f46
h: refs/heads/master
i:
  326287: 52baaf5
v: v3
  • Loading branch information
Jeff Layton authored and Steve French committed Sep 25, 2012
1 parent 7ef46ef commit 92efa01
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 46 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0b688cfc8b3472f5bad104abe0675a060e32ad7b
refs/heads/master: 6f49f46b187df34539f1e5df2469b8a541897700
135 changes: 90 additions & 45 deletions trunk/fs/cifs/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,18 +119,29 @@ cifs_delete_mid(struct mid_q_entry *mid)
DeleteMidQEntry(mid);
}

/*
* smb_send_kvec - send an array of kvecs to the server
* @server: Server to send the data to
* @iov: Pointer to array of kvecs
* @n_vec: length of kvec array
* @sent: amount of data sent on socket is stored here
*
* Our basic "send data to server" function. Should be called with srv_mutex
* held. The caller is responsible for handling the results.
*/
static int
smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec,
size_t *sent)
{
int rc = 0;
int i = 0;
struct msghdr smb_msg;
unsigned int len = iov[0].iov_len;
unsigned int total_len;
int first_vec = 0;
unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
unsigned int remaining;
size_t first_vec = 0;
struct socket *ssocket = server->ssocket;

*sent = 0;

if (ssocket == NULL)
return -ENOTSOCK; /* BB eventually add reconnect code here */

Expand All @@ -143,64 +154,70 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
else
smb_msg.msg_flags = MSG_NOSIGNAL;

total_len = 0;
remaining = 0;
for (i = 0; i < n_vec; i++)
total_len += iov[i].iov_len;

cFYI(1, "Sending smb: total_len %d", total_len);
dump_smb(iov[0].iov_base, len);
remaining += iov[i].iov_len;

i = 0;
while (total_len) {
while (remaining) {
/*
* If blocking send, we try 3 times, since each can block
* for 5 seconds. For nonblocking we have to try more
* but wait increasing amounts of time allowing time for
* socket to clear. The overall time we wait in either
* case to send on the socket is about 15 seconds.
* Similarly we wait for 15 seconds for a response from
* the server in SendReceive[2] for the server to send
* a response back for most types of requests (except
* SMB Write past end of file which can be slow, and
* blocking lock operations). NFS waits slightly longer
* than CIFS, but this can make it take longer for
* nonresponsive servers to be detected and 15 seconds
* is more than enough time for modern networks to
* send a packet. In most cases if we fail to send
* after the retries we will kill the socket and
* reconnect which may clear the network problem.
*/
rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
n_vec - first_vec, total_len);
if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
n_vec - first_vec, remaining);
if (rc == -ENOSPC || rc == -EAGAIN) {
i++;
/*
* If blocking send we try 3 times, since each can block
* for 5 seconds. For nonblocking we have to try more
* but wait increasing amounts of time allowing time for
* socket to clear. The overall time we wait in either
* case to send on the socket is about 15 seconds.
* Similarly we wait for 15 seconds for a response from
* the server in SendReceive[2] for the server to send
* a response back for most types of requests (except
* SMB Write past end of file which can be slow, and
* blocking lock operations). NFS waits slightly longer
* than CIFS, but this can make it take longer for
* nonresponsive servers to be detected and 15 seconds
* is more than enough time for modern networks to
* send a packet. In most cases if we fail to send
* after the retries we will kill the socket and
* reconnect which may clear the network problem.
*/
if ((i >= 14) || (!server->noblocksnd && (i > 2))) {
cERROR(1, "sends on sock %p stuck for 15 seconds",
ssocket);
if (i >= 14 || (!server->noblocksnd && (i > 2))) {
cERROR(1, "sends on sock %p stuck for 15 "
"seconds", ssocket);
rc = -EAGAIN;
break;
}
msleep(1 << i);
continue;
}

if (rc < 0)
break;

if (rc == total_len) {
total_len = 0;
/* send was at least partially successful */
*sent += rc;

if (rc == remaining) {
remaining = 0;
break;
} else if (rc > total_len) {
cERROR(1, "sent %d requested %d", rc, total_len);
}

if (rc > remaining) {
cERROR(1, "sent %d requested %d", rc, remaining);
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;
}
total_len -= rc;

remaining -= rc;

/* the line below resets i */
for (i = first_vec; i < n_vec; i++) {
if (iov[i].iov_len) {
Expand All @@ -215,16 +232,35 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
}
}
}

i = 0; /* in case we get ENOSPC on the next send */
rc = 0;
}
return rc;
}

static int
smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
{
int rc;
struct kvec *iov = rqst->rq_iov;
int n_vec = rqst->rq_nvec;
unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
size_t total_len;

cFYI(1, "Sending smb: smb_len=%u", smb_buf_length);
dump_smb(iov[0].iov_base, iov[0].iov_len);

rc = smb_send_kvec(server, iov, n_vec, &total_len);

if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
cFYI(1, "partial send (%d remaining), terminating session",
total_len);
/* If we have only sent part of an SMB then the next SMB
could be taken as the remainder of this one. We need
to kill the socket so the server throws away the partial
SMB */
cFYI(1, "partial send (wanted=%u sent=%zu): terminating "
"session", smb_buf_length + 4, total_len);
/*
* If we have only sent part of an SMB then the next SMB could
* be taken as the remainder of this one. We need to kill the
* socket so the server throws away the partial SMB
*/
server->tcpStatus = CifsNeedReconnect;
}

Expand All @@ -236,6 +272,15 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
return rc;
}

static int
smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
{
struct smb_rqst rqst = { .rq_iov = iov,
.rq_nvec = n_vec };

return smb_send_rqst(server, &rqst);
}

int
smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
unsigned int smb_buf_length)
Expand Down

0 comments on commit 92efa01

Please sign in to comment.