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
/**
* 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)
blk_integrity_generate(bio);
else
bid->saved_bio_iter = bio->bi_iter;
- return true;
}
EXPORT_SYMBOL(bio_integrity_prep);
*/
#include <linux/blk-integrity.h>
+#include <linux/t10-pi.h>
#include "blk.h"
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);
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;
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))
{
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)
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);
{
}
-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,
}
#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 */