diff options
author | Kent Overstreet <koverstreet@google.com> | 2012-09-10 17:03:28 -0400 |
---|---|---|
committer | Kent Overstreet <koverstreet@google.com> | 2013-03-23 17:26:31 -0400 |
commit | a07876064a0b73ab5ef1ebcf14b1cf0231c07858 (patch) | |
tree | 74a0567401bcdb60f5a8e65c76d5a3a21aeb548f | |
parent | cb34e057ad22a1c2c6f2cb6cd1cbd05cc2f28f28 (diff) |
block: Add bio_alloc_pages()
More utility code to replace stuff that's getting open coded.
Signed-off-by: Kent Overstreet <koverstreet@google.com>
CC: Jens Axboe <axboe@kernel.dk>
CC: NeilBrown <neilb@suse.de>
-rw-r--r-- | drivers/md/raid1.c | 16 | ||||
-rw-r--r-- | fs/bio.c | 28 | ||||
-rw-r--r-- | include/linux/bio.h | 1 |
3 files changed, 32 insertions, 13 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index a7ea954abe1d..aeb4e3f74791 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c | |||
@@ -92,7 +92,6 @@ static void r1bio_pool_free(void *r1_bio, void *data) | |||
92 | static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data) | 92 | static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data) |
93 | { | 93 | { |
94 | struct pool_info *pi = data; | 94 | struct pool_info *pi = data; |
95 | struct page *page; | ||
96 | struct r1bio *r1_bio; | 95 | struct r1bio *r1_bio; |
97 | struct bio *bio; | 96 | struct bio *bio; |
98 | int i, j; | 97 | int i, j; |
@@ -122,14 +121,10 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data) | |||
122 | j = 1; | 121 | j = 1; |
123 | while(j--) { | 122 | while(j--) { |
124 | bio = r1_bio->bios[j]; | 123 | bio = r1_bio->bios[j]; |
125 | for (i = 0; i < RESYNC_PAGES; i++) { | 124 | bio->bi_vcnt = RESYNC_PAGES; |
126 | page = alloc_page(gfp_flags); | ||
127 | if (unlikely(!page)) | ||
128 | goto out_free_pages; | ||
129 | 125 | ||
130 | bio->bi_io_vec[i].bv_page = page; | 126 | if (bio_alloc_pages(bio, gfp_flags)) |
131 | bio->bi_vcnt = i+1; | 127 | goto out_free_bio; |
132 | } | ||
133 | } | 128 | } |
134 | /* If not user-requests, copy the page pointers to all bios */ | 129 | /* If not user-requests, copy the page pointers to all bios */ |
135 | if (!test_bit(MD_RECOVERY_REQUESTED, &pi->mddev->recovery)) { | 130 | if (!test_bit(MD_RECOVERY_REQUESTED, &pi->mddev->recovery)) { |
@@ -143,11 +138,6 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data) | |||
143 | 138 | ||
144 | return r1_bio; | 139 | return r1_bio; |
145 | 140 | ||
146 | out_free_pages: | ||
147 | for (j=0 ; j < pi->raid_disks; j++) | ||
148 | for (i=0; i < r1_bio->bios[j]->bi_vcnt ; i++) | ||
149 | put_page(r1_bio->bios[j]->bi_io_vec[i].bv_page); | ||
150 | j = -1; | ||
151 | out_free_bio: | 141 | out_free_bio: |
152 | while (++j < pi->raid_disks) | 142 | while (++j < pi->raid_disks) |
153 | bio_put(r1_bio->bios[j]); | 143 | bio_put(r1_bio->bios[j]); |
@@ -830,6 +830,34 @@ void bio_advance(struct bio *bio, unsigned bytes) | |||
830 | EXPORT_SYMBOL(bio_advance); | 830 | EXPORT_SYMBOL(bio_advance); |
831 | 831 | ||
832 | /** | 832 | /** |
833 | * bio_alloc_pages - allocates a single page for each bvec in a bio | ||
834 | * @bio: bio to allocate pages for | ||
835 | * @gfp_mask: flags for allocation | ||
836 | * | ||
837 | * Allocates pages up to @bio->bi_vcnt. | ||
838 | * | ||
839 | * Returns 0 on success, -ENOMEM on failure. On failure, any allocated pages are | ||
840 | * freed. | ||
841 | */ | ||
842 | int bio_alloc_pages(struct bio *bio, gfp_t gfp_mask) | ||
843 | { | ||
844 | int i; | ||
845 | struct bio_vec *bv; | ||
846 | |||
847 | bio_for_each_segment_all(bv, bio, i) { | ||
848 | bv->bv_page = alloc_page(gfp_mask); | ||
849 | if (!bv->bv_page) { | ||
850 | while (--bv >= bio->bi_io_vec) | ||
851 | __free_page(bv->bv_page); | ||
852 | return -ENOMEM; | ||
853 | } | ||
854 | } | ||
855 | |||
856 | return 0; | ||
857 | } | ||
858 | EXPORT_SYMBOL(bio_alloc_pages); | ||
859 | |||
860 | /** | ||
833 | * bio_copy_data - copy contents of data buffers from one chain of bios to | 861 | * bio_copy_data - copy contents of data buffers from one chain of bios to |
834 | * another | 862 | * another |
835 | * @src: source bio list | 863 | * @src: source bio list |
diff --git a/include/linux/bio.h b/include/linux/bio.h index be2efa09f9bf..e25378f2f408 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h | |||
@@ -298,6 +298,7 @@ static inline void bio_flush_dcache_pages(struct bio *bi) | |||
298 | #endif | 298 | #endif |
299 | 299 | ||
300 | extern void bio_copy_data(struct bio *dst, struct bio *src); | 300 | extern void bio_copy_data(struct bio *dst, struct bio *src); |
301 | extern int bio_alloc_pages(struct bio *bio, gfp_t gfp); | ||
301 | 302 | ||
302 | extern struct bio *bio_copy_user(struct request_queue *, struct rq_map_data *, | 303 | extern struct bio *bio_copy_user(struct request_queue *, struct rq_map_data *, |
303 | unsigned long, unsigned int, int, gfp_t); | 304 | unsigned long, unsigned int, int, gfp_t); |