On 2/10/22 5:08 AM, Alexander V. Buev wrote: > Check that the size of integrity data correspond to device integrity > profile and data size. Split integrity data to the different bio's > in case of to big orginal bio (together with normal data). > > Signed-off-by: Alexander V. Buev <a.buev@xxxxxxxxx> > --- > block/fops.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 62 insertions(+) > > diff --git a/block/fops.c b/block/fops.c > index 4f59e0f5bf30..99c670b9f7d4 100644 > --- a/block/fops.c > +++ b/block/fops.c > @@ -16,6 +16,7 @@ > #include <linux/suspend.h> > #include <linux/fs.h> > #include <linux/module.h> > +#include <linux/blk-integrity.h> > #include "blk.h" > > static inline struct inode *bdev_file_inode(struct file *file) > @@ -44,6 +45,19 @@ static unsigned int dio_bio_write_op(struct kiocb *iocb) > > #define DIO_INLINE_BIO_VECS 4 > > +static int __bio_integrity_add_iovec(struct bio *bio, struct iov_iter *pi_iter) > +{ > + struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); > + unsigned int pi_len = bio_integrity_bytes(bi, bio->bi_iter.bi_size >> SECTOR_SHIFT); > + size_t iter_count = pi_iter->count-pi_len; > + int ret; > + > + iov_iter_truncate(pi_iter, pi_len); > + ret = bio_integrity_add_iovec(bio, pi_iter); > + pi_iter->count = iter_count; > + return ret; > +} > + > static void blkdev_bio_end_io_simple(struct bio *bio) > { > struct task_struct *waiter = bio->bi_private; > @@ -101,6 +115,14 @@ static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb, > if (iocb->ki_flags & IOCB_HIPRI) > bio_set_polled(&bio, iocb); > > + if (iocb->ki_flags & IOCB_USE_PI) { > + ret = __bio_integrity_add_iovec(&bio, iocb->pi_iter); > + if (ret) { > + bio_release_pages(&bio, should_dirty); > + goto out; > + } > + } > + > submit_bio(&bio); > for (;;) { > set_current_state(TASK_UNINTERRUPTIBLE); > @@ -252,6 +274,16 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, > pos += bio->bi_iter.bi_size; > > nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS); > + > + if (iocb->ki_flags & IOCB_USE_PI) { > + ret = __bio_integrity_add_iovec(bio, iocb->pi_iter); > + if (ret) { > + bio->bi_status = BLK_STS_IOERR; > + bio_endio(bio); > + break; > + } > + } > + > if (!nr_pages) { > submit_bio(bio); > break; > @@ -358,6 +390,15 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb, > task_io_account_write(bio->bi_iter.bi_size); > } > > + if (iocb->ki_flags & IOCB_USE_PI) { > + ret = __bio_integrity_add_iovec(bio, iocb->pi_iter); > + if (ret) { > + bio->bi_status = BLK_STS_IOERR; > + bio_endio(bio); > + return ret; > + } > + } > + > if (iocb->ki_flags & IOCB_HIPRI) { > bio->bi_opf |= REQ_POLLED | REQ_NOWAIT; > submit_bio(bio); > @@ -377,6 +418,27 @@ static ssize_t blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter) > if (!iov_iter_count(iter)) > return 0; > > + if (iocb->ki_flags & IOCB_USE_PI) { > + struct block_device *bdev = iocb->ki_filp->private_data; > + struct blk_integrity *bi = bdev_get_integrity(bdev); > + unsigned int intervals; > + > + if (unlikely(!(bi && bi->tuple_size && > + bi->flags & BLK_INTEGRITY_DEVICE_CAPABLE))) { > + pr_err("Device %d:%d is not integrity capable", > + MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev)); > + return -EINVAL; > + } > + > + intervals = bio_integrity_intervals(bi, iter->count >> 9); > + if (unlikely(intervals * bi->tuple_size > iocb->pi_iter->count)) { > + pr_err("Integrity & data size mismatch data=%zu integrity=%zu intervals=%u tuple=%u", > + iter->count, iocb->pi_iter->count, > + intervals, bi->tuple_size); > + return -EINVAL; > + } > + } > + Is there any reason above code is not moved into inline helper ? > nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS + 1); > if (likely(nr_pages <= BIO_MAX_VECS)) { > if (is_sync_kiocb(iocb)) >