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 <hubcap@omnibond.com>
This commit is contained in:
Mike Marshall 2015-09-04 10:31:16 -04:00
parent 81b784b11e
commit 4d1c44043b
3 changed files with 71 additions and 509 deletions

View File

@ -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;

View File

@ -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;
struct page *page;
size_t copied;
int i;
gossip_debug(GOSSIP_BUFMAP_DEBUG,
"pvfs_bufmap_copy_iovec_from_user: 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_user: computed total ("
"%zd) is not equal to (%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;
}
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;
return size ? -EFAULT : 0;
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()
* Iterate through the array of pages containing the bytes from
* a file being read.
*
* 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)
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 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;
gossip_debug(GOSSIP_BUFMAP_DEBUG,
"pvfs_bufmap_copy_iovec_from_kernel: 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_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;
struct page *page;
int i;
size_t written;
gossip_debug(GOSSIP_BUFMAP_DEBUG,
"pvfs_bufmap_copy_to_user_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_user_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) {
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;
}
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()
*
* 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)
{
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;
gossip_debug(GOSSIP_BUFMAP_DEBUG,
"pvfs_bufmap_copy_to_kernel_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_kernel_iovec: computed total (%zd) is less than (%zd)\n",
amt_copied,
size);
kfree(copied_iovec);
return -EINVAL;
}
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;
}

View File

@ -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_from_iovec(struct pvfs2_bufmap *bufmap,
struct iov_iter *iter,
int buffer_index,
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_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,