aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/direct-io.c9
-rw-r--r--fs/fuse/file.c16
-rw-r--r--include/linux/uio.h1
-rw-r--r--mm/iov_iter.c27
4 files changed, 31 insertions, 22 deletions
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 4b410d58faae..98040ba388ac 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -1100,7 +1100,6 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
1100 get_block_t get_block, dio_iodone_t end_io, 1100 get_block_t get_block, dio_iodone_t end_io,
1101 dio_submit_t submit_io, int flags) 1101 dio_submit_t submit_io, int flags)
1102{ 1102{
1103 int seg;
1104 unsigned i_blkbits = ACCESS_ONCE(inode->i_blkbits); 1103 unsigned i_blkbits = ACCESS_ONCE(inode->i_blkbits);
1105 unsigned blkbits = i_blkbits; 1104 unsigned blkbits = i_blkbits;
1106 unsigned blocksize_mask = (1 << blkbits) - 1; 1105 unsigned blocksize_mask = (1 << blkbits) - 1;
@@ -1108,7 +1107,6 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
1108 loff_t end = offset + iov_iter_count(iter); 1107 loff_t end = offset + iov_iter_count(iter);
1109 struct dio *dio; 1108 struct dio *dio;
1110 struct dio_submit sdio = { 0, }; 1109 struct dio_submit sdio = { 0, };
1111 unsigned long user_addr;
1112 struct buffer_head map_bh = { 0, }; 1110 struct buffer_head map_bh = { 0, };
1113 struct blk_plug plug; 1111 struct blk_plug plug;
1114 unsigned long align = offset | iov_iter_alignment(iter); 1112 unsigned long align = offset | iov_iter_alignment(iter);
@@ -1231,12 +1229,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
1231 if (unlikely(sdio.blkfactor)) 1229 if (unlikely(sdio.blkfactor))
1232 sdio.pages_in_io = 2; 1230 sdio.pages_in_io = 2;
1233 1231
1234 for (seg = 0; seg < iter->nr_segs; seg++) { 1232 sdio.pages_in_io += iov_iter_npages(iter, INT_MAX);
1235 user_addr = (unsigned long)iter->iov[seg].iov_base;
1236 sdio.pages_in_io +=
1237 ((user_addr + iter->iov[seg].iov_len + PAGE_SIZE-1) /
1238 PAGE_SIZE - user_addr / PAGE_SIZE);
1239 }
1240 1233
1241 blk_start_plug(&plug); 1234 blk_start_plug(&plug);
1242 1235
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 7db564d18dc6..7026014717bc 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1310,7 +1310,7 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
1310 1310
1311 while (nbytes < *nbytesp && req->num_pages < req->max_pages) { 1311 while (nbytes < *nbytesp && req->num_pages < req->max_pages) {
1312 unsigned npages; 1312 unsigned npages;
1313 size_t start, end, frag_size; 1313 size_t start;
1314 unsigned n = req->max_pages - req->num_pages; 1314 unsigned n = req->max_pages - req->num_pages;
1315 ssize_t ret = iov_iter_get_pages(ii, 1315 ssize_t ret = iov_iter_get_pages(ii,
1316 &req->pages[req->num_pages], 1316 &req->pages[req->num_pages],
@@ -1344,19 +1344,7 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
1344 1344
1345static inline int fuse_iter_npages(const struct iov_iter *ii_p) 1345static inline int fuse_iter_npages(const struct iov_iter *ii_p)
1346{ 1346{
1347 struct iov_iter ii = *ii_p; 1347 return iov_iter_npages(ii_p, FUSE_MAX_PAGES_PER_REQ);
1348 int npages = 0;
1349
1350 while (iov_iter_count(&ii) && npages < FUSE_MAX_PAGES_PER_REQ) {
1351 unsigned long user_addr = fuse_get_user_addr(&ii);
1352 unsigned offset = user_addr & ~PAGE_MASK;
1353 size_t frag_size = iov_iter_single_seg_count(&ii);
1354
1355 npages += (frag_size + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
1356 iov_iter_advance(&ii, frag_size);
1357 }
1358
1359 return min(npages, FUSE_MAX_PAGES_PER_REQ);
1360} 1348}
1361 1349
1362ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, 1350ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
diff --git a/include/linux/uio.h b/include/linux/uio.h
index 341986116d83..2f8825b06680 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -73,6 +73,7 @@ void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov,
73 unsigned long nr_segs, size_t count); 73 unsigned long nr_segs, size_t count);
74ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages, 74ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages,
75 size_t maxsize, size_t *start); 75 size_t maxsize, size_t *start);
76int iov_iter_npages(const struct iov_iter *i, int maxpages);
76 77
77static inline size_t iov_iter_count(struct iov_iter *i) 78static inline size_t iov_iter_count(struct iov_iter *i)
78{ 79{
diff --git a/mm/iov_iter.c b/mm/iov_iter.c
index 45204cd5ccd8..0b677f8f9bad 100644
--- a/mm/iov_iter.c
+++ b/mm/iov_iter.c
@@ -262,3 +262,30 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
262 return (res == n ? len : res * PAGE_SIZE) - *start; 262 return (res == n ? len : res * PAGE_SIZE) - *start;
263} 263}
264EXPORT_SYMBOL(iov_iter_get_pages); 264EXPORT_SYMBOL(iov_iter_get_pages);
265
266int iov_iter_npages(const struct iov_iter *i, int maxpages)
267{
268 size_t offset = i->iov_offset;
269 size_t size = i->count;
270 const struct iovec *iov = i->iov;
271 int npages = 0;
272 int n;
273
274 for (n = 0; size && n < i->nr_segs; n++, iov++) {
275 unsigned long addr = (unsigned long)iov->iov_base + offset;
276 size_t len = iov->iov_len - offset;
277 offset = 0;
278 if (unlikely(!len)) /* empty segment */
279 continue;
280 if (len > size)
281 len = size;
282 npages += (addr + len + PAGE_SIZE - 1) / PAGE_SIZE
283 - addr / PAGE_SIZE;
284 if (npages >= maxpages) /* don't bother going further */
285 return maxpages;
286 size -= len;
287 offset = 0;
288 }
289 return min(npages, maxpages);
290}
291EXPORT_SYMBOL(iov_iter_npages);