Commit 02569948 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-6.11/block-post-20240722' of git://git.kernel.dk/linux

Pull block integrity mapping updates from Jens Axboe:
 "A set of cleanups and fixes for the block integrity support.

  Sent separately from the main block changes from last week, as they
  depended on later fixes in the 6.10-rc cycle"

* tag 'for-6.11/block-post-20240722' of git://git.kernel.dk/linux:
  block: don't free the integrity payload in bio_integrity_unmap_free_user
  block: don't free submitter owned integrity payload on I/O completion
  block: call bio_integrity_unmap_free_user from blk_rq_unmap_user
  block: don't call bio_uninit from bio_endio
  block: also return bio_integrity_payload * from stubs
  block: split integrity support out of bio.h
parents dd018c23 74cc1502
Loading
Loading
Loading
Loading
+32 −55
Original line number Diff line number Diff line
@@ -22,9 +22,17 @@ void blk_flush_integrity(void)
	flush_workqueue(kintegrityd_wq);
}

static void __bio_integrity_free(struct bio_set *bs,
				 struct bio_integrity_payload *bip)
/**
 * bio_integrity_free - Free bio integrity payload
 * @bio:	bio containing bip to be freed
 *
 * Description: Free the integrity portion of a bio.
 */
void bio_integrity_free(struct bio *bio)
{
	struct bio_integrity_payload *bip = bio_integrity(bio);
	struct bio_set *bs = bio->bi_pool;

	if (bs && mempool_initialized(&bs->bio_integrity_pool)) {
		if (bip->bip_vec)
			bvec_free(&bs->bvec_integrity_pool, bip->bip_vec,
@@ -33,6 +41,8 @@ static void __bio_integrity_free(struct bio_set *bs,
	} else {
		kfree(bip);
	}
	bio->bi_integrity = NULL;
	bio->bi_opf &= ~REQ_INTEGRITY;
}

/**
@@ -86,7 +96,10 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,

	return bip;
err:
	__bio_integrity_free(bs, bip);
	if (bs && mempool_initialized(&bs->bio_integrity_pool))
		mempool_free(bip, &bs->bio_integrity_pool);
	else
		kfree(bip);
	return ERR_PTR(-ENOMEM);
}
EXPORT_SYMBOL(bio_integrity_alloc);
@@ -118,63 +131,26 @@ static void bio_integrity_uncopy_user(struct bio_integrity_payload *bip)
	bio_integrity_unpin_bvec(copy, nr_vecs, true);
}

static void bio_integrity_unmap_user(struct bio_integrity_payload *bip)
{
	bool dirty = bio_data_dir(bip->bip_bio) == READ;

	if (bip->bip_flags & BIP_COPY_USER) {
		if (dirty)
			bio_integrity_uncopy_user(bip);
		kfree(bvec_virt(bip->bip_vec));
		return;
	}

	bio_integrity_unpin_bvec(bip->bip_vec, bip->bip_max_vcnt, dirty);
}

/**
 * bio_integrity_free - Free bio integrity payload
 * @bio:	bio containing bip to be freed
 * bio_integrity_unmap_user - Unmap user integrity payload
 * @bio:	bio containing bip to be unmapped
 *
 * Description: Used to free the integrity portion of a bio. Usually
 * called from bio_free().
 * Unmap the user mapped integrity portion of a bio.
 */
void bio_integrity_free(struct bio *bio)
void bio_integrity_unmap_user(struct bio *bio)
{
	struct bio_integrity_payload *bip = bio_integrity(bio);
	struct bio_set *bs = bio->bi_pool;

	if (bip->bip_flags & BIP_INTEGRITY_USER)
		return;
	if (bip->bip_flags & BIP_BLOCK_INTEGRITY)
	if (bip->bip_flags & BIP_COPY_USER) {
		if (bio_data_dir(bio) == READ)
			bio_integrity_uncopy_user(bip);
		kfree(bvec_virt(bip->bip_vec));

	__bio_integrity_free(bs, bip);
	bio->bi_integrity = NULL;
	bio->bi_opf &= ~REQ_INTEGRITY;
		return;
	}

/**
 * bio_integrity_unmap_free_user - Unmap and free bio user integrity payload
 * @bio:	bio containing bip to be unmapped and freed
 *
 * Description: Used to unmap and free the user mapped integrity portion of a
 * bio. Submitter attaching the user integrity buffer is responsible for
 * unmapping and freeing it during completion.
 */
void bio_integrity_unmap_free_user(struct bio *bio)
{
	struct bio_integrity_payload *bip = bio_integrity(bio);
	struct bio_set *bs = bio->bi_pool;

	if (WARN_ON_ONCE(!(bip->bip_flags & BIP_INTEGRITY_USER)))
		return;
	bio_integrity_unmap_user(bip);
	__bio_integrity_free(bs, bip);
	bio->bi_integrity = NULL;
	bio->bi_opf &= ~REQ_INTEGRITY;
	bio_integrity_unpin_bvec(bip->bip_vec, bip->bip_max_vcnt,
			bio_data_dir(bio) == READ);
}
EXPORT_SYMBOL(bio_integrity_unmap_free_user);

/**
 * bio_integrity_add_page - Attach integrity metadata
@@ -274,7 +250,7 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec,
		goto free_bip;
	}

	bip->bip_flags |= BIP_INTEGRITY_USER | BIP_COPY_USER;
	bip->bip_flags |= BIP_COPY_USER;
	bip->bip_iter.bi_sector = seed;
	bip->bip_vcnt = nr_vecs;
	return 0;
@@ -295,7 +271,6 @@ static int bio_integrity_init_user(struct bio *bio, struct bio_vec *bvec,
		return PTR_ERR(bip);

	memcpy(bip->bip_vec, bvec, nr_vecs * sizeof(*bvec));
	bip->bip_flags |= BIP_INTEGRITY_USER;
	bip->bip_iter.bi_sector = seed;
	bip->bip_iter.bi_size = len;
	bip->bip_vcnt = nr_vecs;
@@ -503,6 +478,8 @@ static void bio_integrity_verify_fn(struct work_struct *work)
	struct bio *bio = bip->bip_bio;

	blk_integrity_verify(bio);

	kfree(bvec_virt(bip->bip_vec));
	bio_integrity_free(bio);
	bio_endio(bio);
}
@@ -523,13 +500,13 @@ bool __bio_integrity_endio(struct bio *bio)
	struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
	struct bio_integrity_payload *bip = bio_integrity(bio);

	if (bio_op(bio) == REQ_OP_READ && !bio->bi_status &&
	    (bip->bip_flags & BIP_BLOCK_INTEGRITY) && bi->csum_type) {
	if (bio_op(bio) == REQ_OP_READ && !bio->bi_status && bi->csum_type) {
		INIT_WORK(&bip->bip_work, bio_integrity_verify_fn);
		queue_work(kintegrityd_wq, &bip->bip_work);
		return false;
	}

	kfree(bvec_virt(bip->bip_vec));
	bio_integrity_free(bio);
	return true;
}
+13 −3
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
 */
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/bio.h>
#include <linux/bio-integrity.h>
#include <linux/blkdev.h>
#include <linux/uio.h>
#include <linux/iocontext.h>
@@ -1630,8 +1630,18 @@ void bio_endio(struct bio *bio)
		goto again;
	}

	/* release cgroup info */
	bio_uninit(bio);
#ifdef CONFIG_BLK_CGROUP
	/*
	 * Release cgroup info.  We shouldn't have to do this here, but quite
	 * a few callers of bio_init fail to call bio_uninit, so we cover up
	 * for that here at least for now.
	 */
	if (bio->bi_blkg) {
		blkg_put(bio->bi_blkg);
		bio->bi_blkg = NULL;
	}
#endif

	if (bio->bi_end_io)
		bio->bi_end_io(bio);
}
+3 −0
Original line number Diff line number Diff line
@@ -757,6 +757,9 @@ int blk_rq_unmap_user(struct bio *bio)
			bio_release_pages(bio, bio_data_dir(bio) == READ);
		}

		if (bio_integrity(bio))
			bio_integrity_unmap_user(bio);

		next_bio = bio;
		bio = bio->bi_next;
		blk_mq_map_bio_put(next_bio);
