/* This is the copy-in part of SG_DXFER_TO_FROM_DEV. */
iter2.data_source = ITER_SOURCE;
ret = bio_copy_from_iter(bio, &iter2); if (ret) goto cleanup;
} else { if (bmd->is_our_pages)
zero_fill_bio(bio);
iov_iter_advance(iter, bio->bi_iter.bi_size);
}
bio->bi_private = bmd;
ret = blk_rq_append_bio(rq, bio); if (ret) goto cleanup; return0;
cleanup: if (!map_data)
bio_free_pages(bio);
bio_uninit(bio);
kfree(bio);
out_bmd:
kfree(bmd); return ret;
}
staticvoid blk_mq_map_bio_put(struct bio *bio)
{ if (bio->bi_opf & REQ_ALLOC_CACHE) {
bio_put(bio);
} else {
bio_uninit(bio);
kfree(bio);
}
}
staticstruct bio *blk_rq_map_bio_alloc(struct request *rq, unsignedint nr_vecs, gfp_t gfp_mask)
{ struct bio *bio;
if (rq->cmd_flags & REQ_ALLOC_CACHE && (nr_vecs <= BIO_INLINE_VECS)) {
bio = bio_alloc_bioset(NULL, nr_vecs, rq->cmd_flags, gfp_mask,
&fs_bio_set); if (!bio) return NULL;
} else {
bio = bio_kmalloc(nr_vecs, gfp_mask); if (!bio) return NULL;
bio_init(bio, NULL, bio->bi_inline_vecs, nr_vecs, req_op(rq));
} return bio;
}
staticint bio_map_user_iov(struct request *rq, struct iov_iter *iter,
gfp_t gfp_mask)
{ unsignedint nr_vecs = iov_iter_npages(iter, BIO_MAX_VECS); struct bio *bio; int ret;
if (!iov_iter_count(iter)) return -EINVAL;
bio = blk_rq_map_bio_alloc(rq, nr_vecs, gfp_mask); if (!bio) return -ENOMEM;
ret = bio_iov_iter_get_pages(bio, iter); if (ret) goto out_put;
ret = blk_rq_append_bio(rq, bio); if (ret) goto out_release; return0;
staticvoid bio_invalidate_vmalloc_pages(struct bio *bio)
{ #ifdef ARCH_IMPLEMENTS_FLUSH_KERNEL_VMAP_RANGE if (bio->bi_private && !op_is_write(bio_op(bio))) { unsignedlong i, len = 0;
for (i = 0; i < bio->bi_vcnt; i++)
len += bio->bi_io_vec[i].bv_len;
invalidate_kernel_vmap_range(bio->bi_private, len);
} #endif
}
staticvoid bio_map_kern_endio(struct bio *bio)
{
bio_invalidate_vmalloc_pages(bio);
bio_uninit(bio);
kfree(bio);
}
staticstruct bio *bio_map_kern(void *data, unsignedint len, enum req_op op,
gfp_t gfp_mask)
{ unsignedint nr_vecs = bio_add_max_vecs(data, len); struct bio *bio;
/* *Appendabiotoapassthroughrequest.Onlyworksifthebiocanbemerged *intotherequestbasedonthedriverconstraints.
*/ int blk_rq_append_bio(struct request *rq, struct bio *bio)
{ conststruct queue_limits *lim = &rq->q->limits; unsignedint max_bytes = lim->max_hw_sectors << SECTOR_SHIFT; unsignedint nr_segs = 0; int ret;
/* check that the data layout matches the hardware restrictions */
ret = bio_split_io_at(bio, lim, &nr_segs, max_bytes, 0); if (ret) { /* if we would have to split the bio, copy instead */ if (ret > 0)
ret = -EREMOTEIO; return ret;
}
/* Prepare bio for passthrough IO given ITER_BVEC iter */ staticint blk_rq_map_user_bvec(struct request *rq, conststruct iov_iter *iter)
{ unsignedint max_bytes = rq->q->limits.max_hw_sectors << SECTOR_SHIFT; struct bio *bio; int ret;
if (!iov_iter_count(iter) || iov_iter_count(iter) > max_bytes) return -EINVAL;
/* reuse the bvecs from the iterator instead of allocating new ones */
bio = blk_rq_map_bio_alloc(rq, 0, GFP_KERNEL); if (!bio) return -ENOMEM;
bio_iov_bvec_set(bio, iter);
ret = blk_rq_append_bio(rq, bio); if (ret)
blk_mq_map_bio_put(bio); return ret;
}
if (map_bvec) {
ret = blk_rq_map_user_bvec(rq, iter); if (!ret) return0; if (ret != -EREMOTEIO) goto fail; /* fall back to copying the data on limits mismatches */
copy = true;
}
i = *iter; do { if (copy)
ret = bio_copy_user_iov(rq, map_data, &i, gfp_mask); else
ret = bio_map_user_iov(rq, &i, gfp_mask); if (ret) { if (ret == -EREMOTEIO)
ret = -EINVAL; goto unmap_rq;
} if (!bio)
bio = rq->bio;
} while (iov_iter_count(&i));
ret = import_iovec(rw, ubuf, iov_count ? iov_count : buf_len,
UIO_FASTIOV, &iov, &iter); if (ret < 0) return ret;
if (iov_count) { /* SG_IO howto says that the shorter of the two wins */
iov_iter_truncate(&iter, buf_len); if (check_iter_count && !iov_iter_count(&iter)) {
kfree(iov); return -EINVAL;
}
}
/** *blk_rq_unmap_user-unmaparequestwithuserdata *@bio:startofbiolist * *Description: *Unmaparqpreviouslymappedbyblk_rq_map_user().Thecallermust *supplytheoriginalrq->biofromtheblk_rq_map_user()return,since *theI/Ocompletionmayhavechangedrq->bio.
*/ int blk_rq_unmap_user(struct bio *bio)
{ struct bio *next_bio; int ret = 0, ret2;
while (bio) { if (bio->bi_private) {
ret2 = bio_uncopy_user(bio); if (ret2 && !ret)
ret = ret2;
} else {
bio_release_pages(bio, bio_data_dir(bio) == READ);
}
if (bio_integrity(bio))
bio_integrity_unmap_user(bio);
next_bio = bio;
bio = bio->bi_next;
blk_mq_map_bio_put(next_bio);
}
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 und die Messung sind noch experimentell.