aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-04-03 22:31:22 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-05-06 17:39:42 -0400
commit2b777c9dd9ebbb2f8b6818d454cc5e6d7c1e3c8b (patch)
treeaceac852de465a0205a7073496126925620ea7cf
parentf0d1bec9d58d4c038d0ac958c9af82be6eb18045 (diff)
ceph_sync_read: stop poking into iov_iter guts
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/ceph/file.c46
-rw-r--r--include/linux/ceph/libceph.h2
-rw-r--r--net/ceph/pagevec.c35
3 files changed, 22 insertions, 61 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index c9a24ba98c9a..672b0fedb17b 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -418,7 +418,7 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i,
418 struct page **pages; 418 struct page **pages;
419 u64 off = iocb->ki_pos; 419 u64 off = iocb->ki_pos;
420 int num_pages, ret; 420 int num_pages, ret;
421 size_t len = i->count; 421 size_t len = iov_iter_count(i);
422 422
423 dout("sync_read on file %p %llu~%u %s\n", file, off, 423 dout("sync_read on file %p %llu~%u %s\n", file, off,
424 (unsigned)len, 424 (unsigned)len,
@@ -436,25 +436,26 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i,
436 436
437 if (file->f_flags & O_DIRECT) { 437 if (file->f_flags & O_DIRECT) {
438 while (iov_iter_count(i)) { 438 while (iov_iter_count(i)) {
439 void __user *data = i->iov[0].iov_base + i->iov_offset; 439 size_t start;
440 size_t len = i->iov[0].iov_len - i->iov_offset; 440 ssize_t n;
441 441
442 num_pages = calc_pages_for((unsigned long)data, len); 442 n = iov_iter_get_pages_alloc(i, &pages, INT_MAX, &start);
443 pages = ceph_get_direct_page_vector(data, 443 if (n < 0)
444 num_pages, true); 444 return n;
445 if (IS_ERR(pages))
446 return PTR_ERR(pages);
447 445
448 ret = striped_read(inode, off, len, 446 num_pages = (n + start + PAGE_SIZE - 1) / PAGE_SIZE;
447
448 ret = striped_read(inode, off, n,
449 pages, num_pages, checkeof, 449 pages, num_pages, checkeof,
450 1, (unsigned long)data & ~PAGE_MASK); 450 1, start);
451
451 ceph_put_page_vector(pages, num_pages, true); 452 ceph_put_page_vector(pages, num_pages, true);
452 453
453 if (ret <= 0) 454 if (ret <= 0)
454 break; 455 break;
455 off += ret; 456 off += ret;
456 iov_iter_advance(i, ret); 457 iov_iter_advance(i, ret);
457 if (ret < len) 458 if (ret < n)
458 break; 459 break;
459 } 460 }
460 } else { 461 } else {
@@ -466,25 +467,14 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i,
466 num_pages, checkeof, 0, 0); 467 num_pages, checkeof, 0, 0);
467 if (ret > 0) { 468 if (ret > 0) {
468 int l, k = 0; 469 int l, k = 0;
469 size_t left = len = ret; 470 size_t left = ret;
470 471
471 while (left) { 472 while (left) {
472 void __user *data = i->iov[0].iov_base 473 int copy = min_t(size_t, PAGE_SIZE, left);
473 + i->iov_offset; 474 l = copy_page_to_iter(pages[k++], 0, copy, i);
474 l = min(i->iov[0].iov_len - i->iov_offset, 475 off += l;
475 left); 476 left -= l;
476 477 if (l < copy)
477 ret = ceph_copy_page_vector_to_user(&pages[k],
478 data, off,
479 l);
480 if (ret > 0) {
481 iov_iter_advance(i, ret);
482 left -= ret;
483 off += ret;
484 k = calc_pages_for(iocb->ki_pos,
485 len - left + 1) - 1;
486 BUG_ON(k >= num_pages && left);
487 } else
488 break; 478 break;
489 } 479 }
490 } 480 }
diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h
index 2f49aa4c4f7f..279b0afac1c1 100644
--- a/include/linux/ceph/libceph.h
+++ b/include/linux/ceph/libceph.h
@@ -222,8 +222,6 @@ extern void ceph_copy_to_page_vector(struct page **pages,
222extern void ceph_copy_from_page_vector(struct page **pages, 222extern void ceph_copy_from_page_vector(struct page **pages,
223 void *data, 223 void *data,
224 loff_t off, size_t len); 224 loff_t off, size_t len);
225extern int ceph_copy_page_vector_to_user(struct page **pages, void __user *data,
226 loff_t off, size_t len);
227extern void ceph_zero_page_vector_range(int off, int len, struct page **pages); 225extern void ceph_zero_page_vector_range(int off, int len, struct page **pages);
228 226
229 227
diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c
index 815a2249cfa9..555013034f7a 100644
--- a/net/ceph/pagevec.c
+++ b/net/ceph/pagevec.c
@@ -53,7 +53,10 @@ void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty)
53 set_page_dirty_lock(pages[i]); 53 set_page_dirty_lock(pages[i]);
54 put_page(pages[i]); 54 put_page(pages[i]);
55 } 55 }
56 kfree(pages); 56 if (is_vmalloc_addr(pages))
57 vfree(pages);
58 else
59 kfree(pages);
57} 60}
58EXPORT_SYMBOL(ceph_put_page_vector); 61EXPORT_SYMBOL(ceph_put_page_vector);
59 62
@@ -165,36 +168,6 @@ void ceph_copy_from_page_vector(struct page **pages,
165EXPORT_SYMBOL(ceph_copy_from_page_vector); 168EXPORT_SYMBOL(ceph_copy_from_page_vector);
166 169
167/* 170/*
168 * copy user data from a page vector into a user pointer
169 */
170int ceph_copy_page_vector_to_user(struct page **pages,
171 void __user *data,
172 loff_t off, size_t len)
173{
174 int i = 0;
175 int po = off & ~PAGE_CACHE_MASK;
176 int left = len;
177 int l, bad;
178
179 while (left > 0) {
180 l = min_t(int, left, PAGE_CACHE_SIZE-po);
181 bad = copy_to_user(data, page_address(pages[i]) + po, l);
182 if (bad == l)
183 return -EFAULT;
184 data += l - bad;
185 left -= l - bad;
186 if (po) {
187 po += l - bad;
188 if (po == PAGE_CACHE_SIZE)
189 po = 0;
190 }
191 i++;
192 }
193 return len;
194}
195EXPORT_SYMBOL(ceph_copy_page_vector_to_user);
196
197/*
198 * Zero an extent within a page vector. Offset is relative to the 171 * Zero an extent within a page vector. Offset is relative to the
199 * start of the first page. 172 * start of the first page.
200 */ 173 */