int bio_integrity_map_user(struct bio *bio, void __user *ubuf, unsigned int len, > + u32 seed, u32 maxvecs) > +{ > + struct request_queue *q = bdev_get_queue(bio->bi_bdev); > + unsigned long align = q->dma_pad_mask | queue_dma_alignment(q); > + struct page *stack_pages[UIO_FASTIOV]; > + size_t offset = offset_in_page(ubuf); > + unsigned long ptr = (uintptr_t)ubuf; > + struct page **pages = stack_pages; > + struct bio_integrity_payload *bip; > + int npages, ret, i; > + > + if (bio_integrity(bio) || ptr & align || maxvecs > UIO_FASTIOV) > + return -EINVAL; We also need to check the length for the dma alignment/pad, not just the start. (The undocumented iov_iter_alignment_iovec helper obsfucateѕ this for the data path). > + bip = bio_integrity_alloc(bio, GFP_KERNEL, maxvecs); > + if (IS_ERR(bip)) > + return PTR_ERR(bip); > + > + ret = pin_user_pages_fast(ptr, UIO_FASTIOV, FOLL_WRITE, pages); > + if (unlikely(ret < 0)) > + goto free_bip; > + > + npages = ret; > + for (i = 0; i < npages; i++) { > + u32 bytes = min_t(u32, len, PAGE_SIZE - offset); > + ret = bio_integrity_add_page(bio, pages[i], bytes, offset); > + if (ret != bytes) { > + ret = -EINVAL; > + goto release_pages; > + } > + len -= ret; > + offset = 0; > + } Any reason to not use the bio_vec array as the buffer, similar to the data size here? > +EXPORT_SYMBOL(bio_integrity_map_user); Everything that just thinly wraps get_user_pages_fast needs to be EXPORT_SYMBOL_GPL.