Commit 6f49f46b authored by Jeff Layton's avatar Jeff Layton Committed by Steve French

cifs: convert send code to use smb_rqst structs

Again, just a change in the arguments and some function renaming here.
In later patches, we'll change this code to deal with page arrays.

In this patch, we add a new smb_send_rqst wrapper and have smb_sendv
call that. Then we move most of the existing smb_sendv code into a new
function -- smb_send_kvec. This seems a little redundant, but later
we'll flesh this out to deal with arrays of pages.
Reviewed-by: default avatarPavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent 0b688cfc
...@@ -119,18 +119,29 @@ cifs_delete_mid(struct mid_q_entry *mid) ...@@ -119,18 +119,29 @@ cifs_delete_mid(struct mid_q_entry *mid)
DeleteMidQEntry(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 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 rc = 0;
int i = 0; int i = 0;
struct msghdr smb_msg; struct msghdr smb_msg;
unsigned int len = iov[0].iov_len; unsigned int remaining;
unsigned int total_len; size_t first_vec = 0;
int first_vec = 0;
unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
struct socket *ssocket = server->ssocket; struct socket *ssocket = server->ssocket;
*sent = 0;
if (ssocket == NULL) if (ssocket == NULL)
return -ENOTSOCK; /* BB eventually add reconnect code here */ return -ENOTSOCK; /* BB eventually add reconnect code here */
...@@ -143,56 +154,60 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) ...@@ -143,56 +154,60 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
else else
smb_msg.msg_flags = MSG_NOSIGNAL; smb_msg.msg_flags = MSG_NOSIGNAL;
total_len = 0; remaining = 0;
for (i = 0; i < n_vec; i++) for (i = 0; i < n_vec; i++)
total_len += iov[i].iov_len; remaining += iov[i].iov_len;
cFYI(1, "Sending smb: total_len %d", total_len);
dump_smb(iov[0].iov_base, len);
i = 0; 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], rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
n_vec - first_vec, total_len); n_vec - first_vec, remaining);
if ((rc == -ENOSPC) || (rc == -EAGAIN)) { if (rc == -ENOSPC || rc == -EAGAIN) {
i++; i++;
/* if (i >= 14 || (!server->noblocksnd && (i > 2))) {
* If blocking send we try 3 times, since each can block cERROR(1, "sends on sock %p stuck for 15 "
* for 5 seconds. For nonblocking we have to try more "seconds", ssocket);
* 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);
rc = -EAGAIN; rc = -EAGAIN;
break; break;
} }
msleep(1 << i); msleep(1 << i);
continue; continue;
} }
if (rc < 0) if (rc < 0)
break; break;
if (rc == total_len) { /* send was at least partially successful */
total_len = 0; *sent += rc;
if (rc == remaining) {
remaining = 0;
break; 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; break;
} }
if (rc == 0) { if (rc == 0) {
/* should never happen, letting socket clear before /* should never happen, letting socket clear before
retrying is our only obvious option here */ retrying is our only obvious option here */
...@@ -200,7 +215,9 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) ...@@ -200,7 +215,9 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
msleep(500); msleep(500);
continue; continue;
} }
total_len -= rc;
remaining -= rc;
/* the line below resets i */ /* the line below resets i */
for (i = first_vec; i < n_vec; i++) { for (i = first_vec; i < n_vec; i++) {
if (iov[i].iov_len) { if (iov[i].iov_len) {
...@@ -215,16 +232,35 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) ...@@ -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 */ 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)) { if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
cFYI(1, "partial send (%d remaining), terminating session", cFYI(1, "partial send (wanted=%u sent=%zu): terminating "
total_len); "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 * If we have only sent part of an SMB then the next SMB could
to kill the socket so the server throws away the partial * be taken as the remainder of this one. We need to kill the
SMB */ * socket so the server throws away the partial SMB
*/
server->tcpStatus = CifsNeedReconnect; server->tcpStatus = CifsNeedReconnect;
} }
...@@ -236,6 +272,15 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) ...@@ -236,6 +272,15 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
return rc; 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 int
smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
unsigned int smb_buf_length) unsigned int smb_buf_length)
......
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