diff options
author | Kent Overstreet <kmo@daterainc.com> | 2014-03-31 16:48:25 -0700 |
---|---|---|
committer | Kent Overstreet <kmo@daterainc.com> | 2014-03-31 17:01:28 -0700 |
commit | d2f9faad6ee77a0011b25bda2307c5bfcfcac832 (patch) | |
tree | c1fb187b0612098df095d42c81a8b81a00ffccec | |
parent | 4d4ee754c4b9a1cfce24e9e6cc287b56bb55d591 (diff) |
block: Use bio_get_user_pages() for __bio_map_user_iov()iov_iter
XXX: block pc bios need to be split by the lower layers
-rw-r--r-- | fs/bio.c | 65 |
1 files changed, 4 insertions, 61 deletions
@@ -1304,14 +1304,10 @@ static struct bio *__bio_map_user_iov(struct request_queue *q, const struct iov_iter *iter, int write_to_vm, gfp_t gfp_mask) { - int j; + ssize_t ret; size_t nr_pages; - struct page **pages; struct bio *bio; - int cur_page = 0; - int ret, offset; struct iov_iter i; - struct iovec iov; if (iov_seg_start_alignment(iter) & queue_dma_alignment(q)) return ERR_PTR(-EINVAL); @@ -1324,57 +1320,11 @@ static struct bio *__bio_map_user_iov(struct request_queue *q, if (!bio) return ERR_PTR(-ENOMEM); - ret = -ENOMEM; - pages = kcalloc(nr_pages, sizeof(struct page *), gfp_mask); - if (!pages) + i = *iter; + ret = bio_get_user_pages(bio, &i, write_to_vm); + if (ret < 0) goto out; - iov_for_each(iov, i, *iter) { - unsigned long uaddr = (unsigned long) iov.iov_base; - unsigned long len = iov.iov_len; - unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - unsigned long start = uaddr >> PAGE_SHIFT; - const int local_nr_pages = end - start; - const int page_limit = cur_page + local_nr_pages; - - ret = get_user_pages_fast(uaddr, local_nr_pages, - write_to_vm, &pages[cur_page]); - if (ret < local_nr_pages) { - ret = -EFAULT; - goto out_unmap; - } - - offset = uaddr & ~PAGE_MASK; - for (j = cur_page; j < page_limit; j++) { - unsigned int bytes = PAGE_SIZE - offset; - - if (len <= 0) - break; - - if (bytes > len) - bytes = len; - - /* - * sorry... - */ - if (bio_add_pc_page(q, bio, pages[j], bytes, offset) < - bytes) - break; - - len -= bytes; - offset = 0; - } - - cur_page = j; - /* - * release the pages we didn't map into the bio, if any - */ - while (j < page_limit) - page_cache_release(pages[j++]); - } - - kfree(pages); - /* * set data direction, and check if mapped pages need bouncing */ @@ -1385,14 +1335,7 @@ static struct bio *__bio_map_user_iov(struct request_queue *q, bio->bi_flags |= (1 << BIO_USER_MAPPED); return bio; - out_unmap: - for (j = 0; j < nr_pages; j++) { - if(!pages[j]) - break; - page_cache_release(pages[j]); - } out: - kfree(pages); bio_put(bio); return ERR_PTR(ret); } |