/** * Create a copy of a write bio. */ struct bio* bio_deep_clone(struct bio *bio, gfp_t gfp_mask) { uint size; struct bio *clone; ASSERT(bio); ASSERT(op_is_write(bio_op(bio))); ASSERT(!bio->bi_next); if (bio_has_data(bio)) size = bio->bi_iter.bi_size; else size = 0; clone = bio_alloc_with_pages(size, bio->bi_bdev, gfp_mask); if (!clone) return NULL; clone->bi_opf = bio->bi_opf; clone->bi_iter.bi_sector = bio->bi_iter.bi_sector; if (size == 0) { /* This is for discard IOs. */ clone->bi_iter.bi_size = bio->bi_iter.bi_size; } else { bio_copy_data(clone, bio); } return clone; }
static blk_status_t pmem_do_bvec(struct pmem_device *pmem, struct page *page, unsigned int len, unsigned int off, unsigned int op, sector_t sector) { blk_status_t rc = BLK_STS_OK; bool bad_pmem = false; phys_addr_t pmem_off = sector * 512 + pmem->data_offset; void *pmem_addr = pmem->virt_addr + pmem_off; if (unlikely(is_bad_pmem(&pmem->bb, sector, len))) bad_pmem = true; if (!op_is_write(op)) { if (unlikely(bad_pmem)) rc = BLK_STS_IOERR; else { rc = read_pmem(page, off, pmem_addr, len); flush_dcache_page(page); } } else { /* * Note that we write the data both before and after * clearing poison. The write before clear poison * handles situations where the latest written data is * preserved and the clear poison operation simply marks * the address range as valid without changing the data. * In this case application software can assume that an * interrupted write will either return the new good * data or an error. * * However, if pmem_clear_poison() leaves the data in an * indeterminate state we need to perform the write * after clear poison. */ flush_dcache_page(page); write_pmem(pmem_addr, page, off, len); if (unlikely(bad_pmem)) { rc = pmem_clear_poison(pmem, pmem_off, len); write_pmem(pmem_addr, page, off, len); } } return rc; }
static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio) { int rc = 0; bool do_acct; unsigned long start; struct bio_vec bvec; struct bvec_iter iter; struct pmem_device *pmem = q->queuedata; struct nd_region *nd_region = to_region(pmem); if (bio->bi_opf & REQ_FLUSH) nvdimm_flush(nd_region); do_acct = nd_iostat_start(bio, &start); bio_for_each_segment(bvec, bio, iter) { rc = pmem_do_bvec(pmem, bvec.bv_page, bvec.bv_len, bvec.bv_offset, op_is_write(bio_op(bio)), iter.bi_sector); if (rc) { bio->bi_error = rc; break; } }