2012/7/18 Jeff Layton <jlayton@xxxxxxxxxx>: > 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. > > Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx> > --- > fs/cifs/transport.c | 135 ++++++++++++++++++++++++++++++++++----------------- > 1 file changed, 90 insertions(+), 45 deletions(-) > > diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c > index 531da42..5a1d817 100644 > --- a/fs/cifs/transport.c > +++ b/fs/cifs/transport.c > @@ -120,18 +120,29 @@ 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 */ > > @@ -144,56 +155,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 */ > @@ -201,7 +216,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) { > @@ -216,16 +233,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; > } > > @@ -237,6 +273,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) > -- > 1.7.10.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html Looks good. Reviewed-by: Pavel Shilovsky <pshilovsky@xxxxxxxxx> -- Best regards, Pavel Shilovsky. -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html