From 917a38c71af82185c39e31589587591fa764fb85 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Tue, 8 May 2018 21:33:51 -0400 Subject: block: Add bioset_init()/bioset_exit() Similarly to mempool_init()/mempool_exit(), take a pointer indirection out of allocation/freeing by allowing biosets to be embedded in other structs. Signed-off-by: Kent Overstreet Signed-off-by: Jens Axboe --- block/bio.c | 93 +++++++++++++++++++++++++++++++++++++---------------- include/linux/bio.h | 2 ++ 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/block/bio.c b/block/bio.c index 06df6cf..ee182de 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1856,22 +1856,84 @@ int biovec_init_pool(mempool_t *pool, int pool_entries) return mempool_init_slab_pool(pool, pool_entries, bp->slab); } -void bioset_free(struct bio_set *bs) +/* + * bioset_exit - exit a bioset initialized with bioset_init() + * + * May be called on a zeroed but uninitialized bioset (i.e. allocated with + * kzalloc()). + */ +void bioset_exit(struct bio_set *bs) { if (bs->rescue_workqueue) destroy_workqueue(bs->rescue_workqueue); + bs->rescue_workqueue = NULL; mempool_exit(&bs->bio_pool); mempool_exit(&bs->bvec_pool); bioset_integrity_free(bs); - bio_put_slab(bs); + if (bs->bio_slab) + bio_put_slab(bs); + bs->bio_slab = NULL; +} +EXPORT_SYMBOL(bioset_exit); +void bioset_free(struct bio_set *bs) +{ + bioset_exit(bs); kfree(bs); } EXPORT_SYMBOL(bioset_free); /** + * bioset_init - Initialize a bio_set + * @pool_size: Number of bio and bio_vecs to cache in the mempool + * @front_pad: Number of bytes to allocate in front of the returned bio + * @flags: Flags to modify behavior, currently %BIOSET_NEED_BVECS + * and %BIOSET_NEED_RESCUER + * + * Similar to bioset_create(), but initializes a passed-in bioset instead of + * separately allocating it. + */ +int bioset_init(struct bio_set *bs, + unsigned int pool_size, + unsigned int front_pad, + int flags) +{ + unsigned int back_pad = BIO_INLINE_VECS * sizeof(struct bio_vec); + + bs->front_pad = front_pad; + + spin_lock_init(&bs->rescue_lock); + bio_list_init(&bs->rescue_list); + INIT_WORK(&bs->rescue_work, bio_alloc_rescue); + + bs->bio_slab = bio_find_or_create_slab(front_pad + back_pad); + if (!bs->bio_slab) + return -ENOMEM; + + if (mempool_init_slab_pool(&bs->bio_pool, pool_size, bs->bio_slab)) + goto bad; + + if ((flags & BIOSET_NEED_BVECS) && + biovec_init_pool(&bs->bvec_pool, pool_size)) + goto bad; + + if (!(flags & BIOSET_NEED_RESCUER)) + return 0; + + bs->rescue_workqueue = alloc_workqueue("bioset", WQ_MEM_RECLAIM, 0); + if (!bs->rescue_workqueue) + goto bad; + + return 0; +bad: + bioset_exit(bs); + return -ENOMEM; +} +EXPORT_SYMBOL(bioset_init); + +/** * bioset_create - Create a bio_set * @pool_size: Number of bio and bio_vecs to cache in the mempool * @front_pad: Number of bytes to allocate in front of the returned bio @@ -1895,43 +1957,18 @@ struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad, int flags) { - unsigned int back_pad = BIO_INLINE_VECS * sizeof(struct bio_vec); struct bio_set *bs; bs = kzalloc(sizeof(*bs), GFP_KERNEL); if (!bs) return NULL; - bs->front_pad = front_pad; - - spin_lock_init(&bs->rescue_lock); - bio_list_init(&bs->rescue_list); - INIT_WORK(&bs->rescue_work, bio_alloc_rescue); - - bs->bio_slab = bio_find_or_create_slab(front_pad + back_pad); - if (!bs->bio_slab) { + if (bioset_init(bs, pool_size, front_pad, flags)) { kfree(bs); return NULL; } - if (mempool_init_slab_pool(&bs->bio_pool, pool_size, bs->bio_slab)) - goto bad; - - if ((flags & BIOSET_NEED_BVECS) && - biovec_init_pool(&bs->bvec_pool, pool_size)) - goto bad; - - if (!(flags & BIOSET_NEED_RESCUER)) - return bs; - - bs->rescue_workqueue = alloc_workqueue("bioset", WQ_MEM_RECLAIM, 0); - if (!bs->rescue_workqueue) - goto bad; - return bs; -bad: - bioset_free(bs); - return NULL; } EXPORT_SYMBOL(bioset_create); diff --git a/include/linux/bio.h b/include/linux/bio.h index 720f726..fa3cf94 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -406,6 +406,8 @@ static inline struct bio *bio_next_split(struct bio *bio, int sectors, return bio_split(bio, sectors, gfp, bs); } +extern int bioset_init(struct bio_set *, unsigned int, unsigned int, int flags); +extern void bioset_exit(struct bio_set *); extern struct bio_set *bioset_create(unsigned int, unsigned int, int flags); enum { BIOSET_NEED_BVECS = BIT(0), -- cgit v1.1