Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 451a9ebf authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe
Browse files

bio: fix bio_kmalloc()



Impact: fix bio_kmalloc() and its destruction path

bio_kmalloc() was broken in two ways.

* bvec_alloc_bs() first allocates bvec using kmalloc() and then
  ignores it and allocates again like non-kmalloc bvecs.

* bio_kmalloc_destructor() didn't check for and free bio integrity
  data.

This patch fixes the above problems.  kmalloc patch is separated out
from bio_alloc_bioset() and allocates the requested number of bvecs as
inline bvecs.

* bio_alloc_bioset() no longer takes NULL @bs.  None other than
  bio_kmalloc() used it and outside users can't know how it was
  allocated anyway.

* Define and use BIO_POOL_NONE so that pool index check in
  bvec_free_bs() triggers if inline or kmalloc allocated bvec gets
  there.

* Relocate destructors on top of each allocation function so that how
  they're used is more clear.

Jens Axboe suggested allocating bvecs inline.

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent cd0aca2d
Loading
Loading
Loading
Loading
+54 −64
Original line number Diff line number Diff line
@@ -174,14 +174,6 @@ struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx,
{
	struct bio_vec *bvl;

	/*
	 * If 'bs' is given, lookup the pool and do the mempool alloc.
	 * If not, this is a bio_kmalloc() allocation and just do a
	 * kzalloc() for the exact number of vecs right away.
	 */
	if (!bs)
		bvl = kmalloc(nr * sizeof(struct bio_vec), gfp_mask);

	/*
	 * see comment near bvec_array define!
	 */
@@ -260,21 +252,6 @@ void bio_free(struct bio *bio, struct bio_set *bs)
	mempool_free(p, bs->bio_pool);
}

/*
 * default destructor for a bio allocated with bio_alloc_bioset()
 */
static void bio_fs_destructor(struct bio *bio)
{
	bio_free(bio, fs_bio_set);
}

static void bio_kmalloc_destructor(struct bio *bio)
{
	if (bio_has_allocated_vec(bio))
		kfree(bio->bi_io_vec);
	kfree(bio);
}

void bio_init(struct bio *bio)
{
	memset(bio, 0, sizeof(*bio));
@@ -301,21 +278,15 @@ void bio_init(struct bio *bio)
 **/
struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
{
	unsigned long idx = BIO_POOL_NONE;
	struct bio_vec *bvl = NULL;
	struct bio *bio = NULL;
	unsigned long idx = 0;
	void *p = NULL;
	struct bio *bio;
	void *p;

	if (bs) {
	p = mempool_alloc(bs->bio_pool, gfp_mask);
		if (!p)
			goto err;
	if (unlikely(!p))
		return NULL;
	bio = p + bs->front_pad;
	} else {
		bio = kmalloc(sizeof(*bio), gfp_mask);
		if (!bio)
			goto err;
	}

	bio_init(bio);

@@ -332,22 +303,50 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)

		nr_iovecs = bvec_nr_vecs(idx);
	}
out_set:
	bio->bi_flags |= idx << BIO_POOL_OFFSET;
	bio->bi_max_vecs = nr_iovecs;
out_set:
	bio->bi_io_vec = bvl;

	return bio;

err_free:
	if (bs)
	mempool_free(p, bs->bio_pool);
	else
		kfree(bio);
err:
	return NULL;
}

static void bio_fs_destructor(struct bio *bio)
{
	bio_free(bio, fs_bio_set);
}

/**
 *	bio_alloc - allocate a new bio, memory pool backed
 *	@gfp_mask: allocation mask to use
 *	@nr_iovecs: number of iovecs
 *
 *	Allocate a new bio with @nr_iovecs bvecs.  If @gfp_mask
 *	contains __GFP_WAIT, the allocation is guaranteed to succeed.
 *
 *	RETURNS:
 *	Pointer to new bio on success, NULL on failure.
 */
struct bio *bio_alloc(gfp_t gfp_mask, int nr_iovecs)
{
	struct bio *bio = bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set);

	if (bio)
		bio->bi_destructor = bio_fs_destructor;

	return bio;
}

static void bio_kmalloc_destructor(struct bio *bio)
{
	if (bio_integrity(bio))
		bio_integrity_free(bio);
	kfree(bio);
}

/**
 * bio_alloc - allocate a bio for I/O
 * @gfp_mask:   the GFP_ mask given to the slab allocator
@@ -366,28 +365,19 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
 *   do so can cause livelocks under memory pressure.
 *
 **/
struct bio *bio_alloc(gfp_t gfp_mask, int nr_iovecs)
{
	struct bio *bio = bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set);

	if (bio)
		bio->bi_destructor = bio_fs_destructor;

	return bio;
}

/*
 * Like bio_alloc(), but doesn't use a mempool backing. This means that
 * it CAN fail, but while bio_alloc() can only be used for allocations
 * that have a short (finite) life span, bio_kmalloc() should be used
 * for more permanent bio allocations (like allocating some bio's for
 * initalization or setup purposes).
 */
struct bio *bio_kmalloc(gfp_t gfp_mask, int nr_iovecs)
{
	struct bio *bio = bio_alloc_bioset(gfp_mask, nr_iovecs, NULL);
	struct bio *bio;

	if (bio)
	bio = kmalloc(sizeof(struct bio) + nr_iovecs * sizeof(struct bio_vec),
		      gfp_mask);
	if (unlikely(!bio))
		return NULL;

	bio_init(bio);
	bio->bi_flags |= BIO_POOL_NONE << BIO_POOL_OFFSET;
	bio->bi_max_vecs = nr_iovecs;
	bio->bi_io_vec = bio->bi_inline_vecs;
	bio->bi_destructor = bio_kmalloc_destructor;

	return bio;
+1 −0
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ struct bio {
 * top 4 bits of bio flags indicate the pool this bio came from
 */
#define BIO_POOL_BITS		(4)
#define BIO_POOL_NONE		((1UL << BIO_POOL_BITS) - 1)
#define BIO_POOL_OFFSET		(BITS_PER_LONG - BIO_POOL_BITS)
#define BIO_POOL_MASK		(1UL << BIO_POOL_OFFSET)
#define BIO_POOL_IDX(bio)	((bio)->bi_flags >> BIO_POOL_OFFSET)