ceph_sync_read: stop poking into iov_iter guts
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
f0d1bec9d5
commit
2b777c9dd9
3 changed files with 22 additions and 61 deletions
|
@ -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,
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
ret = striped_read(inode, off, len,
|
num_pages = (n + start + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||||
|
|
||||||
|
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,
|
||||||
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,
|
||||||
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)
|
||||||
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,
|
||||||
}
|
}
|
||||||
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.
|
||||||
|
|
Loading…
Add table
Reference in a new issue