.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2016 CNEX Labs |
---|
3 | 4 | * Initial release: Javier Gonzalez <javier@cnexlabs.com> |
---|
.. | .. |
---|
16 | 17 | */ |
---|
17 | 18 | |
---|
18 | 19 | #include "pblk.h" |
---|
| 20 | +#include "pblk-trace.h" |
---|
19 | 21 | |
---|
20 | 22 | static unsigned long pblk_end_w_bio(struct pblk *pblk, struct nvm_rq *rqd, |
---|
21 | 23 | struct pblk_c_ctx *c_ctx) |
---|
.. | .. |
---|
81 | 83 | #ifdef CONFIG_NVM_PBLK_DEBUG |
---|
82 | 84 | atomic_long_sub(c_ctx->nr_valid, &pblk->inflight_writes); |
---|
83 | 85 | #endif |
---|
84 | | - |
---|
85 | | - pblk_up_rq(pblk, rqd->ppa_list, rqd->nr_ppas, c_ctx->lun_bitmap); |
---|
| 86 | + pblk_up_rq(pblk, c_ctx->lun_bitmap); |
---|
86 | 87 | |
---|
87 | 88 | pos = pblk_rb_sync_init(&pblk->rwb, &flags); |
---|
88 | 89 | if (pos == c_ctx->sentry) { |
---|
.. | .. |
---|
104 | 105 | } |
---|
105 | 106 | |
---|
106 | 107 | /* Map remaining sectors in chunk, starting from ppa */ |
---|
107 | | -static void pblk_map_remaining(struct pblk *pblk, struct ppa_addr *ppa) |
---|
| 108 | +static void pblk_map_remaining(struct pblk *pblk, struct ppa_addr *ppa, |
---|
| 109 | + int rqd_ppas) |
---|
108 | 110 | { |
---|
109 | | - struct nvm_tgt_dev *dev = pblk->dev; |
---|
110 | | - struct nvm_geo *geo = &dev->geo; |
---|
111 | 111 | struct pblk_line *line; |
---|
112 | 112 | struct ppa_addr map_ppa = *ppa; |
---|
| 113 | + __le64 addr_empty = cpu_to_le64(ADDR_EMPTY); |
---|
| 114 | + __le64 *lba_list; |
---|
113 | 115 | u64 paddr; |
---|
114 | 116 | int done = 0; |
---|
| 117 | + int n = 0; |
---|
115 | 118 | |
---|
116 | | - line = &pblk->lines[pblk_ppa_to_line(*ppa)]; |
---|
| 119 | + line = pblk_ppa_to_line(pblk, *ppa); |
---|
| 120 | + lba_list = emeta_to_lbas(pblk, line->emeta->buf); |
---|
| 121 | + |
---|
117 | 122 | spin_lock(&line->lock); |
---|
118 | 123 | |
---|
119 | 124 | while (!done) { |
---|
.. | .. |
---|
122 | 127 | if (!test_and_set_bit(paddr, line->map_bitmap)) |
---|
123 | 128 | line->left_msecs--; |
---|
124 | 129 | |
---|
| 130 | + if (n < rqd_ppas && lba_list[paddr] != addr_empty) |
---|
| 131 | + line->nr_valid_lbas--; |
---|
| 132 | + |
---|
| 133 | + lba_list[paddr] = addr_empty; |
---|
| 134 | + |
---|
125 | 135 | if (!test_and_set_bit(paddr, line->invalid_bitmap)) |
---|
126 | 136 | le32_add_cpu(line->vsc, -1); |
---|
127 | 137 | |
---|
128 | | - if (geo->version == NVM_OCSSD_SPEC_12) { |
---|
129 | | - map_ppa.ppa++; |
---|
130 | | - if (map_ppa.g.pg == geo->num_pg) |
---|
131 | | - done = 1; |
---|
132 | | - } else { |
---|
133 | | - map_ppa.m.sec++; |
---|
134 | | - if (map_ppa.m.sec == geo->clba) |
---|
135 | | - done = 1; |
---|
136 | | - } |
---|
| 138 | + done = nvm_next_ppa_in_chk(pblk->dev, &map_ppa); |
---|
| 139 | + |
---|
| 140 | + n++; |
---|
137 | 141 | } |
---|
138 | 142 | |
---|
139 | 143 | line->w_err_gc->has_write_err = 1; |
---|
.. | .. |
---|
149 | 153 | struct pblk_w_ctx *w_ctx; |
---|
150 | 154 | struct ppa_addr ppa_l2p; |
---|
151 | 155 | int flags; |
---|
152 | | - unsigned int pos, i; |
---|
| 156 | + unsigned int i; |
---|
153 | 157 | |
---|
154 | 158 | spin_lock(&pblk->trans_lock); |
---|
155 | | - pos = sentry; |
---|
156 | 159 | for (i = 0; i < nr_entries; i++) { |
---|
157 | | - entry = &rb->entries[pos]; |
---|
| 160 | + entry = &rb->entries[pblk_rb_ptr_wrap(rb, sentry, i)]; |
---|
158 | 161 | w_ctx = &entry->w_ctx; |
---|
159 | 162 | |
---|
160 | 163 | /* Check if the lba has been overwritten */ |
---|
.. | .. |
---|
170 | 173 | /* Release flags on write context. Protect from writes */ |
---|
171 | 174 | smp_store_release(&w_ctx->flags, flags); |
---|
172 | 175 | |
---|
173 | | - /* Decrese the reference count to the line as we will |
---|
| 176 | + /* Decrease the reference count to the line as we will |
---|
174 | 177 | * re-map these entries |
---|
175 | 178 | */ |
---|
176 | | - line = &pblk->lines[pblk_ppa_to_line(w_ctx->ppa)]; |
---|
| 179 | + line = pblk_ppa_to_line(pblk, w_ctx->ppa); |
---|
| 180 | + atomic_dec(&line->sec_to_update); |
---|
177 | 181 | kref_put(&line->ref, pblk_line_put); |
---|
178 | | - |
---|
179 | | - pos = (pos + 1) & (rb->nr_entries - 1); |
---|
180 | 182 | } |
---|
181 | 183 | spin_unlock(&pblk->trans_lock); |
---|
182 | 184 | } |
---|
.. | .. |
---|
210 | 212 | struct pblk *pblk = recovery->pblk; |
---|
211 | 213 | struct nvm_rq *rqd = recovery->rqd; |
---|
212 | 214 | struct pblk_c_ctx *c_ctx = nvm_rq_to_pdu(rqd); |
---|
213 | | - struct ppa_addr *ppa_list; |
---|
| 215 | + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); |
---|
214 | 216 | |
---|
215 | 217 | pblk_log_write_err(pblk, rqd); |
---|
216 | 218 | |
---|
217 | | - if (rqd->nr_ppas == 1) |
---|
218 | | - ppa_list = &rqd->ppa_addr; |
---|
219 | | - else |
---|
220 | | - ppa_list = rqd->ppa_list; |
---|
221 | | - |
---|
222 | | - pblk_map_remaining(pblk, ppa_list); |
---|
| 219 | + pblk_map_remaining(pblk, ppa_list, rqd->nr_ppas); |
---|
223 | 220 | pblk_queue_resubmit(pblk, c_ctx); |
---|
224 | 221 | |
---|
225 | | - pblk_up_rq(pblk, rqd->ppa_list, rqd->nr_ppas, c_ctx->lun_bitmap); |
---|
| 222 | + pblk_up_rq(pblk, c_ctx->lun_bitmap); |
---|
226 | 223 | if (c_ctx->nr_padded) |
---|
227 | 224 | pblk_bio_free_pages(pblk, rqd->bio, c_ctx->nr_valid, |
---|
228 | 225 | c_ctx->nr_padded); |
---|
.. | .. |
---|
231 | 228 | mempool_free(recovery, &pblk->rec_pool); |
---|
232 | 229 | |
---|
233 | 230 | atomic_dec(&pblk->inflight_io); |
---|
| 231 | + pblk_write_kick(pblk); |
---|
234 | 232 | } |
---|
235 | 233 | |
---|
236 | 234 | |
---|
.. | .. |
---|
259 | 257 | if (rqd->error) { |
---|
260 | 258 | pblk_end_w_fail(pblk, rqd); |
---|
261 | 259 | return; |
---|
262 | | - } |
---|
| 260 | + } else { |
---|
| 261 | + if (trace_pblk_chunk_state_enabled()) |
---|
| 262 | + pblk_check_chunk_state_update(pblk, rqd); |
---|
263 | 263 | #ifdef CONFIG_NVM_PBLK_DEBUG |
---|
264 | | - else |
---|
265 | 264 | WARN_ONCE(rqd->bio->bi_status, "pblk: corrupted write error\n"); |
---|
266 | 265 | #endif |
---|
| 266 | + } |
---|
267 | 267 | |
---|
268 | 268 | pblk_complete_write(pblk, rqd, c_ctx); |
---|
269 | 269 | atomic_dec(&pblk->inflight_io); |
---|
.. | .. |
---|
275 | 275 | struct pblk_g_ctx *m_ctx = nvm_rq_to_pdu(rqd); |
---|
276 | 276 | struct pblk_line *line = m_ctx->private; |
---|
277 | 277 | struct pblk_emeta *emeta = line->emeta; |
---|
| 278 | + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); |
---|
278 | 279 | int sync; |
---|
279 | 280 | |
---|
280 | | - pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas); |
---|
| 281 | + pblk_up_chunk(pblk, ppa_list[0]); |
---|
281 | 282 | |
---|
282 | 283 | if (rqd->error) { |
---|
283 | 284 | pblk_log_write_err(pblk, rqd); |
---|
284 | 285 | pblk_err(pblk, "metadata I/O failed. Line %d\n", line->id); |
---|
285 | 286 | line->w_err_gc->has_write_err = 1; |
---|
| 287 | + } else { |
---|
| 288 | + if (trace_pblk_chunk_state_enabled()) |
---|
| 289 | + pblk_check_chunk_state_update(pblk, rqd); |
---|
286 | 290 | } |
---|
287 | 291 | |
---|
288 | 292 | sync = atomic_add_return(rqd->nr_ppas, &emeta->sync); |
---|
.. | .. |
---|
296 | 300 | } |
---|
297 | 301 | |
---|
298 | 302 | static int pblk_alloc_w_rq(struct pblk *pblk, struct nvm_rq *rqd, |
---|
299 | | - unsigned int nr_secs, |
---|
300 | | - nvm_end_io_fn(*end_io)) |
---|
| 303 | + unsigned int nr_secs, nvm_end_io_fn(*end_io)) |
---|
301 | 304 | { |
---|
302 | | - struct nvm_tgt_dev *dev = pblk->dev; |
---|
303 | | - |
---|
304 | 305 | /* Setup write request */ |
---|
305 | 306 | rqd->opcode = NVM_OP_PWRITE; |
---|
306 | 307 | rqd->nr_ppas = nr_secs; |
---|
307 | | - rqd->flags = pblk_set_progr_mode(pblk, PBLK_WRITE); |
---|
| 308 | + rqd->is_seq = 1; |
---|
308 | 309 | rqd->private = pblk; |
---|
309 | 310 | rqd->end_io = end_io; |
---|
310 | 311 | |
---|
311 | | - rqd->meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, |
---|
312 | | - &rqd->dma_meta_list); |
---|
313 | | - if (!rqd->meta_list) |
---|
314 | | - return -ENOMEM; |
---|
315 | | - |
---|
316 | | - rqd->ppa_list = rqd->meta_list + pblk_dma_meta_size; |
---|
317 | | - rqd->dma_ppa_list = rqd->dma_meta_list + pblk_dma_meta_size; |
---|
318 | | - |
---|
319 | | - return 0; |
---|
| 312 | + return pblk_alloc_rqd_meta(pblk, rqd); |
---|
320 | 313 | } |
---|
321 | 314 | |
---|
322 | 315 | static int pblk_setup_w_rq(struct pblk *pblk, struct nvm_rq *rqd, |
---|
.. | .. |
---|
343 | 336 | } |
---|
344 | 337 | |
---|
345 | 338 | if (likely(!e_line || !atomic_read(&e_line->left_eblks))) |
---|
346 | | - pblk_map_rq(pblk, rqd, c_ctx->sentry, lun_bitmap, valid, 0); |
---|
| 339 | + ret = pblk_map_rq(pblk, rqd, c_ctx->sentry, lun_bitmap, |
---|
| 340 | + valid, 0); |
---|
347 | 341 | else |
---|
348 | | - pblk_map_erase_rq(pblk, rqd, c_ctx->sentry, lun_bitmap, |
---|
| 342 | + ret = pblk_map_erase_rq(pblk, rqd, c_ctx->sentry, lun_bitmap, |
---|
349 | 343 | valid, erase_ppa); |
---|
350 | 344 | |
---|
351 | | - return 0; |
---|
| 345 | + return ret; |
---|
352 | 346 | } |
---|
353 | 347 | |
---|
354 | 348 | static int pblk_calc_secs_to_sync(struct pblk *pblk, unsigned int secs_avail, |
---|
.. | .. |
---|
356 | 350 | { |
---|
357 | 351 | int secs_to_sync; |
---|
358 | 352 | |
---|
359 | | - secs_to_sync = pblk_calc_secs(pblk, secs_avail, secs_to_flush); |
---|
| 353 | + secs_to_sync = pblk_calc_secs(pblk, secs_avail, secs_to_flush, true); |
---|
360 | 354 | |
---|
361 | 355 | #ifdef CONFIG_NVM_PBLK_DEBUG |
---|
362 | 356 | if ((!secs_to_sync && secs_to_flush) |
---|
.. | .. |
---|
377 | 371 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; |
---|
378 | 372 | struct pblk_line_meta *lm = &pblk->lm; |
---|
379 | 373 | struct pblk_emeta *emeta = meta_line->emeta; |
---|
| 374 | + struct ppa_addr *ppa_list; |
---|
380 | 375 | struct pblk_g_ctx *m_ctx; |
---|
381 | | - struct bio *bio; |
---|
382 | 376 | struct nvm_rq *rqd; |
---|
383 | 377 | void *data; |
---|
384 | 378 | u64 paddr; |
---|
.. | .. |
---|
396 | 390 | rq_len = rq_ppas * geo->csecs; |
---|
397 | 391 | data = ((void *)emeta->buf) + emeta->mem; |
---|
398 | 392 | |
---|
399 | | - bio = pblk_bio_map_addr(pblk, data, rq_ppas, rq_len, |
---|
400 | | - l_mg->emeta_alloc_type, GFP_KERNEL); |
---|
401 | | - if (IS_ERR(bio)) { |
---|
402 | | - pblk_err(pblk, "failed to map emeta io"); |
---|
403 | | - ret = PTR_ERR(bio); |
---|
404 | | - goto fail_free_rqd; |
---|
405 | | - } |
---|
406 | | - bio->bi_iter.bi_sector = 0; /* internal bio */ |
---|
407 | | - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); |
---|
408 | | - rqd->bio = bio; |
---|
409 | | - |
---|
410 | 393 | ret = pblk_alloc_w_rq(pblk, rqd, rq_ppas, pblk_end_io_write_meta); |
---|
411 | 394 | if (ret) |
---|
412 | | - goto fail_free_bio; |
---|
| 395 | + goto fail_free_rqd; |
---|
413 | 396 | |
---|
| 397 | + ppa_list = nvm_rq_to_ppa_list(rqd); |
---|
414 | 398 | for (i = 0; i < rqd->nr_ppas; ) { |
---|
415 | 399 | spin_lock(&meta_line->lock); |
---|
416 | 400 | paddr = __pblk_alloc_page(pblk, meta_line, rq_ppas); |
---|
417 | 401 | spin_unlock(&meta_line->lock); |
---|
418 | 402 | for (j = 0; j < rq_ppas; j++, i++, paddr++) |
---|
419 | | - rqd->ppa_list[i] = addr_to_gen_ppa(pblk, paddr, id); |
---|
| 403 | + ppa_list[i] = addr_to_gen_ppa(pblk, paddr, id); |
---|
420 | 404 | } |
---|
421 | 405 | |
---|
422 | 406 | spin_lock(&l_mg->close_lock); |
---|
.. | .. |
---|
425 | 409 | list_del(&meta_line->list); |
---|
426 | 410 | spin_unlock(&l_mg->close_lock); |
---|
427 | 411 | |
---|
428 | | - pblk_down_page(pblk, rqd->ppa_list, rqd->nr_ppas); |
---|
| 412 | + pblk_down_chunk(pblk, ppa_list[0]); |
---|
429 | 413 | |
---|
430 | | - ret = pblk_submit_io(pblk, rqd); |
---|
| 414 | + ret = pblk_submit_io(pblk, rqd, data); |
---|
431 | 415 | if (ret) { |
---|
432 | 416 | pblk_err(pblk, "emeta I/O submission failed: %d\n", ret); |
---|
433 | 417 | goto fail_rollback; |
---|
.. | .. |
---|
436 | 420 | return NVM_IO_OK; |
---|
437 | 421 | |
---|
438 | 422 | fail_rollback: |
---|
439 | | - pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas); |
---|
| 423 | + pblk_up_chunk(pblk, ppa_list[0]); |
---|
440 | 424 | spin_lock(&l_mg->close_lock); |
---|
441 | 425 | pblk_dealloc_page(pblk, meta_line, rq_ppas); |
---|
442 | 426 | list_add(&meta_line->list, &meta_line->list); |
---|
443 | 427 | spin_unlock(&l_mg->close_lock); |
---|
444 | | -fail_free_bio: |
---|
445 | | - bio_put(bio); |
---|
446 | 428 | fail_free_rqd: |
---|
447 | 429 | pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT); |
---|
448 | 430 | return ret; |
---|
.. | .. |
---|
527 | 509 | meta_line = pblk_should_submit_meta_io(pblk, rqd); |
---|
528 | 510 | |
---|
529 | 511 | /* Submit data write for current data line */ |
---|
530 | | - err = pblk_submit_io(pblk, rqd); |
---|
| 512 | + err = pblk_submit_io(pblk, rqd, NULL); |
---|
531 | 513 | if (err) { |
---|
532 | 514 | pblk_err(pblk, "data I/O submission failed: %d\n", err); |
---|
533 | 515 | return NVM_IO_ERR; |
---|
.. | .. |
---|
570 | 552 | c_ctx->nr_padded); |
---|
571 | 553 | } |
---|
572 | 554 | |
---|
573 | | -static int pblk_submit_write(struct pblk *pblk) |
---|
| 555 | +static int pblk_submit_write(struct pblk *pblk, int *secs_left) |
---|
574 | 556 | { |
---|
575 | 557 | struct bio *bio; |
---|
576 | 558 | struct nvm_rq *rqd; |
---|
577 | 559 | unsigned int secs_avail, secs_to_sync, secs_to_com; |
---|
578 | | - unsigned int secs_to_flush; |
---|
| 560 | + unsigned int secs_to_flush, packed_meta_pgs; |
---|
579 | 561 | unsigned long pos; |
---|
580 | 562 | unsigned int resubmit; |
---|
| 563 | + |
---|
| 564 | + *secs_left = 0; |
---|
581 | 565 | |
---|
582 | 566 | spin_lock(&pblk->resubmit_lock); |
---|
583 | 567 | resubmit = !list_empty(&pblk->resubmit_list); |
---|
.. | .. |
---|
608 | 592 | */ |
---|
609 | 593 | secs_avail = pblk_rb_read_count(&pblk->rwb); |
---|
610 | 594 | if (!secs_avail) |
---|
611 | | - return 1; |
---|
| 595 | + return 0; |
---|
612 | 596 | |
---|
613 | 597 | secs_to_flush = pblk_rb_flush_point_count(&pblk->rwb); |
---|
614 | | - if (!secs_to_flush && secs_avail < pblk->min_write_pgs) |
---|
615 | | - return 1; |
---|
| 598 | + if (!secs_to_flush && secs_avail < pblk->min_write_pgs_data) |
---|
| 599 | + return 0; |
---|
616 | 600 | |
---|
617 | 601 | secs_to_sync = pblk_calc_secs_to_sync(pblk, secs_avail, |
---|
618 | 602 | secs_to_flush); |
---|
619 | 603 | if (secs_to_sync > pblk->max_write_pgs) { |
---|
620 | 604 | pblk_err(pblk, "bad buffer sync calculation\n"); |
---|
621 | | - return 1; |
---|
| 605 | + return 0; |
---|
622 | 606 | } |
---|
623 | 607 | |
---|
624 | 608 | secs_to_com = (secs_to_sync > secs_avail) ? |
---|
.. | .. |
---|
626 | 610 | pos = pblk_rb_read_commit(&pblk->rwb, secs_to_com); |
---|
627 | 611 | } |
---|
628 | 612 | |
---|
629 | | - bio = bio_alloc(GFP_KERNEL, secs_to_sync); |
---|
| 613 | + packed_meta_pgs = (pblk->min_write_pgs - pblk->min_write_pgs_data); |
---|
| 614 | + bio = bio_alloc(GFP_KERNEL, secs_to_sync + packed_meta_pgs); |
---|
630 | 615 | |
---|
631 | 616 | bio->bi_iter.bi_sector = 0; /* internal bio */ |
---|
632 | 617 | bio_set_op_attrs(bio, REQ_OP_WRITE, 0); |
---|
.. | .. |
---|
647 | 632 | atomic_long_add(secs_to_sync, &pblk->sub_writes); |
---|
648 | 633 | #endif |
---|
649 | 634 | |
---|
| 635 | + *secs_left = 1; |
---|
650 | 636 | return 0; |
---|
651 | 637 | |
---|
652 | 638 | fail_free_bio: |
---|
.. | .. |
---|
655 | 641 | bio_put(bio); |
---|
656 | 642 | pblk_free_rqd(pblk, rqd, PBLK_WRITE); |
---|
657 | 643 | |
---|
658 | | - return 1; |
---|
| 644 | + return -EINTR; |
---|
659 | 645 | } |
---|
660 | 646 | |
---|
661 | 647 | int pblk_write_ts(void *data) |
---|
662 | 648 | { |
---|
663 | 649 | struct pblk *pblk = data; |
---|
| 650 | + int secs_left; |
---|
| 651 | + int write_failure = 0; |
---|
664 | 652 | |
---|
665 | 653 | while (!kthread_should_stop()) { |
---|
666 | | - if (!pblk_submit_write(pblk)) |
---|
667 | | - continue; |
---|
| 654 | + if (!write_failure) { |
---|
| 655 | + write_failure = pblk_submit_write(pblk, &secs_left); |
---|
| 656 | + |
---|
| 657 | + if (secs_left) |
---|
| 658 | + continue; |
---|
| 659 | + } |
---|
668 | 660 | set_current_state(TASK_INTERRUPTIBLE); |
---|
669 | 661 | io_schedule(); |
---|
670 | 662 | } |
---|