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. > + 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. -- 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