From 4d1c44043b26e99dd70f379cdbe80c64f43fd123 Mon Sep 17 00:00:00 2001 From: Mike Marshall Date: Fri, 4 Sep 2015 10:31:16 -0400 Subject: [PATCH] Orangefs: use iov_iter interface replace opencoded pvfs_bufmap_copy_to_kernel_iovec, pvfs_bufmap_copy_to_user_iovec, pvfs_bufmap_copy_iovec_from_kernel, and pvfs_bufmap_copy_iovec_from_user with pvfs_bufmap_copy_to_iovec and pvfs_bufmap_copy_from_iovec, which both use the iov_iter interface. Signed-off-by: Mike Marshall --- fs/orangefs/file.c | 77 +++--- fs/orangefs/pvfs2-bufmap.c | 474 +++---------------------------------- fs/orangefs/pvfs2-bufmap.h | 31 +-- 3 files changed, 72 insertions(+), 510 deletions(-) diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c index 013a07c8bdfd..3e5fc1a2c82f 100644 --- a/fs/orangefs/file.c +++ b/fs/orangefs/file.c @@ -33,31 +33,30 @@ static int precopy_buffers(struct pvfs2_bufmap *bufmap, int buffer_index, const struct iovec *vec, unsigned long nr_segs, - size_t total_size, - int from_user) + size_t total_size) { int ret = 0; + struct iov_iter iter; /* * copy data from application/kernel by pulling it out * of the iovec. */ - /* Are we copying from User Virtual Addresses? */ - if (from_user) - ret = pvfs_bufmap_copy_iovec_from_user( - bufmap, - buffer_index, - vec, - nr_segs, - total_size); - /* Are we copying from Kernel Virtual Addresses? */ - else - ret = pvfs_bufmap_copy_iovec_from_kernel( - bufmap, - buffer_index, - vec, - nr_segs, - total_size); + + + if (total_size) { + iov_iter_init(&iter, WRITE, vec, nr_segs, total_size); + ret = pvfs_bufmap_copy_from_iovec(bufmap, + &iter, + buffer_index, + total_size); + if (ret < 0) + gossip_err("%s: Failed to copy-in buffers. Please make sure that the pvfs2-client is running. %ld\n", + __func__, + (long)ret); + + } + if (ret < 0) gossip_err("%s: Failed to copy-in buffers. Please make sure that the pvfs2-client is running. %ld\n", __func__, @@ -76,35 +75,24 @@ static int postcopy_buffers(struct pvfs2_bufmap *bufmap, int buffer_index, const struct iovec *vec, int nr_segs, - size_t total_size, - int to_user) + size_t total_size) { int ret = 0; + struct iov_iter iter; + /* * copy data to application/kernel by pushing it out to * the iovec. NOTE; target buffers can be addresses or * struct page pointers. */ if (total_size) { - /* Are we copying to User Virtual Addresses? */ - if (to_user) - ret = pvfs_bufmap_copy_to_user_iovec( - bufmap, - buffer_index, - vec, - nr_segs, - total_size); - /* Are we copying to Kern Virtual Addresses? */ - else - ret = pvfs_bufmap_copy_to_kernel_iovec( - bufmap, - buffer_index, - vec, - nr_segs, - total_size); + iov_iter_init(&iter, READ, vec, nr_segs, total_size); + ret = pvfs_bufmap_copy_to_iovec(bufmap, + &iter, + buffer_index); if (ret < 0) - gossip_err("%s: Failed to copy-out buffers. Please make sure that the pvfs2-client is running (%ld)\n", + gossip_err("%s: Failed to copy-out buffers. Please make sure that the pvfs2-client is running (%ld)\n", __func__, (long)ret); } @@ -116,7 +104,7 @@ static int postcopy_buffers(struct pvfs2_bufmap *bufmap, */ static ssize_t wait_for_direct_io(enum PVFS_io_type type, struct inode *inode, loff_t *offset, struct iovec *vec, unsigned long nr_segs, - size_t total_size, loff_t readahead_size, int to_user) + size_t total_size, loff_t readahead_size) { struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(inode); struct pvfs2_khandle *handle = &pvfs2_inode->refn.khandle; @@ -158,10 +146,9 @@ static ssize_t wait_for_direct_io(enum PVFS_io_type type, struct inode *inode, new_op->upcall.req.io.offset = *offset; gossip_debug(GOSSIP_FILE_DEBUG, - "%s(%pU): copy_to_user %d nr_segs %lu, offset: %llu total_size: %zd\n", + "%s(%pU): nr_segs %lu, offset: %llu total_size: %zd\n", __func__, handle, - to_user, nr_segs, llu(*offset), total_size); @@ -174,8 +161,7 @@ static ssize_t wait_for_direct_io(enum PVFS_io_type type, struct inode *inode, buffer_index, vec, nr_segs, - total_size, - to_user); + total_size); if (ret < 0) goto out; } @@ -239,8 +225,7 @@ static ssize_t wait_for_direct_io(enum PVFS_io_type type, struct inode *inode, buffer_index, vec, nr_segs, - new_op->downcall.resp.io.amt_complete, - to_user); + new_op->downcall.resp.io.amt_complete); if (ret < 0) { /* * put error codes in downcall so that handle_io_error() @@ -606,7 +591,7 @@ static ssize_t do_readv_writev(enum PVFS_io_type type, struct file *file, (int)*offset); ret = wait_for_direct_io(type, inode, offset, ptr, - seg_array[seg], each_count, 0, 1); + seg_array[seg], each_count, 0); gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): return from wait_for_io:%d\n", __func__, @@ -699,7 +684,7 @@ ssize_t pvfs2_inode_read(struct inode *inode, llu(*offset)); ret = wait_for_direct_io(PVFS_IO_READ, inode, offset, &vec, 1, - count, readahead_size, 0); + count, readahead_size); if (ret > 0) *offset += ret; diff --git a/fs/orangefs/pvfs2-bufmap.c b/fs/orangefs/pvfs2-bufmap.c index a439163f8d7c..e01e220fd5d7 100644 --- a/fs/orangefs/pvfs2-bufmap.c +++ b/fs/orangefs/pvfs2-bufmap.c @@ -507,468 +507,60 @@ void readdir_index_put(struct pvfs2_bufmap *bufmap, int buffer_index) pvfs2_bufmap_unref(bufmap); } -/* - * pvfs_bufmap_copy_iovec_from_user() - * - * copies data from several user space address's in an iovec - * to a mapped buffer - * - * Note that the mapped buffer is a series of pages and therefore - * the copies have to be split by PAGE_SIZE bytes at a time. - * Note that this routine checks that summation of iov_len - * across all the elements of iov is equal to size. - * - * returns 0 on success, -errno on failure - */ -int pvfs_bufmap_copy_iovec_from_user(struct pvfs2_bufmap *bufmap, - int buffer_index, - const struct iovec *iov, - unsigned long nr_segs, - size_t size) +int pvfs_bufmap_copy_from_iovec(struct pvfs2_bufmap *bufmap, + struct iov_iter *iter, + int buffer_index, + size_t size) { - size_t ret = 0; - size_t amt_copied = 0; - size_t cur_copy_size = 0; - unsigned int to_page_offset = 0; - unsigned int to_page_index = 0; - void *to_kaddr = NULL; - void __user *from_addr = NULL; - struct iovec *copied_iovec = NULL; struct pvfs_bufmap_desc *to; - unsigned int seg; - char *tmp_printer = NULL; - int tmp_int = 0; - - gossip_debug(GOSSIP_BUFMAP_DEBUG, - "pvfs_bufmap_copy_iovec_from_user: index %d, " - "size %zd\n", - buffer_index, - size); - - to = &bufmap->desc_array[buffer_index]; - - /* - * copy the passed in iovec so that we can change some of its fields - */ - copied_iovec = kmalloc_array(nr_segs, - sizeof(*copied_iovec), - PVFS2_BUFMAP_GFP_FLAGS); - if (copied_iovec == NULL) - return -ENOMEM; - - memcpy(copied_iovec, iov, nr_segs * sizeof(*copied_iovec)); - /* - * Go through each segment in the iovec and make sure that - * the summation of iov_len matches the given size. - */ - for (seg = 0, amt_copied = 0; seg < nr_segs; seg++) - amt_copied += copied_iovec[seg].iov_len; - if (amt_copied != size) { - gossip_err( - "pvfs2_bufmap_copy_iovec_from_user: computed total (" - "%zd) is not equal to (%zd)\n", - amt_copied, - size); - kfree(copied_iovec); - return -EINVAL; - } - - to_page_index = 0; - to_page_offset = 0; - amt_copied = 0; - seg = 0; - /* - * Go through each segment in the iovec and copy its - * buffer into the mapped buffer one page at a time though - */ - while (amt_copied < size) { - struct iovec *iv = &copied_iovec[seg]; - int inc_to_page_index; - - if (iv->iov_len < (PAGE_SIZE - to_page_offset)) { - cur_copy_size = - PVFS_util_min(iv->iov_len, size - amt_copied); - seg++; - from_addr = iv->iov_base; - inc_to_page_index = 0; - } else if (iv->iov_len == (PAGE_SIZE - to_page_offset)) { - cur_copy_size = - PVFS_util_min(iv->iov_len, size - amt_copied); - seg++; - from_addr = iv->iov_base; - inc_to_page_index = 1; - } else { - cur_copy_size = - PVFS_util_min(PAGE_SIZE - to_page_offset, - size - amt_copied); - from_addr = iv->iov_base; - iv->iov_base += cur_copy_size; - iv->iov_len -= cur_copy_size; - inc_to_page_index = 1; - } - to_kaddr = pvfs2_kmap(to->page_array[to_page_index]); - ret = - copy_from_user(to_kaddr + to_page_offset, - from_addr, - cur_copy_size); - if (!PageReserved(to->page_array[to_page_index])) - SetPageDirty(to->page_array[to_page_index]); - - if (!tmp_printer) { - tmp_printer = (char *)(to_kaddr + to_page_offset); - tmp_int += tmp_printer[0]; - gossip_debug(GOSSIP_BUFMAP_DEBUG, - "First character (integer value) in pvfs_bufmap_copy_from_user: %d\n", - tmp_int); - } - - pvfs2_kunmap(to->page_array[to_page_index]); - if (ret) { - gossip_err("Failed to copy data from user space\n"); - kfree(copied_iovec); - return -EFAULT; - } - - amt_copied += cur_copy_size; - if (inc_to_page_index) { - to_page_offset = 0; - to_page_index++; - } else { - to_page_offset += cur_copy_size; - } - } - kfree(copied_iovec); - return 0; -} - -/* - * pvfs_bufmap_copy_iovec_from_kernel() - * - * copies data from several kernel space address's in an iovec - * to a mapped buffer - * - * Note that the mapped buffer is a series of pages and therefore - * the copies have to be split by PAGE_SIZE bytes at a time. - * Note that this routine checks that summation of iov_len - * across all the elements of iov is equal to size. - * - * returns 0 on success, -errno on failure - */ -int pvfs_bufmap_copy_iovec_from_kernel(struct pvfs2_bufmap *bufmap, - int buffer_index, const struct iovec *iov, - unsigned long nr_segs, size_t size) -{ - size_t amt_copied = 0; - size_t cur_copy_size = 0; - int to_page_index = 0; - void *to_kaddr = NULL; - void *from_kaddr = NULL; - struct kvec *iv = NULL; - struct iovec *copied_iovec = NULL; - struct pvfs_bufmap_desc *to; - unsigned int seg; - unsigned to_page_offset = 0; + struct page *page; + size_t copied; + int i; gossip_debug(GOSSIP_BUFMAP_DEBUG, - "pvfs_bufmap_copy_iovec_from_kernel: index %d, " - "size %zd\n", - buffer_index, - size); + "%s: buffer_index:%d: size:%lu:\n", + __func__, buffer_index, size); to = &bufmap->desc_array[buffer_index]; - /* - * copy the passed in iovec so that we can change some of its fields - */ - copied_iovec = kmalloc_array(nr_segs, - sizeof(*copied_iovec), - PVFS2_BUFMAP_GFP_FLAGS); - if (copied_iovec == NULL) - return -ENOMEM; - - memcpy(copied_iovec, iov, nr_segs * sizeof(*copied_iovec)); - /* - * Go through each segment in the iovec and make sure that - * the summation of iov_len matches the given size. - */ - for (seg = 0, amt_copied = 0; seg < nr_segs; seg++) - amt_copied += copied_iovec[seg].iov_len; - if (amt_copied != size) { - gossip_err("pvfs2_bufmap_copy_iovec_from_kernel: computed total(%zd) is not equal to (%zd)\n", - amt_copied, - size); - kfree(copied_iovec); - return -EINVAL; - } - to_page_index = 0; - amt_copied = 0; - seg = 0; - to_page_offset = 0; - /* - * Go through each segment in the iovec and copy its - * buffer into the mapped buffer one page at a time though - */ - while (amt_copied < size) { - int inc_to_page_index; - - iv = (struct kvec *) &copied_iovec[seg]; - - if (iv->iov_len < (PAGE_SIZE - to_page_offset)) { - cur_copy_size = - PVFS_util_min(iv->iov_len, size - amt_copied); - seg++; - from_kaddr = iv->iov_base; - inc_to_page_index = 0; - } else if (iv->iov_len == (PAGE_SIZE - to_page_offset)) { - cur_copy_size = - PVFS_util_min(iv->iov_len, size - amt_copied); - seg++; - from_kaddr = iv->iov_base; - inc_to_page_index = 1; - } else { - cur_copy_size = - PVFS_util_min(PAGE_SIZE - to_page_offset, - size - amt_copied); - from_kaddr = iv->iov_base; - iv->iov_base += cur_copy_size; - iv->iov_len -= cur_copy_size; - inc_to_page_index = 1; - } - to_kaddr = pvfs2_kmap(to->page_array[to_page_index]); - memcpy(to_kaddr + to_page_offset, from_kaddr, cur_copy_size); - if (!PageReserved(to->page_array[to_page_index])) - SetPageDirty(to->page_array[to_page_index]); - pvfs2_kunmap(to->page_array[to_page_index]); - amt_copied += cur_copy_size; - if (inc_to_page_index) { - to_page_offset = 0; - to_page_index++; - } else { - to_page_offset += cur_copy_size; - } - } - kfree(copied_iovec); - return 0; -} - -/* - * pvfs_bufmap_copy_to_user_iovec() - * - * copies data to several user space address's in an iovec - * from a mapped buffer - * - * returns 0 on success, -errno on failure - */ -int pvfs_bufmap_copy_to_user_iovec(struct pvfs2_bufmap *bufmap, - int buffer_index, const struct iovec *iov, - unsigned long nr_segs, size_t size) -{ - size_t ret = 0; - size_t amt_copied = 0; - size_t cur_copy_size = 0; - int from_page_index = 0; - void *from_kaddr = NULL; - void __user *to_addr = NULL; - struct iovec *copied_iovec = NULL; - struct pvfs_bufmap_desc *from; - unsigned int seg; - unsigned from_page_offset = 0; - char *tmp_printer = NULL; - int tmp_int = 0; - - gossip_debug(GOSSIP_BUFMAP_DEBUG, - "pvfs_bufmap_copy_to_user_iovec: index %d, size %zd\n", - buffer_index, - size); - - from = &bufmap->desc_array[buffer_index]; - /* - * copy the passed in iovec so that we can change some of its fields - */ - copied_iovec = kmalloc_array(nr_segs, - sizeof(*copied_iovec), - PVFS2_BUFMAP_GFP_FLAGS); - if (copied_iovec == NULL) - return -ENOMEM; - - memcpy(copied_iovec, iov, nr_segs * sizeof(*copied_iovec)); - /* - * Go through each segment in the iovec and make sure that - * the summation of iov_len is greater than the given size. - */ - for (seg = 0, amt_copied = 0; seg < nr_segs; seg++) - amt_copied += copied_iovec[seg].iov_len; - if (amt_copied < size) { - gossip_err("pvfs2_bufmap_copy_to_user_iovec: computed total (%zd) is less than (%zd)\n", - amt_copied, - size); - kfree(copied_iovec); - return -EINVAL; + for (i = 0; size; i++) { + page = to->page_array[i]; + copied = copy_page_from_iter(page, 0, PAGE_SIZE, iter); + size -= copied; + if ((copied == 0) && (size)) + break; } - from_page_index = 0; - amt_copied = 0; - seg = 0; - from_page_offset = 0; - /* - * Go through each segment in the iovec and copy from the mapper buffer, - * but make sure that we do so one page at a time. - */ - while (amt_copied < size) { - struct iovec *iv = &copied_iovec[seg]; - int inc_from_page_index; - - if (iv->iov_len < (PAGE_SIZE - from_page_offset)) { - cur_copy_size = - PVFS_util_min(iv->iov_len, size - amt_copied); - seg++; - to_addr = iv->iov_base; - inc_from_page_index = 0; - } else if (iv->iov_len == (PAGE_SIZE - from_page_offset)) { - cur_copy_size = - PVFS_util_min(iv->iov_len, size - amt_copied); - seg++; - to_addr = iv->iov_base; - inc_from_page_index = 1; - } else { - cur_copy_size = - PVFS_util_min(PAGE_SIZE - from_page_offset, - size - amt_copied); - to_addr = iv->iov_base; - iv->iov_base += cur_copy_size; - iv->iov_len -= cur_copy_size; - inc_from_page_index = 1; - } - from_kaddr = pvfs2_kmap(from->page_array[from_page_index]); - if (!tmp_printer) { - tmp_printer = (char *)(from_kaddr + from_page_offset); - tmp_int += tmp_printer[0]; - gossip_debug(GOSSIP_BUFMAP_DEBUG, - "First character (integer value) in pvfs_bufmap_copy_to_user_iovec: %d\n", - tmp_int); - } - ret = - copy_to_user(to_addr, - from_kaddr + from_page_offset, - cur_copy_size); - pvfs2_kunmap(from->page_array[from_page_index]); - if (ret) { - gossip_err("Failed to copy data to user space\n"); - kfree(copied_iovec); - return -EFAULT; - } + return size ? -EFAULT : 0; - amt_copied += cur_copy_size; - if (inc_from_page_index) { - from_page_offset = 0; - from_page_index++; - } else { - from_page_offset += cur_copy_size; - } - } - kfree(copied_iovec); - return 0; } /* - * pvfs_bufmap_copy_to_kernel_iovec() + * Iterate through the array of pages containing the bytes from + * a file being read. * - * copies data to several kernel space address's in an iovec - * from a mapped buffer - * - * returns 0 on success, -errno on failure */ -int pvfs_bufmap_copy_to_kernel_iovec(struct pvfs2_bufmap *bufmap, - int buffer_index, const struct iovec *iov, - unsigned long nr_segs, size_t size) +int pvfs_bufmap_copy_to_iovec(struct pvfs2_bufmap *bufmap, + struct iov_iter *iter, + int buffer_index) { - size_t amt_copied = 0; - size_t cur_copy_size = 0; - int from_page_index = 0; - void *from_kaddr = NULL; - void *to_kaddr = NULL; - struct kvec *iv; - struct iovec *copied_iovec = NULL; struct pvfs_bufmap_desc *from; - unsigned int seg; - unsigned int from_page_offset = 0; + struct page *page; + int i; + size_t written; gossip_debug(GOSSIP_BUFMAP_DEBUG, - "pvfs_bufmap_copy_to_kernel_iovec: index %d, size %zd\n", - buffer_index, - size); + "%s: buffer_index:%d: iov_iter_count(iter):%lu:\n", + __func__, buffer_index, iov_iter_count(iter)); - from = &bufmap->desc_array[buffer_index]; - /* - * copy the passed in iovec so that we can change some of its fields - */ - copied_iovec = kmalloc_array(nr_segs, - sizeof(*copied_iovec), - PVFS2_BUFMAP_GFP_FLAGS); - if (copied_iovec == NULL) - return -ENOMEM; + from = &bufmap->desc_array[buffer_index]; - memcpy(copied_iovec, iov, nr_segs * sizeof(*copied_iovec)); - /* - * Go through each segment in the iovec and make sure that - * the summation of iov_len is greater than the given size. - */ - for (seg = 0, amt_copied = 0; seg < nr_segs; seg++) - amt_copied += copied_iovec[seg].iov_len; - - if (amt_copied < size) { - gossip_err("pvfs2_bufmap_copy_to_kernel_iovec: computed total (%zd) is less than (%zd)\n", - amt_copied, - size); - kfree(copied_iovec); - return -EINVAL; + for (i = 0; iov_iter_count(iter); i++) { + page = from->page_array[i]; + written = copy_page_to_iter(page, 0, PAGE_SIZE, iter); + if ((written == 0) && (iov_iter_count(iter))) + break; } - from_page_index = 0; - amt_copied = 0; - seg = 0; - from_page_offset = 0; - /* - * Go through each segment in the iovec and copy from the mapper buffer, - * but make sure that we do so one page at a time. - */ - while (amt_copied < size) { - int inc_from_page_index; - - iv = (struct kvec *) &copied_iovec[seg]; - - if (iv->iov_len < (PAGE_SIZE - from_page_offset)) { - cur_copy_size = - PVFS_util_min(iv->iov_len, size - amt_copied); - seg++; - to_kaddr = iv->iov_base; - inc_from_page_index = 0; - } else if (iv->iov_len == (PAGE_SIZE - from_page_offset)) { - cur_copy_size = - PVFS_util_min(iv->iov_len, size - amt_copied); - seg++; - to_kaddr = iv->iov_base; - inc_from_page_index = 1; - } else { - cur_copy_size = - PVFS_util_min(PAGE_SIZE - from_page_offset, - size - amt_copied); - to_kaddr = iv->iov_base; - iv->iov_base += cur_copy_size; - iv->iov_len -= cur_copy_size; - inc_from_page_index = 1; - } - from_kaddr = pvfs2_kmap(from->page_array[from_page_index]); - memcpy(to_kaddr, from_kaddr + from_page_offset, cur_copy_size); - pvfs2_kunmap(from->page_array[from_page_index]); - amt_copied += cur_copy_size; - if (inc_from_page_index) { - from_page_offset = 0; - from_page_index++; - } else { - from_page_offset += cur_copy_size; - } - } - kfree(copied_iovec); - return 0; + return iov_iter_count(iter) ? -EFAULT : 0; } diff --git a/fs/orangefs/pvfs2-bufmap.h b/fs/orangefs/pvfs2-bufmap.h index e269deafbb74..a0f84c045d73 100644 --- a/fs/orangefs/pvfs2-bufmap.h +++ b/fs/orangefs/pvfs2-bufmap.h @@ -42,29 +42,14 @@ int readdir_index_get(struct pvfs2_bufmap **mapp, int *buffer_index); void readdir_index_put(struct pvfs2_bufmap *bufmap, int buffer_index); -int pvfs_bufmap_copy_iovec_from_user(struct pvfs2_bufmap *bufmap, - int buffer_index, - const struct iovec *iov, - unsigned long nr_segs, - size_t size); - -int pvfs_bufmap_copy_iovec_from_kernel(struct pvfs2_bufmap *bufmap, - int buffer_index, - const struct iovec *iov, - unsigned long nr_segs, - size_t size); - -int pvfs_bufmap_copy_to_user_iovec(struct pvfs2_bufmap *bufmap, - int buffer_index, - const struct iovec *iov, - unsigned long nr_segs, - size_t size); - -int pvfs_bufmap_copy_to_kernel_iovec(struct pvfs2_bufmap *bufmap, - int buffer_index, - const struct iovec *iov, - unsigned long nr_segs, - size_t size); +int pvfs_bufmap_copy_from_iovec(struct pvfs2_bufmap *bufmap, + struct iov_iter *iter, + int buffer_index, + size_t size); + +int pvfs_bufmap_copy_to_iovec(struct pvfs2_bufmap *bufmap, + struct iov_iter *iter, + int buffer_index); size_t pvfs_bufmap_copy_to_user_task_iovec(struct task_struct *tsk, struct iovec *iovec, -- 2.45.2