aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier González <javier@cnexlabs.com>2017-10-13 08:46:22 -0400
committerJens Axboe <axboe@kernel.dk>2017-10-13 10:34:57 -0400
commita4809fee4e774fdf3296cc69c22ce6e6acef36b2 (patch)
tree6d0e2d6834b43dade6027d30f2fda792e00fe132
parent26532ee52b77185b095d29b54c83386f737a74ba (diff)
lightnvm: pblk: check lba sanity on read path
As part of pblk's recovery scheme, we store the lba mapped to each physical sector on the device's out-of-bound (OOB) area. On the read path, we can use this information to validate that the data being delivered to the upper layers corresponds to the lba being requested. The cost of this check is an extra copy on the DMA region on the device and an extra comparison in the host, given that (i) the OOB area is being read together with the data in the media, and (ii) the DMA region allocated for the ppa list can be reused for the metadata stored on the OOB area. Signed-off-by: Javier González <javier@cnexlabs.com> Signed-off-by: Matias Bjørling <m@bjorling.me> Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--drivers/lightnvm/pblk-read.c51
-rw-r--r--drivers/lightnvm/pblk.h4
2 files changed, 51 insertions, 4 deletions
diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c
index 0299fc08291d..a465d9980df4 100644
--- a/drivers/lightnvm/pblk-read.c
+++ b/drivers/lightnvm/pblk-read.c
@@ -41,6 +41,7 @@ static int pblk_read_from_cache(struct pblk *pblk, struct bio *bio,
41static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd, 41static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
42 sector_t blba, unsigned long *read_bitmap) 42 sector_t blba, unsigned long *read_bitmap)
43{ 43{
44 struct pblk_sec_meta *meta_list = rqd->meta_list;
44 struct bio *bio = rqd->bio; 45 struct bio *bio = rqd->bio;
45 struct ppa_addr ppas[PBLK_MAX_REQ_ADDRS]; 46 struct ppa_addr ppas[PBLK_MAX_REQ_ADDRS];
46 int nr_secs = rqd->nr_ppas; 47 int nr_secs = rqd->nr_ppas;
@@ -56,6 +57,7 @@ static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
56retry: 57retry:
57 if (pblk_ppa_empty(p)) { 58 if (pblk_ppa_empty(p)) {
58 WARN_ON(test_and_set_bit(i, read_bitmap)); 59 WARN_ON(test_and_set_bit(i, read_bitmap));
60 meta_list[i].lba = cpu_to_le64(ADDR_EMPTY);
59 61
60 if (unlikely(!advanced_bio)) { 62 if (unlikely(!advanced_bio)) {
61 bio_advance(bio, (i) * PBLK_EXPOSED_PAGE_SIZE); 63 bio_advance(bio, (i) * PBLK_EXPOSED_PAGE_SIZE);
@@ -75,6 +77,7 @@ retry:
75 goto retry; 77 goto retry;
76 } 78 }
77 WARN_ON(test_and_set_bit(i, read_bitmap)); 79 WARN_ON(test_and_set_bit(i, read_bitmap));
80 meta_list[i].lba = cpu_to_le64(lba);
78 advanced_bio = true; 81 advanced_bio = true;
79#ifdef CONFIG_NVM_DEBUG 82#ifdef CONFIG_NVM_DEBUG
80 atomic_long_inc(&pblk->cache_reads); 83 atomic_long_inc(&pblk->cache_reads);
@@ -110,10 +113,26 @@ static int pblk_submit_read_io(struct pblk *pblk, struct nvm_rq *rqd)
110 return NVM_IO_OK; 113 return NVM_IO_OK;
111} 114}
112 115
116static void pblk_read_check(struct pblk *pblk, struct nvm_rq *rqd,
117 sector_t blba)
118{
119 struct pblk_sec_meta *meta_list = rqd->meta_list;
120 int nr_lbas = rqd->nr_ppas;
121 int i;
122
123 for (i = 0; i < nr_lbas; i++) {
124 u64 lba = le64_to_cpu(meta_list[i].lba);
125
126 if (lba == ADDR_EMPTY)
127 continue;
128
129 WARN(lba != blba + i, "pblk: corrupted read LBA\n");
130 }
131}
132
113static void pblk_end_io_read(struct nvm_rq *rqd) 133static void pblk_end_io_read(struct nvm_rq *rqd)
114{ 134{
115 struct pblk *pblk = rqd->private; 135 struct pblk *pblk = rqd->private;
116 struct nvm_tgt_dev *dev = pblk->dev;
117 struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd); 136 struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd);
118 struct bio *bio = rqd->bio; 137 struct bio *bio = rqd->bio;
119 138
@@ -124,6 +143,8 @@ static void pblk_end_io_read(struct nvm_rq *rqd)
124 WARN_ONCE(bio->bi_status, "pblk: corrupted read error\n"); 143 WARN_ONCE(bio->bi_status, "pblk: corrupted read error\n");
125#endif 144#endif
126 145
146 pblk_read_check(pblk, rqd, r_ctx->lba);
147
127 bio_put(bio); 148 bio_put(bio);
128 if (r_ctx->private) { 149 if (r_ctx->private) {
129 struct bio *orig_bio = r_ctx->private; 150 struct bio *orig_bio = r_ctx->private;
@@ -149,15 +170,21 @@ static int pblk_fill_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd,
149 unsigned long *read_bitmap) 170 unsigned long *read_bitmap)
150{ 171{
151 struct bio *new_bio, *bio = rqd->bio; 172 struct bio *new_bio, *bio = rqd->bio;
173 struct pblk_sec_meta *meta_list = rqd->meta_list;
152 struct bio_vec src_bv, dst_bv; 174 struct bio_vec src_bv, dst_bv;
153 void *ppa_ptr = NULL; 175 void *ppa_ptr = NULL;
154 void *src_p, *dst_p; 176 void *src_p, *dst_p;
155 dma_addr_t dma_ppa_list = 0; 177 dma_addr_t dma_ppa_list = 0;
178 __le64 *lba_list_mem, *lba_list_media;
156 int nr_secs = rqd->nr_ppas; 179 int nr_secs = rqd->nr_ppas;
157 int nr_holes = nr_secs - bitmap_weight(read_bitmap, nr_secs); 180 int nr_holes = nr_secs - bitmap_weight(read_bitmap, nr_secs);
158 int i, ret, hole; 181 int i, ret, hole;
159 DECLARE_COMPLETION_ONSTACK(wait); 182 DECLARE_COMPLETION_ONSTACK(wait);
160 183
184 /* Re-use allocated memory for intermediate lbas */
185 lba_list_mem = (((void *)rqd->ppa_list) + pblk_dma_ppa_size);
186 lba_list_media = (((void *)rqd->ppa_list) + 2 * pblk_dma_ppa_size);
187
161 new_bio = bio_alloc(GFP_KERNEL, nr_holes); 188 new_bio = bio_alloc(GFP_KERNEL, nr_holes);
162 189
163 if (pblk_bio_add_pages(pblk, new_bio, GFP_KERNEL, nr_holes)) 190 if (pblk_bio_add_pages(pblk, new_bio, GFP_KERNEL, nr_holes))
@@ -168,6 +195,9 @@ static int pblk_fill_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd,
168 goto err; 195 goto err;
169 } 196 }
170 197
198 for (i = 0; i < nr_secs; i++)
199 lba_list_mem[i] = meta_list[i].lba;
200
171 new_bio->bi_iter.bi_sector = 0; /* internal bio */ 201 new_bio->bi_iter.bi_sector = 0; /* internal bio */
172 bio_set_op_attrs(new_bio, REQ_OP_READ, 0); 202 bio_set_op_attrs(new_bio, REQ_OP_READ, 0);
173 203
@@ -207,10 +237,17 @@ static int pblk_fill_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd,
207 rqd->dma_ppa_list = dma_ppa_list; 237 rqd->dma_ppa_list = dma_ppa_list;
208 } 238 }
209 239
240 for (i = 0; i < nr_secs; i++) {
241 lba_list_media[i] = meta_list[i].lba;
242 meta_list[i].lba = lba_list_mem[i];
243 }
244
210 /* Fill the holes in the original bio */ 245 /* Fill the holes in the original bio */
211 i = 0; 246 i = 0;
212 hole = find_first_zero_bit(read_bitmap, nr_secs); 247 hole = find_first_zero_bit(read_bitmap, nr_secs);
213 do { 248 do {
249 meta_list[hole].lba = lba_list_media[i];
250
214 src_bv = new_bio->bi_io_vec[i++]; 251 src_bv = new_bio->bi_io_vec[i++];
215 dst_bv = bio->bi_io_vec[bio_init_idx + hole]; 252 dst_bv = bio->bi_io_vec[bio_init_idx + hole];
216 253
@@ -251,6 +288,7 @@ err:
251static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, 288static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd,
252 sector_t lba, unsigned long *read_bitmap) 289 sector_t lba, unsigned long *read_bitmap)
253{ 290{
291 struct pblk_sec_meta *meta_list = rqd->meta_list;
254 struct bio *bio = rqd->bio; 292 struct bio *bio = rqd->bio;
255 struct ppa_addr ppa; 293 struct ppa_addr ppa;
256 294
@@ -263,6 +301,7 @@ static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd,
263retry: 301retry:
264 if (pblk_ppa_empty(ppa)) { 302 if (pblk_ppa_empty(ppa)) {
265 WARN_ON(test_and_set_bit(0, read_bitmap)); 303 WARN_ON(test_and_set_bit(0, read_bitmap));
304 meta_list[0].lba = cpu_to_le64(ADDR_EMPTY);
266 return; 305 return;
267 } 306 }
268 307
@@ -274,6 +313,9 @@ retry:
274 pblk_lookup_l2p_seq(pblk, &ppa, lba, 1); 313 pblk_lookup_l2p_seq(pblk, &ppa, lba, 1);
275 goto retry; 314 goto retry;
276 } 315 }
316
317 meta_list[0].lba = cpu_to_le64(lba);
318
277 WARN_ON(test_and_set_bit(0, read_bitmap)); 319 WARN_ON(test_and_set_bit(0, read_bitmap));
278#ifdef CONFIG_NVM_DEBUG 320#ifdef CONFIG_NVM_DEBUG
279 atomic_long_inc(&pblk->cache_reads); 321 atomic_long_inc(&pblk->cache_reads);
@@ -290,9 +332,10 @@ int pblk_submit_read(struct pblk *pblk, struct bio *bio)
290 struct nvm_tgt_dev *dev = pblk->dev; 332 struct nvm_tgt_dev *dev = pblk->dev;
291 sector_t blba = pblk_get_lba(bio); 333 sector_t blba = pblk_get_lba(bio);
292 unsigned int nr_secs = pblk_get_secs(bio); 334 unsigned int nr_secs = pblk_get_secs(bio);
335 struct pblk_g_ctx *r_ctx;
293 struct nvm_rq *rqd; 336 struct nvm_rq *rqd;
294 unsigned long read_bitmap; /* Max 64 ppas per request */
295 unsigned int bio_init_idx; 337 unsigned int bio_init_idx;
338 unsigned long read_bitmap; /* Max 64 ppas per request */
296 int ret = NVM_IO_ERR; 339 int ret = NVM_IO_ERR;
297 340
298 /* logic error: lba out-of-bounds. Ignore read request */ 341 /* logic error: lba out-of-bounds. Ignore read request */
@@ -312,6 +355,9 @@ int pblk_submit_read(struct pblk *pblk, struct bio *bio)
312 rqd->private = pblk; 355 rqd->private = pblk;
313 rqd->end_io = pblk_end_io_read; 356 rqd->end_io = pblk_end_io_read;
314 357
358 r_ctx = nvm_rq_to_pdu(rqd);
359 r_ctx->lba = blba;
360
315 /* Save the index for this bio's start. This is needed in case 361 /* Save the index for this bio's start. This is needed in case
316 * we need to fill a partial read. 362 * we need to fill a partial read.
317 */ 363 */
@@ -344,7 +390,6 @@ int pblk_submit_read(struct pblk *pblk, struct bio *bio)
344 /* All sectors are to be read from the device */ 390 /* All sectors are to be read from the device */
345 if (bitmap_empty(&read_bitmap, rqd->nr_ppas)) { 391 if (bitmap_empty(&read_bitmap, rqd->nr_ppas)) {
346 struct bio *int_bio = NULL; 392 struct bio *int_bio = NULL;
347 struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd);
348 393
349 /* Clone read bio to deal with read errors internally */ 394 /* Clone read bio to deal with read errors internally */
350 int_bio = bio_clone_fast(bio, GFP_KERNEL, pblk_bio_set); 395 int_bio = bio_clone_fast(bio, GFP_KERNEL, pblk_bio_set);
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index 12a20f800c26..4a51e6d4d036 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -99,6 +99,7 @@ enum {
99}; 99};
100 100
101#define pblk_dma_meta_size (sizeof(struct pblk_sec_meta) * PBLK_MAX_REQ_ADDRS) 101#define pblk_dma_meta_size (sizeof(struct pblk_sec_meta) * PBLK_MAX_REQ_ADDRS)
102#define pblk_dma_ppa_size (sizeof(u64) * PBLK_MAX_REQ_ADDRS)
102 103
103/* write buffer completion context */ 104/* write buffer completion context */
104struct pblk_c_ctx { 105struct pblk_c_ctx {
@@ -110,9 +111,10 @@ struct pblk_c_ctx {
110 unsigned int nr_padded; 111 unsigned int nr_padded;
111}; 112};
112 113
113/* generic context */ 114/* read context */
114struct pblk_g_ctx { 115struct pblk_g_ctx {
115 void *private; 116 void *private;
117 u64 lba;
116}; 118};
117 119
118/* Pad context */ 120/* Pad context */