Indicate to the ublk server when an incoming request has integrity data
by setting UBLK_IO_F_INTEGRITY in the ublksrv_io_desc's op_flags field.
If the ublk device doesn't support integrity, the request will never
provide integrity data. If the ublk device supports integrity, the
request may omit the integrity buffer only if metadata_size matches the
PI tuple size determined by csum_type. In this case, the ublk server
should internally generate/verify the protection information from the
data and sector offset.
Set the UBLK_IO_F_CHECK_{GUARD,REFTAG,APPTAG} flags based on the
request's BIP_CHECK_{GUARD,REFTAG,APPTAG} flags, indicating whether to
verify the guard, reference, and app tags in the protection information.
The expected reference tag (32 or 48 bits) and app tag (16 bits) are
indicated in ublksrv_io_desc's new struct ublksrv_io_integrity integrity
field. This field is unioned with the addr field to avoid changing the
size of struct ublksrv_io_desc. UBLK_F_INTEGRITY requires
UBLK_F_USER_COPY and the addr field isn't used for UBLK_F_USER_COPY, so
the two fields aren't needed simultaneously.Signed-off-by: Caleb Sander Mateos <[email protected]> --- drivers/block/ublk_drv.c | 43 +++++++++++++++++++++++++++++++---- include/uapi/linux/ublk_cmd.h | 27 ++++++++++++++++++++-- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 2f9316febf83..51469e0627ff 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -316,10 +316,36 @@ static inline bool ublk_dev_is_zoned(const struct ublk_device *ub) static inline bool ublk_queue_is_zoned(const struct ublk_queue *ubq) { return ubq->flags & UBLK_F_ZONED; } +static void ublk_setup_iod_buf(const struct ublk_queue *ubq, + const struct request *req, + struct ublksrv_io_desc *iod) +{ +#ifdef CONFIG_BLK_DEV_INTEGRITY + if (ubq->flags & UBLK_F_INTEGRITY) { + struct bio_integrity_payload *bip; + sector_t ref_tag_seed; + + if (!blk_integrity_rq(req)) + return; + + bip = bio_integrity(req->bio); + ref_tag_seed = bip_get_seed(bip); + iod->integrity.ref_tag_lo = ref_tag_seed; + iod->integrity.ref_tag_hi = ref_tag_seed >> 32; + iod->integrity.app_tag = bip->app_tag; + } else +#endif /* #ifdef CONFIG_BLK_DEV_INTEGRITY */ + { + const struct ublk_io *io = &ubq->ios[req->tag]; + + iod->addr = io->buf.addr; + } +} + #ifdef CONFIG_BLK_DEV_ZONED struct ublk_zoned_report_desc { __u64 sector; __u32 operation; @@ -498,11 +524,10 @@ static int ublk_report_zones(struct gendisk *disk, sector_t sector, static blk_status_t ublk_setup_iod_zoned(struct ublk_queue *ubq, struct request *req) { struct ublksrv_io_desc *iod = ublk_get_iod(ubq, req->tag); - struct ublk_io *io = &ubq->ios[req->tag]; struct ublk_zoned_report_desc *desc; u32 ublk_op; switch (req_op(req)) { case REQ_OP_ZONE_OPEN: @@ -545,11 +570,11 @@ static blk_status_t ublk_setup_iod_zoned(struct ublk_queue *ubq, } iod->op_flags = ublk_op | ublk_req_build_flags(req); iod->nr_sectors = blk_rq_sectors(req); iod->start_sector = blk_rq_pos(req); - iod->addr = io->buf.addr; + ublk_setup_iod_buf(ubq, req, iod); return BLK_STS_OK; } #else @@ -1120,17 +1145,27 @@ static inline unsigned int ublk_req_build_flags(struct request *req) flags |= UBLK_IO_F_NOUNMAP; if (req->cmd_flags & REQ_SWAP) flags |= UBLK_IO_F_SWAP; + if (blk_integrity_rq(req)) { + flags |= UBLK_IO_F_INTEGRITY; + + if (bio_integrity_flagged(req->bio, BIP_CHECK_GUARD)) + flags |= UBLK_IO_F_CHECK_GUARD; + if (bio_integrity_flagged(req->bio, BIP_CHECK_REFTAG)) + flags |= UBLK_IO_F_CHECK_REFTAG; + if (bio_integrity_flagged(req->bio, BIP_CHECK_APPTAG)) + flags |= UBLK_IO_F_CHECK_APPTAG; + } + return flags; } static blk_status_t ublk_setup_iod(struct ublk_queue *ubq, struct request *req) { struct ublksrv_io_desc *iod = ublk_get_iod(ubq, req->tag); - struct ublk_io *io = &ubq->ios[req->tag]; u32 ublk_op; switch (req_op(req)) { case REQ_OP_READ: ublk_op = UBLK_IO_OP_READ; @@ -1155,11 +1190,11 @@ static blk_status_t ublk_setup_iod(struct ublk_queue *ubq, struct request *req) /* need to translate since kernel may change */ iod->op_flags = ublk_op | ublk_req_build_flags(req); iod->nr_sectors = blk_rq_sectors(req); iod->start_sector = blk_rq_pos(req); - iod->addr = io->buf.addr; + ublk_setup_iod_buf(ubq, req, iod); return BLK_STS_OK; } static inline struct ublk_uring_cmd_pdu *ublk_get_uring_cmd_pdu( diff --git a/include/uapi/linux/ublk_cmd.h b/include/uapi/linux/ublk_cmd.h index a54c47832fa2..a22de3fc5447 100644 --- a/include/uapi/linux/ublk_cmd.h +++ b/include/uapi/linux/ublk_cmd.h @@ -412,10 +412,25 @@ struct ublksrv_ctrl_dev_info { * * ublk server has to check this flag if UBLK_AUTO_BUF_REG_FALLBACK is * passed in. */ #define UBLK_IO_F_NEED_REG_BUF (1U << 17) +/* Request has an integrity data buffer */ +#define UBLK_IO_F_INTEGRITY (1UL << 18) +/* Guard tag verification requested */ +#define UBLK_IO_F_CHECK_GUARD (1UL << 19) +/* Reference tag verification requested */ +#define UBLK_IO_F_CHECK_REFTAG (1UL << 20) +/* Application tag verification requested */ +#define UBLK_IO_F_CHECK_APPTAG (1UL << 21) + +struct ublksrv_io_integrity +{ + __u32 ref_tag_lo; /* low 32 bits of reference tag seed */ + __u16 ref_tag_hi; /* high 16 bits of reference tag seed */ + __u16 app_tag; +}; /* * io cmd is described by this structure, and stored in share memory, indexed * by request tag. * @@ -432,12 +447,20 @@ struct ublksrv_io_desc { }; /* start sector for this io */ __u64 start_sector; - /* buffer address in ublksrv daemon vm space, from ublk driver */ - __u64 addr; + union { + /* + * buffer address in ublksrv daemon vm space, from ublk driver. + * Unused for UBLK_F_SUPPORT_ZERO_COPY, UBLK_F_USER_COPY, or + * UBLK_F_AUTO_BUF_REG. + */ + __u64 addr; + /* Integrity options, for UBLK_F_INTEGRITY */ + struct ublksrv_io_integrity integrity; + }; }; static inline __u8 ublksrv_get_op(const struct ublksrv_io_desc *iod) { return iod->op_flags & 0xff; -- 2.45.2
