Commit ce386181 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull vfs fixes from Al Viro:
 "Fairly old DIO bug caught by Andreas (3.10+) and several slightly
  younger blk_rq_map_user_iov() bugs, both on map and copy codepaths
  (Vitaly and me)"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  bio_copy_user_iov(): don't ignore ->iov_offset
  more bio_map_user_iov() leak fixes
  fix unbalanced page refcounting in bio_map_user_iov
  direct-io: Prevent NULL pointer access in submit_page_section
parents a957fd42 1cfd0ddd
...@@ -1239,8 +1239,8 @@ struct bio *bio_copy_user_iov(struct request_queue *q, ...@@ -1239,8 +1239,8 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
*/ */
bmd->is_our_pages = map_data ? 0 : 1; bmd->is_our_pages = map_data ? 0 : 1;
memcpy(bmd->iov, iter->iov, sizeof(struct iovec) * iter->nr_segs); memcpy(bmd->iov, iter->iov, sizeof(struct iovec) * iter->nr_segs);
iov_iter_init(&bmd->iter, iter->type, bmd->iov, bmd->iter = *iter;
iter->nr_segs, iter->count); bmd->iter.iov = bmd->iov;
ret = -ENOMEM; ret = -ENOMEM;
bio = bio_kmalloc(gfp_mask, nr_pages); bio = bio_kmalloc(gfp_mask, nr_pages);
...@@ -1331,6 +1331,7 @@ struct bio *bio_map_user_iov(struct request_queue *q, ...@@ -1331,6 +1331,7 @@ struct bio *bio_map_user_iov(struct request_queue *q,
int ret, offset; int ret, offset;
struct iov_iter i; struct iov_iter i;
struct iovec iov; struct iovec iov;
struct bio_vec *bvec;
iov_for_each(iov, i, *iter) { iov_for_each(iov, i, *iter) {
unsigned long uaddr = (unsigned long) iov.iov_base; unsigned long uaddr = (unsigned long) iov.iov_base;
...@@ -1375,7 +1376,12 @@ struct bio *bio_map_user_iov(struct request_queue *q, ...@@ -1375,7 +1376,12 @@ struct bio *bio_map_user_iov(struct request_queue *q,
ret = get_user_pages_fast(uaddr, local_nr_pages, ret = get_user_pages_fast(uaddr, local_nr_pages,
(iter->type & WRITE) != WRITE, (iter->type & WRITE) != WRITE,
&pages[cur_page]); &pages[cur_page]);
if (ret < local_nr_pages) { if (unlikely(ret < local_nr_pages)) {
for (j = cur_page; j < page_limit; j++) {
if (!pages[j])
break;
put_page(pages[j]);
}
ret = -EFAULT; ret = -EFAULT;
goto out_unmap; goto out_unmap;
} }
...@@ -1383,6 +1389,7 @@ struct bio *bio_map_user_iov(struct request_queue *q, ...@@ -1383,6 +1389,7 @@ struct bio *bio_map_user_iov(struct request_queue *q,
offset = offset_in_page(uaddr); offset = offset_in_page(uaddr);
for (j = cur_page; j < page_limit; j++) { for (j = cur_page; j < page_limit; j++) {
unsigned int bytes = PAGE_SIZE - offset; unsigned int bytes = PAGE_SIZE - offset;
unsigned short prev_bi_vcnt = bio->bi_vcnt;
if (len <= 0) if (len <= 0)
break; break;
...@@ -1397,6 +1404,13 @@ struct bio *bio_map_user_iov(struct request_queue *q, ...@@ -1397,6 +1404,13 @@ struct bio *bio_map_user_iov(struct request_queue *q,
bytes) bytes)
break; break;
/*
* check if vector was merged with previous
* drop page reference if needed
*/
if (bio->bi_vcnt == prev_bi_vcnt)
put_page(pages[j]);
len -= bytes; len -= bytes;
offset = 0; offset = 0;
} }
...@@ -1423,10 +1437,8 @@ struct bio *bio_map_user_iov(struct request_queue *q, ...@@ -1423,10 +1437,8 @@ struct bio *bio_map_user_iov(struct request_queue *q,
return bio; return bio;
out_unmap: out_unmap:
for (j = 0; j < nr_pages; j++) { bio_for_each_segment_all(bvec, bio, j) {
if (!pages[j]) put_page(bvec->bv_page);
break;
put_page(pages[j]);
} }
out: out:
kfree(pages); kfree(pages);
......
...@@ -866,7 +866,8 @@ submit_page_section(struct dio *dio, struct dio_submit *sdio, struct page *page, ...@@ -866,7 +866,8 @@ submit_page_section(struct dio *dio, struct dio_submit *sdio, struct page *page,
*/ */
if (sdio->boundary) { if (sdio->boundary) {
ret = dio_send_cur_page(dio, sdio, map_bh); ret = dio_send_cur_page(dio, sdio, map_bh);
dio_bio_submit(dio, sdio); if (sdio->bio)
dio_bio_submit(dio, sdio);
put_page(sdio->cur_page); put_page(sdio->cur_page);
sdio->cur_page = NULL; sdio->cur_page = NULL;
} }
......
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