On Thu, 13 Oct 2011 13:20:18 +0400 Pavel Shilovsky <piastryyy@xxxxxxxxx> wrote: > 2011/8/29 Jeff Layton <jlayton@xxxxxxxxxx>: > > Eventually we'll want to allow cifsd to read data directly into the > > pagecache. In order to do that we'll need a routine that can take a > > kvec array and pass that directly to kernel_recvmsg. > > > > Unfortunately though, the kernel's recvmsg routines modify the kvec > > array that gets passed in, so we need to use a copy of the kvec array > > and refresh that copy on each pass through the loop. > > > > Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx> > > --- > > fs/cifs/connect.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++----- > > 1 files changed, 65 insertions(+), 7 deletions(-) > > > > diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c > > index e6da201..08c6b0e 100644 > > --- a/fs/cifs/connect.c > > +++ b/fs/cifs/connect.c > > @@ -375,14 +375,58 @@ server_unresponsive(struct TCP_Server_Info *server) > > return false; > > } > > > > +/* > > + * kvec_array_setup - clone a kvec array, and advance into it > > + * @new: pointer to memory for cloned array > > + * @iov: pointer to original array > > + * @nr_segs: number of members in original array > > + * @bytes: number of bytes to advance into the cloned array > > + * > > + * This function will copy the array provided in iov to a section of memory > > + * and advance the specified number of bytes into the new array. It returns > > + * the number of segments in the new array. "new" must be at least as big as > > + * the original iov array. > > + */ > > +static unsigned int > > +kvec_array_init(struct kvec *new, struct kvec *iov, unsigned int nr_segs, > > I think it should be kvec_array_setup as it said in the description above. > Good catch... Unless there is an objection, I'll also fix this in a follow-on patch to the series. > > + size_t bytes) > > +{ > > + size_t base = 0; > > + > > + while (bytes || !iov->iov_len) { > > + int copy = min(bytes, iov->iov_len); > > + > > + bytes -= copy; > > + base += copy; > > + if (iov->iov_len == base) { > > + iov++; > > + nr_segs--; > > + base = 0; > > + } > > + } > > + memcpy(new, iov, sizeof(*iov) * nr_segs); > > + new->iov_base += base; > > + new->iov_len -= base; > > + return nr_segs; > > +} > > + > > static int > > -read_from_socket(struct TCP_Server_Info *server, char *buf, > > - unsigned int to_read) > > +readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig, > > + unsigned int nr_segs, unsigned int to_read) > > { > > int length = 0; > > int total_read; > > + unsigned int segs; > > struct msghdr smb_msg; > > - struct kvec iov; > > + struct kvec *iov; > > + > > + /* > > + * FIXME: allocation here may cause deadlocks under memory pressure. > > + * Switch this to use a fixed, per-socket buffer. > > + */ > > + iov = kmalloc(sizeof(*iov_orig) * nr_segs, GFP_KERNEL); > > + if (!iov) > > + return -ENOMEM; > > > > smb_msg.msg_control = NULL; > > smb_msg.msg_controllen = 0; > > @@ -393,10 +437,11 @@ read_from_socket(struct TCP_Server_Info *server, char *buf, > > break; > > } > > > > - iov.iov_base = buf + total_read; > > - iov.iov_len = to_read; > > - length = kernel_recvmsg(server->ssocket, &smb_msg, &iov, 1, > > - to_read, 0); > > + segs = kvec_array_init(iov, iov_orig, nr_segs, total_read); > > + > > + length = kernel_recvmsg(server->ssocket, &smb_msg, > > + iov, segs, to_read, 0); > > + > > if (server->tcpStatus == CifsExiting) { > > total_read = -ESHUTDOWN; > > break; > > @@ -423,9 +468,22 @@ read_from_socket(struct TCP_Server_Info *server, char *buf, > > break; > > } > > } > > + kfree(iov); > > return total_read; > > } > > > > +static int > > +read_from_socket(struct TCP_Server_Info *server, char *buf, > > + unsigned int to_read) > > +{ > > + struct kvec iov; > > + > > + iov.iov_base = buf; > > + iov.iov_len = to_read; > > + > > + return readv_from_socket(server, &iov, 1, to_read); > > +} > > + > > static bool > > check_rfc1002_header(struct TCP_Server_Info *server, char *buf) > > { > > -- > > 1.7.6 > > > > -- > > 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 > > > > > > -- > Best regards, > Pavel Shilovsky. -- Jeff Layton <jlayton@xxxxxxxxxx> -- 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