diff --git a/block/bio-integrity.c b/block/bio-integrity.c index e79eaf047794..c8cfd15fb589 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -402,6 +402,20 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) extraction_flags, &offset); if (unlikely(ret < 0)) goto free_bvec; + /* Handle partial pinning. This can happen when pin_user_pages_fast() + * returns fewer pages than requested + */ + if (unlikely(ret != bytes)) { + int npinned = DIV_ROUND_UP(offset + ret, PAGE_SIZE); + int i; + + for (i = 0; i < npinned; i++) + unpin_user_page(pages[i]); + if (pages != stack_pages) + kvfree(pages); + ret = -EFAULT; + goto free_bvec; + } nr_bvecs = bvec_from_pages(bvec, pages, nr_vecs, bytes, offset, &is_p2p);