/** * bio_integrity_free - Free bio integrity payload * @bio: bio containing bip to be freed * * Description: Free the integrity portion of a bio.
*/ void bio_integrity_free(struct bio *bio)
{
kfree(bio_integrity(bio));
bio->bi_integrity = NULL;
bio->bi_opf &= ~REQ_INTEGRITY;
}
/** * bio_integrity_alloc - Allocate integrity payload and attach it to bio * @bio: bio to attach integrity metadata to * @gfp_mask: Memory allocation mask * @nr_vecs: Number of integrity metadata scatter-gather elements * * Description: This function prepares a bio for attaching integrity * metadata. nr_vecs specifies the maximum number of pages containing * integrity metadata that can be attached.
*/ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
gfp_t gfp_mask, unsignedint nr_vecs)
{ struct bio_integrity_alloc *bia;
if (WARN_ON_ONCE(bio_has_crypt_ctx(bio))) return ERR_PTR(-EOPNOTSUPP);
/** * bio_integrity_unmap_user - Unmap user integrity payload * @bio: bio containing bip to be unmapped * * Unmap the user mapped integrity portion of a bio.
*/ void bio_integrity_unmap_user(struct bio *bio)
{ struct bio_integrity_payload *bip = bio_integrity(bio);
if (bip->bip_flags & BIP_COPY_USER) { if (bio_data_dir(bio) == READ)
bio_integrity_uncopy_user(bip);
kfree(bvec_virt(bip->bip_vec)); return;
}
if (bip->bip_vcnt >=
min(bip->bip_max_vcnt, queue_max_integrity_segments(q))) return 0;
/* * If the queue doesn't support SG gaps and adding this segment * would create a gap, disallow it.
*/ if (bvec_gap_to_prev(&q->limits, bv, offset)) return 0;
}
/* * We need to preserve the original bvec and the number of vecs * in it for completion handling
*/
bip = bio_integrity_alloc(bio, GFP_KERNEL, nr_vecs + 1);
}
if (IS_ERR(bip)) {
ret = PTR_ERR(bip); goto free_buf;
}
if (write)
bio_integrity_unpin_bvec(bvec, nr_vecs); else
memcpy(&bip->bip_vec[1], bvec, nr_vecs * sizeof(*bvec));
ret = bio_integrity_add_page(bio, virt_to_page(buf), len,
offset_in_page(buf)); if (ret != len) {
ret = -ENOMEM; goto free_bip;
}
if (bio_integrity(bio)) return -EINVAL; if (bytes >> SECTOR_SHIFT > queue_max_hw_sectors(q)) return -E2BIG;
nr_vecs = iov_iter_npages(iter, BIO_MAX_VECS + 1); if (nr_vecs > BIO_MAX_VECS) return -E2BIG; if (nr_vecs > UIO_FASTIOV) {
bvec = kcalloc(nr_vecs, sizeof(*bvec), GFP_KERNEL); if (!bvec) return -ENOMEM;
pages = NULL;
}
copy = !iov_iter_is_aligned(iter, align, align);
ret = iov_iter_extract_pages(iter, &pages, bytes, nr_vecs, 0, &offset); if (unlikely(ret < 0)) goto free_bvec;
nr_bvecs = bvec_from_pages(bvec, pages, nr_vecs, bytes, offset); if (pages != stack_pages)
kvfree(pages); if (nr_bvecs > queue_max_integrity_segments(q))
copy = true;
if (copy)
ret = bio_integrity_copy_user(bio, bvec, nr_bvecs, bytes); else
ret = bio_integrity_init_user(bio, bvec, nr_bvecs, bytes); if (ret) goto release_pages; if (bvec != stack_vec)
kfree(bvec);
if (meta->flags & IO_INTEGRITY_CHK_GUARD)
bip->bip_flags |= BIP_CHECK_GUARD; if (meta->flags & IO_INTEGRITY_CHK_APPTAG)
bip->bip_flags |= BIP_CHECK_APPTAG; if (meta->flags & IO_INTEGRITY_CHK_REFTAG)
bip->bip_flags |= BIP_CHECK_REFTAG;
bip->app_tag = meta->app_tag;
}
int bio_integrity_map_iter(struct bio *bio, struct uio_meta *meta)
{ struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk); unsignedint integrity_bytes; int ret; struct iov_iter it;
if (!bi) return -EINVAL; /* * original meta iterator can be bigger. * process integrity info corresponding to current data buffer only.
*/
it = meta->iter;
integrity_bytes = bio_integrity_bytes(bi, bio_sectors(bio)); if (it.count < integrity_bytes) return -EINVAL;
/* should fit into two bytes */
BUILD_BUG_ON(IO_INTEGRITY_VALID_FLAGS >= (1 << 16));
if (meta->flags && (meta->flags & ~IO_INTEGRITY_VALID_FLAGS)) return -EINVAL;
/** * bio_integrity_advance - Advance integrity vector * @bio: bio whose integrity vector to update * @bytes_done: number of data bytes that have been completed * * Description: This function calculates how many integrity bytes the * number of completed data bytes correspond to and advances the * integrity vector accordingly.
*/ void bio_integrity_advance(struct bio *bio, unsignedint bytes_done)
{ struct bio_integrity_payload *bip = bio_integrity(bio); struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk); unsigned bytes = bio_integrity_bytes(bi, bytes_done >> 9);
/** * bio_integrity_trim - Trim integrity vector * @bio: bio whose integrity vector to update * * Description: Used to trim the integrity vector in a cloned bio.
*/ void bio_integrity_trim(struct bio *bio)
{ struct bio_integrity_payload *bip = bio_integrity(bio); struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
/** * bio_integrity_clone - Callback for cloning bios with integrity metadata * @bio: New bio * @bio_src: Original bio * @gfp_mask: Memory allocation mask * * Description: Called to allocate a bip when cloning a bio
*/ int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
gfp_t gfp_mask)
{ struct bio_integrity_payload *bip_src = bio_integrity(bio_src); struct bio_integrity_payload *bip;
BUG_ON(bip_src == NULL);
bip = bio_integrity_alloc(bio, gfp_mask, 0); if (IS_ERR(bip)) return PTR_ERR(bip);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.