+12 −2
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
#ifndef BLK_INTERNAL_H
#define BLK_INTERNAL_H

#include <linux/bio-integrity.h>
#include <linux/blk-crypto.h>
#include <linux/memblock.h>	/* for max_pfn/max_low_pfn */
#include <linux/sched/sysctl.h>
@@ -201,11 +202,20 @@ static inline unsigned int blk_queue_get_max_sectors(struct request *rq)

#ifdef CONFIG_BLK_DEV_INTEGRITY
void blk_flush_integrity(void);
bool __bio_integrity_endio(struct bio *);
void bio_integrity_free(struct bio *bio);

/*
 * Integrity payloads can either be owned by the submitter, in which case
 * bio_uninit will free them, or owned and generated by the block layer,
 * in which case we'll verify them here (for reads) and free them before
 * the bio is handed back to the submitted.
 */
bool __bio_integrity_endio(struct bio *bio);
static inline bool bio_integrity_endio(struct bio *bio)
{
	if (bio_integrity(bio))
	struct bio_integrity_payload *bip = bio_integrity(bio);

	if (bip && (bip->bip_flags & BIP_BLOCK_INTEGRITY))
		return __bio_integrity_endio(bio);
	return true;
}
+1 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@
#include <linux/export.h>
#include <linux/swap.h>
#include <linux/gfp.h>
#include <linux/bio.h>
#include <linux/bio-integrity.h>
#include <linux/pagemap.h>
#include <linux/mempool.h>
#include <linux/blkdev.h>
Loading