On Wed, Jan 28, 2026 at 05:14:56PM +0100, Christoph Hellwig wrote:
> Split the logic to see if a bio needs integrity metadata from
> bio_integrity_prep into a reusable helper than can be called from
> file system code.
> 
> Signed-off-by: Christoph Hellwig <[email protected]>
> Reviewed-by: Anuj Gupta <[email protected]>
> Reviewed-by: Kanchan Joshi <[email protected]>
> Reviewed-by: Martin K. Petersen <[email protected]>
> Tested-by: Anuj Gupta <[email protected]>

Looks good to me now, thanks for clarifying the kerneldoc
Reviewed-by: "Darrick J. Wong" <[email protected]>

--D

> ---
>  block/bio-integrity-auto.c    | 64 +++++------------------------------
>  block/bio-integrity.c         | 48 ++++++++++++++++++++++++++
>  block/blk-mq.c                |  6 ++--
>  drivers/nvdimm/btt.c          |  6 ++--
>  include/linux/bio-integrity.h |  5 ++-
>  include/linux/blk-integrity.h | 23 +++++++++++++
>  6 files changed, 89 insertions(+), 63 deletions(-)
> 
> diff --git a/block/bio-integrity-auto.c b/block/bio-integrity-auto.c
> index 44dcdf7520c5..e16f669dbf1e 100644
> --- a/block/bio-integrity-auto.c
> +++ b/block/bio-integrity-auto.c
> @@ -50,11 +50,6 @@ static bool bip_should_check(struct bio_integrity_payload 
> *bip)
>       return bip->bip_flags & BIP_CHECK_FLAGS;
>  }
>  
> -static bool bi_offload_capable(struct blk_integrity *bi)
> -{
> -     return bi->metadata_size == bi->pi_tuple_size;
> -}
> -
>  /**
>   * __bio_integrity_endio - Integrity I/O completion function
>   * @bio:     Protected bio
> @@ -84,69 +79,27 @@ bool __bio_integrity_endio(struct bio *bio)
>  /**
>   * bio_integrity_prep - Prepare bio for integrity I/O
>   * @bio:     bio to prepare
> + * @action:  preparation action needed (BI_ACT_*)
> + *
> + * Allocate the integrity payload.  For writes, generate the integrity 
> metadata
> + * and for reads, setup the completion handler to verify the metadata.
>   *
> - * Checks if the bio already has an integrity payload attached.  If it does, 
> the
> - * payload has been generated by another kernel subsystem, and we just pass 
> it
> - * through.
> - * Otherwise allocates integrity payload and for writes the integrity 
> metadata
> - * will be generated.  For reads, the completion handler will verify the
> - * metadata.
> + * This is used for bios that do not have user integrity payloads attached.
>   */
> -bool bio_integrity_prep(struct bio *bio)
> +void bio_integrity_prep(struct bio *bio, unsigned int action)
>  {
>       struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
>       struct bio_integrity_data *bid;
> -     bool set_flags = true;
> -     gfp_t gfp = GFP_NOIO;
> -
> -     if (!bi)
> -             return true;
> -
> -     if (!bio_sectors(bio))
> -             return true;
> -
> -     /* Already protected? */
> -     if (bio_integrity(bio))
> -             return true;
> -
> -     switch (bio_op(bio)) {
> -     case REQ_OP_READ:
> -             if (bi->flags & BLK_INTEGRITY_NOVERIFY) {
> -                     if (bi_offload_capable(bi))
> -                             return true;
> -                     set_flags = false;
> -             }
> -             break;
> -     case REQ_OP_WRITE:
> -             /*
> -              * Zero the memory allocated to not leak uninitialized kernel
> -              * memory to disk for non-integrity metadata where nothing else
> -              * initializes the memory.
> -              */
> -             if (bi->flags & BLK_INTEGRITY_NOGENERATE) {
> -                     if (bi_offload_capable(bi))
> -                             return true;
> -                     set_flags = false;
> -                     gfp |= __GFP_ZERO;
> -             } else if (bi->metadata_size > bi->pi_tuple_size)
> -                     gfp |= __GFP_ZERO;
> -             break;
> -     default:
> -             return true;
> -     }
> -
> -     if (WARN_ON_ONCE(bio_has_crypt_ctx(bio)))
> -             return true;
>  
>       bid = mempool_alloc(&bid_pool, GFP_NOIO);
>       bio_integrity_init(bio, &bid->bip, &bid->bvec, 1);
>       bid->bio = bio;
>       bid->bip.bip_flags |= BIP_BLOCK_INTEGRITY;
> -     bio_integrity_alloc_buf(bio, gfp & __GFP_ZERO);
> +     bio_integrity_alloc_buf(bio, action & BI_ACT_ZERO);
>  
>       bip_set_seed(&bid->bip, bio->bi_iter.bi_sector);
>  
> -     if (set_flags) {
> +     if (action & BI_ACT_CHECK) {
>               if (bi->csum_type == BLK_INTEGRITY_CSUM_IP)
>                       bid->bip.bip_flags |= BIP_IP_CHECKSUM;
>               if (bi->csum_type)
> @@ -160,7 +113,6 @@ bool bio_integrity_prep(struct bio *bio)
>               blk_integrity_generate(bio);
>       else
>               bid->saved_bio_iter = bio->bi_iter;
> -     return true;
>  }
>  EXPORT_SYMBOL(bio_integrity_prep);
>  
> diff --git a/block/bio-integrity.c b/block/bio-integrity.c
> index 09eeaf6e74b8..6bdbb4ed2d1a 100644
> --- a/block/bio-integrity.c
> +++ b/block/bio-integrity.c
> @@ -7,6 +7,7 @@
>   */
>  
>  #include <linux/blk-integrity.h>
> +#include <linux/t10-pi.h>
>  #include "blk.h"
>  
>  struct bio_integrity_alloc {
> @@ -16,6 +17,53 @@ struct bio_integrity_alloc {
>  
>  static mempool_t integrity_buf_pool;
>  
> +static bool bi_offload_capable(struct blk_integrity *bi)
> +{
> +     return bi->metadata_size == bi->pi_tuple_size;
> +}
> +
> +unsigned int __bio_integrity_action(struct bio *bio)
> +{
> +     struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
> +
> +     if (WARN_ON_ONCE(bio_has_crypt_ctx(bio)))
> +             return 0;
> +
> +     switch (bio_op(bio)) {
> +     case REQ_OP_READ:
> +             if (bi->flags & BLK_INTEGRITY_NOVERIFY) {
> +                     if (bi_offload_capable(bi))
> +                             return 0;
> +                     return BI_ACT_BUFFER;
> +             }
> +             return BI_ACT_BUFFER | BI_ACT_CHECK;
> +     case REQ_OP_WRITE:
> +             /*
> +              * Flush masquerading as write?
> +              */
> +             if (!bio_sectors(bio))
> +                     return 0;
> +
> +             /*
> +              * Zero the memory allocated to not leak uninitialized kernel
> +              * memory to disk for non-integrity metadata where nothing else
> +              * initializes the memory.
> +              */
> +             if (bi->flags & BLK_INTEGRITY_NOGENERATE) {
> +                     if (bi_offload_capable(bi))
> +                             return 0;
> +                     return BI_ACT_BUFFER | BI_ACT_ZERO;
> +             }
> +
> +             if (bi->metadata_size > bi->pi_tuple_size)
> +                     return BI_ACT_BUFFER | BI_ACT_CHECK | BI_ACT_ZERO;
> +             return BI_ACT_BUFFER | BI_ACT_CHECK;
> +     default:
> +             return 0;
> +     }
> +}
> +EXPORT_SYMBOL_GPL(__bio_integrity_action);
> +
>  void bio_integrity_alloc_buf(struct bio *bio, bool zero_buffer)
>  {
>       struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
> diff --git a/block/blk-mq.c b/block/blk-mq.c
> index cf1daedbb39f..d40942bafd02 100644
> --- a/block/blk-mq.c
> +++ b/block/blk-mq.c
> @@ -3134,6 +3134,7 @@ void blk_mq_submit_bio(struct bio *bio)
>       struct request_queue *q = bdev_get_queue(bio->bi_bdev);
>       struct blk_plug *plug = current->plug;
>       const int is_sync = op_is_sync(bio->bi_opf);
> +     unsigned int integrity_action;
>       struct blk_mq_hw_ctx *hctx;
>       unsigned int nr_segs;
>       struct request *rq;
> @@ -3186,8 +3187,9 @@ void blk_mq_submit_bio(struct bio *bio)
>       if (!bio)
>               goto queue_exit;
>  
> -     if (!bio_integrity_prep(bio))
> -             goto queue_exit;
> +     integrity_action = bio_integrity_action(bio);
> +     if (integrity_action)
> +             bio_integrity_prep(bio, integrity_action);
>  
>       blk_mq_bio_issue_init(q, bio);
>       if (blk_mq_attempt_bio_merge(q, bio, nr_segs))
> diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
> index a933db961ed7..9cc4b659de1a 100644
> --- a/drivers/nvdimm/btt.c
> +++ b/drivers/nvdimm/btt.c
> @@ -1437,14 +1437,16 @@ static void btt_submit_bio(struct bio *bio)
>  {
>       struct bio_integrity_payload *bip = bio_integrity(bio);
>       struct btt *btt = bio->bi_bdev->bd_disk->private_data;
> +     unsigned int integrity_action;
>       struct bvec_iter iter;
>       unsigned long start;
>       struct bio_vec bvec;
>       int err = 0;
>       bool do_acct;
>  
> -     if (!bio_integrity_prep(bio))
> -             return;
> +     integrity_action = bio_integrity_action(bio);
> +     if (integrity_action)
> +             bio_integrity_prep(bio, integrity_action);
>  
>       do_acct = blk_queue_io_stat(bio->bi_bdev->bd_disk->queue);
>       if (do_acct)
> diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h
> index 21e4652dcfd2..276cbbdd2c9d 100644
> --- a/include/linux/bio-integrity.h
> +++ b/include/linux/bio-integrity.h
> @@ -78,7 +78,7 @@ int bio_integrity_add_page(struct bio *bio, struct page 
> *page, unsigned int len,
>  int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter);
>  int bio_integrity_map_iter(struct bio *bio, struct uio_meta *meta);
>  void bio_integrity_unmap_user(struct bio *bio);
> -bool bio_integrity_prep(struct bio *bio);
> +void bio_integrity_prep(struct bio *bio, unsigned int action);
>  void bio_integrity_advance(struct bio *bio, unsigned int bytes_done);
>  void bio_integrity_trim(struct bio *bio);
>  int bio_integrity_clone(struct bio *bio, struct bio *bio_src, gfp_t 
> gfp_mask);
> @@ -104,9 +104,8 @@ static inline void bio_integrity_unmap_user(struct bio 
> *bio)
>  {
>  }
>  
> -static inline bool bio_integrity_prep(struct bio *bio)
> +static inline void bio_integrity_prep(struct bio *bio, unsigned int action)
>  {
> -     return true;
>  }
>  
>  static inline int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
> diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h
> index c15b1ac62765..fd3f3c8c0fcd 100644
> --- a/include/linux/blk-integrity.h
> +++ b/include/linux/blk-integrity.h
> @@ -180,4 +180,27 @@ static inline struct bio_vec rq_integrity_vec(struct 
> request *rq)
>  }
>  #endif /* CONFIG_BLK_DEV_INTEGRITY */
>  
> +enum bio_integrity_action {
> +     BI_ACT_BUFFER           = (1u << 0),    /* allocate buffer */
> +     BI_ACT_CHECK            = (1u << 1),    /* generate / verify PI */
> +     BI_ACT_ZERO             = (1u << 2),    /* zero buffer */
> +};
> +
> +/**
> + * bio_integrity_action - return the integrity action needed for a bio
> + * @bio:     bio to operate on
> + *
> + * Returns the mask of integrity actions (BI_ACT_*) that need to be performed
> + * for @bio.
> + */
> +unsigned int __bio_integrity_action(struct bio *bio);
> +static inline unsigned int bio_integrity_action(struct bio *bio)
> +{
> +     if (!blk_get_integrity(bio->bi_bdev->bd_disk))
> +             return 0;
> +     if (bio_integrity(bio))
> +             return 0;
> +     return __bio_integrity_action(bio);
> +}
> +
>  #endif /* _LINUX_BLK_INTEGRITY_H */
> -- 
> 2.47.3
> 
> 

Reply via email to