cifs: convert send code to use smb_rqst structs
authorJeff Layton <jlayton@redhat.com>
Tue, 18 Sep 2012 23:20:34 +0000 (16:20 -0700)
committerSteve French <smfrench@gmail.com>
Tue, 25 Sep 2012 02:46:31 +0000 (21:46 -0500)
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>
fs/cifs/transport.c

index bc9ccddad9377876e4736740dfb0c407d9371b73..766307b725bd4eecd330c787e6bcaf9020debcd1 100644 (file)
@@ -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 */
 
@@ -143,56 +154,60 @@ 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 */
@@ -200,7 +215,9 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
                        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) {
@@ -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;
        }
 
@@ -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)