diff options
-rw-r--r-- | fs/bio.c | 54 |
1 files changed, 4 insertions, 50 deletions
@@ -995,48 +995,13 @@ static void bio_copy_kern_endio(struct bio *bio, int err) | |||
995 | struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len, | 995 | struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len, |
996 | gfp_t gfp_mask, int reading) | 996 | gfp_t gfp_mask, int reading) |
997 | { | 997 | { |
998 | unsigned long kaddr = (unsigned long)data; | ||
999 | unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
1000 | unsigned long start = kaddr >> PAGE_SHIFT; | ||
1001 | const int nr_pages = end - start; | ||
1002 | struct bio *bio; | 998 | struct bio *bio; |
1003 | struct bio_vec *bvec; | 999 | struct bio_vec *bvec; |
1004 | struct bio_map_data *bmd; | 1000 | int i; |
1005 | int i, ret; | ||
1006 | struct sg_iovec iov; | ||
1007 | |||
1008 | iov.iov_base = data; | ||
1009 | iov.iov_len = len; | ||
1010 | |||
1011 | bmd = bio_alloc_map_data(nr_pages, 1, gfp_mask); | ||
1012 | if (!bmd) | ||
1013 | return ERR_PTR(-ENOMEM); | ||
1014 | |||
1015 | ret = -ENOMEM; | ||
1016 | bio = bio_alloc(gfp_mask, nr_pages); | ||
1017 | if (!bio) | ||
1018 | goto out_bmd; | ||
1019 | |||
1020 | while (len) { | ||
1021 | struct page *page; | ||
1022 | unsigned int bytes = PAGE_SIZE; | ||
1023 | |||
1024 | if (bytes > len) | ||
1025 | bytes = len; | ||
1026 | |||
1027 | page = alloc_page(q->bounce_gfp | gfp_mask); | ||
1028 | if (!page) { | ||
1029 | ret = -ENOMEM; | ||
1030 | goto cleanup; | ||
1031 | } | ||
1032 | |||
1033 | if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes) { | ||
1034 | ret = -EINVAL; | ||
1035 | goto cleanup; | ||
1036 | } | ||
1037 | 1001 | ||
1038 | len -= bytes; | 1002 | bio = bio_copy_user(q, NULL, (unsigned long)data, len, 1, gfp_mask); |
1039 | } | 1003 | if (IS_ERR(bio)) |
1004 | return bio; | ||
1040 | 1005 | ||
1041 | if (!reading) { | 1006 | if (!reading) { |
1042 | void *p = data; | 1007 | void *p = data; |
@@ -1049,20 +1014,9 @@ struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len, | |||
1049 | } | 1014 | } |
1050 | } | 1015 | } |
1051 | 1016 | ||
1052 | bio->bi_private = bmd; | ||
1053 | bio->bi_end_io = bio_copy_kern_endio; | 1017 | bio->bi_end_io = bio_copy_kern_endio; |
1054 | 1018 | ||
1055 | bio_set_map_data(bmd, bio, &iov, 1, 1); | ||
1056 | return bio; | 1019 | return bio; |
1057 | cleanup: | ||
1058 | bio_for_each_segment(bvec, bio, i) | ||
1059 | __free_page(bvec->bv_page); | ||
1060 | |||
1061 | bio_put(bio); | ||
1062 | out_bmd: | ||
1063 | bio_free_map_data(bmd); | ||
1064 | |||
1065 | return ERR_PTR(ret); | ||
1066 | } | 1020 | } |
1067 | 1021 | ||
1068 | /* | 1022 | /* |