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: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
parent
0b688cfc8b
commit
6f49f46b18
1 changed files with 91 additions and 46 deletions
|
@ -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)
|
||||||
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;
|
||||||
break;
|
|
||||||
} else if (rc > total_len) {
|
if (rc == remaining) {
|
||||||
cERROR(1, "sent %d requested %d", rc, total_len);
|
remaining = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rc > remaining) {
|
||||||
|
cERROR(1, "sent %d requested %d", rc, remaining);
|
||||||
|
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
Loading…
Reference in a new issue