forked from luck/tmp_suning_uos_patched
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:
parent
81b784b11e
commit
4d1c44043b
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue
Block a user