bool blk_integrity_merge_bio(struct request_queue *q, struct request *req, struct bio *bio) { int nr_integrity_segs; struct bio *next = bio->bi_next; if (blk_integrity_rq(req) == 0 && bio_integrity(bio) == NULL) return true; if (blk_integrity_rq(req) == 0 || bio_integrity(bio) == NULL) return false; if (bio_integrity(req->bio)->bip_flags != bio_integrity(bio)->bip_flags) return false; bio->bi_next = NULL; nr_integrity_segs = blk_rq_count_integrity_sg(q, bio); bio->bi_next = next; if (req->nr_integrity_segments + nr_integrity_segs > q->limits.max_integrity_segments) return false; req->nr_integrity_segments += nr_integrity_segs; return true; }
static void __bio_free(struct bio *bio) { bio_disassociate_task(bio); if (bio_integrity(bio)) bio_integrity_free(bio); }
/** * bio_integrity_process - Process integrity metadata for a bio * @bio: bio to generate/verify integrity metadata for * @proc_fn: Pointer to the relevant processing function */ static int bio_integrity_process(struct bio *bio, integrity_processing_fn *proc_fn) { struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); struct blk_integrity_iter iter; struct bvec_iter bviter; struct bio_vec bv; struct bio_integrity_payload *bip = bio_integrity(bio); unsigned int ret = 0; void *prot_buf = page_address(bip->bip_vec->bv_page) + bip->bip_vec->bv_offset; iter.disk_name = bio->bi_bdev->bd_disk->disk_name; iter.interval = bi->interval; iter.seed = bip_get_seed(bip); iter.prot_buf = prot_buf; bio_for_each_segment(bv, bio, bviter) { void *kaddr = kmap_atomic(bv.bv_page); iter.data_buf = kaddr + bv.bv_offset; iter.data_size = bv.bv_len; ret = proc_fn(&iter); if (ret) { kunmap_atomic(kaddr); return ret; } kunmap_atomic(kaddr); }
/** * bio_integrity_add_page - Attach integrity metadata * @bio: bio to update * @page: page containing integrity metadata * @len: number of bytes of integrity metadata in page * @offset: start offset within page * * Description: Attach a page containing integrity metadata to bio. */ int bio_integrity_add_page(struct bio *bio, struct page *page, unsigned int len, unsigned int offset) { struct bio_integrity_payload *bip = bio_integrity(bio); struct bio_vec *iv; if (bip->bip_vcnt >= bip->bip_max_vcnt) { printk(KERN_ERR "%s: bip_vec full\n", __func__); return 0; } iv = bip->bip_vec + bip->bip_vcnt; if (bip->bip_vcnt && bvec_gap_to_prev(bdev_get_queue(bio->bi_bdev), &bip->bip_vec[bip->bip_vcnt - 1], offset)) return 0; iv->bv_page = page; iv->bv_len = len; iv->bv_offset = offset; bip->bip_vcnt++; return len; }
static inline int ll_new_hw_segment(struct request_queue *q, struct request *req, struct bio *bio) { int nr_phys_segs = bio_phys_segments(q, bio); if (req->nr_phys_segments + nr_phys_segs > queue_max_segments(q)) goto no_merge; if (bio_integrity(bio) && blk_integrity_merge_bio(q, req, bio)) goto no_merge; /* * This will form the start of a new hw segment. Bump both * counters. */ req->nr_phys_segments += nr_phys_segs; return 1; no_merge: req->cmd_flags |= REQ_NOMERGE; if (req == q->last_merge) q->last_merge = NULL; return 0; }
/** * bio_integrity_enabled - Check whether integrity can be passed * @bio: bio to check * * Description: Determines whether bio_integrity_prep() can be called * on this bio or not. bio data direction and target device must be * set prior to calling. The functions honors the write_generate and * read_verify flags in sysfs. */ int bio_integrity_enabled(struct bio *bio) { /* Already protected? */ if (bio_integrity(bio)) return 0; return bdev_integrity_enabled(bio->bi_bdev, bio_data_dir(bio)); }
bool blk_integrity_merge_rq(struct request_queue *q, struct request *req, struct request *next) { if (blk_integrity_rq(req) == 0 && blk_integrity_rq(next) == 0) return true; if (blk_integrity_rq(req) == 0 || blk_integrity_rq(next) == 0) return false; if (bio_integrity(req->bio)->bip_flags != bio_integrity(next->bio)->bip_flags) return false; if (req->nr_integrity_segments + next->nr_integrity_segments > q->limits.max_integrity_segments) return false; return true; }
void bio_free(struct bio *bio, struct bio_set *bio_set) { if (bio->bi_io_vec) { const int pool_idx = BIO_POOL_IDX(bio); BIO_BUG_ON(pool_idx >= BIOVEC_NR_POOLS); mempool_free(bio->bi_io_vec, bio_set->bvec_pools[pool_idx]); } if (bio_integrity(bio)) bio_integrity_free(bio, bio_set); mempool_free(bio, bio_set->bio_pool); }
void bio_free(struct bio *bio, struct bio_set *bs) { void *p; if (bio_has_allocated_vec(bio)) bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio)); if (bio_integrity(bio)) bio_integrity_free(bio, bs); p = bio; if (bs->front_pad) p -= bs->front_pad; mempool_free(p, bs->bio_pool); }
void bio_free(struct bio *bio, struct bio_set *bs) { void *p; if (bio_has_allocated_vec(bio)) bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio)); if (bio_integrity(bio)) bio_integrity_free(bio, bs); /* * If we have front padding, adjust the bio pointer before freeing */ p = bio; if (bs->front_pad) p -= bs->front_pad; mempool_free(p, bs->bio_pool); }
static void nd_blk_make_request(struct request_queue *q, struct bio *bio) { struct block_device *bdev = bio->bi_bdev; struct gendisk *disk = bdev->bd_disk; struct bio_integrity_payload *bip; struct nd_blk_device *blk_dev; struct bvec_iter iter; unsigned long start; struct bio_vec bvec; int err = 0, rw; bool do_acct; /* * bio_integrity_enabled also checks if the bio already has an * integrity payload attached. If it does, we *don't* do a * bio_integrity_prep here - the payload has been generated by * another kernel subsystem, and we just pass it through. */ if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { bio->bi_error = -EIO; goto out; } bip = bio_integrity(bio); blk_dev = disk->private_data; rw = bio_data_dir(bio); do_acct = nd_iostat_start(bio, &start); bio_for_each_segment(bvec, bio, iter) { unsigned int len = bvec.bv_len; BUG_ON(len > PAGE_SIZE); err = nd_blk_do_bvec(blk_dev, bip, bvec.bv_page, len, bvec.bv_offset, rw, iter.bi_sector); if (err) { dev_info(&blk_dev->nsblk->common.dev, "io error in %s sector %lld, len %d,\n", (rw == READ) ? "READ" : "WRITE", (unsigned long long) iter.bi_sector, len); bio->bi_error = err; break; } }
/** * bio_integrity_add_page - Attach integrity metadata * @bio: bio to update * @page: page containing integrity metadata * @len: number of bytes of integrity metadata in page * @offset: start offset within page * * Description: Attach a page containing integrity metadata to bio. */ int bio_integrity_add_page(struct bio *bio, struct page *page, unsigned int len, unsigned int offset) { struct bio_integrity_payload *bip = bio_integrity(bio); struct bio_vec *iv; if (bip->bip_vcnt >= bip->bip_max_vcnt) { printk(KERN_ERR "%s: bip_vec full\n", __func__); return 0; } iv = bip->bip_vec + bip->bip_vcnt; iv->bv_page = page; iv->bv_len = len; iv->bv_offset = offset; bip->bip_vcnt++; return len; }
/** * bio_integrity_free - Free bio integrity payload * @bio: bio containing bip to be freed * * Description: Used to free the integrity portion of a bio. Usually * called from bio_free(). */ void bio_integrity_free(struct bio *bio) { struct bio_integrity_payload *bip = bio_integrity(bio); struct bio_set *bs = bio->bi_pool; if (bip->bip_flags & BIP_BLOCK_INTEGRITY) kfree(page_address(bip->bip_vec->bv_page) + bip->bip_vec->bv_offset); if (bs) { if (bip->bip_slab != BIO_POOL_NONE) bvec_free(bs->bvec_integrity_pool, bip->bip_vec, bip->bip_slab); mempool_free(bip, bs->bio_integrity_pool); } else { kfree(bip); } bio->bi_integrity = NULL; }
bool blk_rq_merge_ok(struct request *rq, struct bio *bio) { struct request_queue *q = rq->q; if (!rq_mergeable(rq) || !bio_mergeable(bio)) return false; if (!blk_check_merge_flags(rq->cmd_flags, bio->bi_rw)) return false; /* different data direction or already started, don't merge */ if (bio_data_dir(bio) != rq_data_dir(rq)) return false; /* must be same device and not a special request */ if (rq->rq_disk != bio->bi_bdev->bd_disk || req_no_special_merge(rq)) return false; /* only merge integrity protected bio into ditto rq */ if (bio_integrity(bio) != blk_integrity_rq(rq)) return false; /* must be using the same buffer */ if (rq->cmd_flags & REQ_WRITE_SAME && !blk_write_same_mergeable(rq->bio, bio)) return false; if (q->queue_flags & (1 << QUEUE_FLAG_SG_GAPS)) { struct bio_vec *bprev; bprev = &rq->biotail->bi_io_vec[rq->biotail->bi_vcnt - 1]; if (bvec_gap_to_prev(bprev, bio->bi_io_vec[0].bv_offset)) return false; } return true; }
/** * bio_integrity_enabled - Check whether integrity can be passed * @bio: bio to check * * Description: Determines whether bio_integrity_prep() can be called * on this bio or not. bio data direction and target device must be * set prior to calling. The functions honors the write_generate and * read_verify flags in sysfs. */ bool bio_integrity_enabled(struct bio *bio) { struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); if (!bio_is_rw(bio)) return false; /* Already protected? */ if (bio_integrity(bio)) return false; if (bi == NULL) return false; if (bio_data_dir(bio) == READ && bi->verify_fn != NULL && (bi->flags & BLK_INTEGRITY_VERIFY)) return true; if (bio_data_dir(bio) == WRITE && bi->generate_fn != NULL && (bi->flags & BLK_INTEGRITY_GENERATE)) return true; return false; }
static void bio_kmalloc_destructor(struct bio *bio) { if (bio_integrity(bio)) bio_integrity_free(bio, fs_bio_set); kfree(bio); }