Commit 2b777c9d authored by Al Viro's avatar Al Viro

ceph_sync_read: stop poking into iov_iter guts

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent f0d1bec9
...@@ -418,7 +418,7 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i, ...@@ -418,7 +418,7 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i,
struct page **pages; struct page **pages;
u64 off = iocb->ki_pos; u64 off = iocb->ki_pos;
int num_pages, ret; int num_pages, ret;
size_t len = i->count; size_t len = iov_iter_count(i);
dout("sync_read on file %p %llu~%u %s\n", file, off, dout("sync_read on file %p %llu~%u %s\n", file, off,
(unsigned)len, (unsigned)len,
...@@ -436,25 +436,26 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i, ...@@ -436,25 +436,26 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i,
if (file->f_flags & O_DIRECT) { if (file->f_flags & O_DIRECT) {
while (iov_iter_count(i)) { while (iov_iter_count(i)) {
void __user *data = i->iov[0].iov_base + i->iov_offset; size_t start;
size_t len = i->iov[0].iov_len - i->iov_offset; ssize_t n;
num_pages = calc_pages_for((unsigned long)data, len); n = iov_iter_get_pages_alloc(i, &pages, INT_MAX, &start);
pages = ceph_get_direct_page_vector(data, if (n < 0)
num_pages, true); return n;
if (IS_ERR(pages))
return PTR_ERR(pages); num_pages = (n + start + PAGE_SIZE - 1) / PAGE_SIZE;
ret = striped_read(inode, off, len, ret = striped_read(inode, off, n,
pages, num_pages, checkeof, pages, num_pages, checkeof,
1, (unsigned long)data & ~PAGE_MASK); 1, start);
ceph_put_page_vector(pages, num_pages, true); ceph_put_page_vector(pages, num_pages, true);
if (ret <= 0) if (ret <= 0)
break; break;
off += ret; off += ret;
iov_iter_advance(i, ret); iov_iter_advance(i, ret);
if (ret < len) if (ret < n)
break; break;
} }
} else { } else {
...@@ -466,25 +467,14 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i, ...@@ -466,25 +467,14 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i,
num_pages, checkeof, 0, 0); num_pages, checkeof, 0, 0);
if (ret > 0) { if (ret > 0) {
int l, k = 0; int l, k = 0;
size_t left = len = ret; size_t left = ret;
while (left) { while (left) {
void __user *data = i->iov[0].iov_base int copy = min_t(size_t, PAGE_SIZE, left);
+ i->iov_offset; l = copy_page_to_iter(pages[k++], 0, copy, i);
l = min(i->iov[0].iov_len - i->iov_offset, off += l;
left); left -= l;
if (l < copy)
ret = ceph_copy_page_vector_to_user(&pages[k],
data, off,
l);
if (ret > 0) {
iov_iter_advance(i, ret);
left -= ret;
off += ret;
k = calc_pages_for(iocb->ki_pos,
len - left + 1) - 1;
BUG_ON(k >= num_pages && left);
} else
break; break;
} }
} }
......
...@@ -222,8 +222,6 @@ extern void ceph_copy_to_page_vector(struct page **pages, ...@@ -222,8 +222,6 @@ extern void ceph_copy_to_page_vector(struct page **pages,
extern void ceph_copy_from_page_vector(struct page **pages, extern void ceph_copy_from_page_vector(struct page **pages,
void *data, void *data,
loff_t off, size_t len); loff_t off, size_t len);
extern int ceph_copy_page_vector_to_user(struct page **pages, void __user *data,
loff_t off, size_t len);
extern void ceph_zero_page_vector_range(int off, int len, struct page **pages); extern void ceph_zero_page_vector_range(int off, int len, struct page **pages);
......
...@@ -53,6 +53,9 @@ void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty) ...@@ -53,6 +53,9 @@ void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty)
set_page_dirty_lock(pages[i]); set_page_dirty_lock(pages[i]);
put_page(pages[i]); put_page(pages[i]);
} }
if (is_vmalloc_addr(pages))
vfree(pages);
else
kfree(pages); kfree(pages);
} }
EXPORT_SYMBOL(ceph_put_page_vector); EXPORT_SYMBOL(ceph_put_page_vector);
...@@ -164,36 +167,6 @@ void ceph_copy_from_page_vector(struct page **pages, ...@@ -164,36 +167,6 @@ void ceph_copy_from_page_vector(struct page **pages,
} }
EXPORT_SYMBOL(ceph_copy_from_page_vector); EXPORT_SYMBOL(ceph_copy_from_page_vector);
/*
* copy user data from a page vector into a user pointer
*/
int ceph_copy_page_vector_to_user(struct page **pages,
void __user *data,
loff_t off, size_t len)
{
int i = 0;
int po = off & ~PAGE_CACHE_MASK;
int left = len;
int l, bad;
while (left > 0) {
l = min_t(int, left, PAGE_CACHE_SIZE-po);
bad = copy_to_user(data, page_address(pages[i]) + po, l);
if (bad == l)
return -EFAULT;
data += l - bad;
left -= l - bad;
if (po) {
po += l - bad;
if (po == PAGE_CACHE_SIZE)
po = 0;
}
i++;
}
return len;
}
EXPORT_SYMBOL(ceph_copy_page_vector_to_user);
/* /*
* Zero an extent within a page vector. Offset is relative to the * Zero an extent within a page vector. Offset is relative to the
* start of the first page. * start of the first page.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment