static int btt_read_pg()

in btt.c [1198:1294]


static int btt_read_pg(struct btt *btt, struct bio_integrity_payload *bip,
			struct page *page, unsigned int off, sector_t sector,
			unsigned int len)
{
	int ret = 0;
	int t_flag, e_flag;
	struct arena_info *arena = NULL;
	u32 lane = 0, premap, postmap;

	while (len) {
		u32 cur_len;

		lane = nd_region_acquire_lane(btt->nd_region);

		ret = lba_to_arena(btt, sector, &premap, &arena);
		if (ret)
			goto out_lane;

		cur_len = min(btt->sector_size, len);

		ret = btt_map_read(arena, premap, &postmap, &t_flag, &e_flag,
				NVDIMM_IO_ATOMIC);
		if (ret)
			goto out_lane;

		/*
		 * We loop to make sure that the post map LBA didn't change
		 * from under us between writing the RTT and doing the actual
		 * read.
		 */
		while (1) {
			u32 new_map;
			int new_t, new_e;

			if (t_flag) {
				zero_fill_data(page, off, cur_len);
				goto out_lane;
			}

			if (e_flag) {
				ret = -EIO;
				goto out_lane;
			}

			arena->rtt[lane] = RTT_VALID | postmap;
			/*
			 * Barrier to make sure this write is not reordered
			 * to do the verification map_read before the RTT store
			 */
			barrier();

			ret = btt_map_read(arena, premap, &new_map, &new_t,
						&new_e, NVDIMM_IO_ATOMIC);
			if (ret)
				goto out_rtt;

			if ((postmap == new_map) && (t_flag == new_t) &&
					(e_flag == new_e))
				break;

			postmap = new_map;
			t_flag = new_t;
			e_flag = new_e;
		}

		ret = btt_data_read(arena, page, off, postmap, cur_len);
		if (ret) {
			/* Media error - set the e_flag */
			if (btt_map_write(arena, premap, postmap, 0, 1, NVDIMM_IO_ATOMIC))
				dev_warn_ratelimited(to_dev(arena),
					"Error persistently tracking bad blocks at %#x\n",
					premap);
			goto out_rtt;
		}

		if (bip) {
			ret = btt_rw_integrity(btt, bip, arena, postmap, READ);
			if (ret)
				goto out_rtt;
		}

		arena->rtt[lane] = RTT_INVALID;
		nd_region_release_lane(btt->nd_region, lane);

		len -= cur_len;
		off += cur_len;
		sector += btt->sector_size >> SECTOR_SHIFT;
	}

	return 0;

 out_rtt:
	arena->rtt[lane] = RTT_INVALID;
 out_lane:
	nd_region_release_lane(btt->nd_region, lane);
	return ret;
}