Introduce the capability to manage multiple open lines. Maintain one line for user writes (hot) and a second line for gc writes (cold). As user and gc writes still utilize a shared ring buffer, in rare cases a multi-sector write will contain both gc and user data. This is acceptable, as on a tested SSD with minimum write size of 64KB, less than 1% of all writes contain both hot and cold sectors. For a zipfian random distribution of LBA writes with theta-zipf of 1.2, this patch reduces write amplification from 2.5 to 1.3 and increases user write IOPS by 2.1x. Signed-off-by: Heiner Litz <hlitz@xxxxxxxx> --- drivers/lightnvm/pblk-core.c | 157 +++++++++++++++++++++++-------- drivers/lightnvm/pblk-init.c | 9 +- drivers/lightnvm/pblk-map.c | 29 +++--- drivers/lightnvm/pblk-recovery.c | 43 ++++++--- drivers/lightnvm/pblk-write.c | 37 +++++--- drivers/lightnvm/pblk.h | 28 ++++-- 6 files changed, 213 insertions(+), 90 deletions(-) diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c index 73be3a0311ff..bbb216788bc8 100644 --- a/drivers/lightnvm/pblk-core.c +++ b/drivers/lightnvm/pblk-core.c @@ -1294,7 +1294,7 @@ int pblk_line_recov_alloc(struct pblk *pblk, struct pblk_line *line) int ret; spin_lock(&l_mg->free_lock); - l_mg->data_line = line; + pblk_line_set_data_line(pblk, PBLK_LINETYPE_DATA, line); list_del(&line->list); ret = pblk_line_prepare(pblk, line); @@ -1410,7 +1410,7 @@ struct pblk_line *pblk_line_get(struct pblk *pblk) } static struct pblk_line *pblk_line_retry(struct pblk *pblk, - struct pblk_line *line) + struct pblk_line *line, int type) { struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line *retry_line; @@ -1419,7 +1419,7 @@ static struct pblk_line *pblk_line_retry(struct pblk *pblk, spin_lock(&l_mg->free_lock); retry_line = pblk_line_get(pblk); if (!retry_line) { - l_mg->data_line = NULL; + pblk_line_set_data_line(pblk, type, NULL); spin_unlock(&l_mg->free_lock); return NULL; } @@ -1432,7 +1432,7 @@ static struct pblk_line *pblk_line_retry(struct pblk *pblk, pblk_line_reinit(line); - l_mg->data_line = retry_line; + pblk_line_set_data_line(pblk, type, retry_line); spin_unlock(&l_mg->free_lock); pblk_rl_free_lines_dec(&pblk->rl, line, false); @@ -1450,37 +1450,29 @@ static void pblk_set_space_limit(struct pblk *pblk) atomic_set(&rl->rb_space, 0); } -struct pblk_line *pblk_line_get_first_data(struct pblk *pblk) +struct pblk_line *pblk_line_get_first_data(struct pblk *pblk, int type) { struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line *line; spin_lock(&l_mg->free_lock); - line = pblk_line_get(pblk); + line = pblk_line_init_data_line(pblk, type); if (!line) { spin_unlock(&l_mg->free_lock); return NULL; } - line->seq_nr = l_mg->d_seq_nr++; - line->type = PBLK_LINETYPE_DATA; - l_mg->data_line = line; - pblk_line_setup_metadata(line, l_mg, &pblk->lm); /* Allocate next line for preparation */ - l_mg->data_next = pblk_line_get(pblk); - if (!l_mg->data_next) { + if (!pblk_line_init_next_line(pblk, type)) { /* If we cannot get a new line, we need to stop the pipeline. * Only allow as many writes in as we can store safely and then * fail gracefully */ pblk_set_space_limit(pblk); - l_mg->data_next = NULL; - } else { - l_mg->data_next->seq_nr = l_mg->d_seq_nr++; - l_mg->data_next->type = PBLK_LINETYPE_DATA; + pblk_line_set_next_line(pblk, type, NULL); } spin_unlock(&l_mg->free_lock); @@ -1488,14 +1480,14 @@ struct pblk_line *pblk_line_get_first_data(struct pblk *pblk) return NULL; if (pblk_line_erase(pblk, line)) { - line = pblk_line_retry(pblk, line); + line = pblk_line_retry(pblk, line, type); if (!line) return NULL; } retry_setup: if (!pblk_line_init_metadata(pblk, line, NULL)) { - line = pblk_line_retry(pblk, line); + line = pblk_line_retry(pblk, line, type); if (!line) return NULL; @@ -1503,7 +1495,7 @@ struct pblk_line *pblk_line_get_first_data(struct pblk *pblk) } if (!pblk_line_init_bb(pblk, line, 1)) { - line = pblk_line_retry(pblk, line); + line = pblk_line_retry(pblk, line, type); if (!line) return NULL; @@ -1596,12 +1588,18 @@ void __pblk_pipeline_flush(struct pblk *pblk) pblk_flush_writer(pblk); pblk_wait_for_meta(pblk); - ret = pblk_recov_pad(pblk); + ret = pblk_recov_pad(pblk, PBLK_LINETYPE_DATA); if (ret) { pblk_err(pblk, "could not close data on teardown(%d)\n", ret); return; } + ret = pblk_recov_pad(pblk, PBLK_LINETYPE_GC); + if (ret) { + pblk_err(pblk, "could not close gc on teardown(%d)\n", ret); + return; + } + flush_workqueue(pblk->bb_wq); pblk_line_close_meta_sync(pblk); } @@ -1613,8 +1611,10 @@ void __pblk_pipeline_stop(struct pblk *pblk) spin_lock(&l_mg->free_lock); pblk->state = PBLK_STATE_STOPPED; trace_pblk_state(pblk_disk_name(pblk), pblk->state); - l_mg->data_line = NULL; - l_mg->data_next = NULL; + pblk_line_set_data_line(pblk, PBLK_LINETYPE_DATA, NULL); + pblk_line_set_data_line(pblk, PBLK_LINETYPE_GC, NULL); + pblk_line_set_next_line(pblk, PBLK_LINETYPE_DATA, NULL); + pblk_line_set_next_line(pblk, PBLK_LINETYPE_GC, NULL); spin_unlock(&l_mg->free_lock); } @@ -1624,19 +1624,20 @@ void pblk_pipeline_stop(struct pblk *pblk) __pblk_pipeline_stop(pblk); } -struct pblk_line *pblk_line_replace_data(struct pblk *pblk) +struct pblk_line *pblk_line_replace_data(struct pblk *pblk, int type) { struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line *cur, *new = NULL; unsigned int left_seblks; - new = l_mg->data_next; + new = pblk_line_get_next_line(pblk, type); if (!new) goto out; spin_lock(&l_mg->free_lock); - cur = l_mg->data_line; - l_mg->data_line = new; + + cur = pblk_line_get_data_line(pblk, type); + pblk_line_set_data_line(pblk, type, new); pblk_line_setup_metadata(new, l_mg, &pblk->lm); spin_unlock(&l_mg->free_lock); @@ -1659,7 +1660,7 @@ struct pblk_line *pblk_line_replace_data(struct pblk *pblk) retry_setup: if (!pblk_line_init_metadata(pblk, new, cur)) { - new = pblk_line_retry(pblk, new); + new = pblk_line_retry(pblk, new, type); if (!new) goto out; @@ -1667,7 +1668,7 @@ struct pblk_line *pblk_line_replace_data(struct pblk *pblk) } if (!pblk_line_init_bb(pblk, new, 1)) { - new = pblk_line_retry(pblk, new); + new = pblk_line_retry(pblk, new, type); if (!new) goto out; @@ -1678,17 +1679,12 @@ struct pblk_line *pblk_line_replace_data(struct pblk *pblk) /* Allocate next line for preparation */ spin_lock(&l_mg->free_lock); - l_mg->data_next = pblk_line_get(pblk); - if (!l_mg->data_next) { + if (!pblk_line_init_next_line(pblk, type)) { /* If we cannot get a new line, we need to stop the pipeline. * Only allow as many writes in as we can store safely and then * fail gracefully */ pblk_stop_writes(pblk, new); - l_mg->data_next = NULL; - } else { - l_mg->data_next->seq_nr = l_mg->d_seq_nr++; - l_mg->data_next->type = PBLK_LINETYPE_DATA; } spin_unlock(&l_mg->free_lock); @@ -1801,15 +1797,100 @@ int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr ppa) return err; } -struct pblk_line *pblk_line_get_data(struct pblk *pblk) +struct pblk_line *pblk_line_get_data_line(struct pblk *pblk, int type) { - return pblk->l_mg.data_line; + switch (type) { + case PBLK_LINETYPE_DATA: + return pblk->l_mg.data_line; + case PBLK_LINETYPE_GC: + return pblk->l_mg.gc_line; + case PBLK_LINETYPE_LOG: + return pblk->l_mg.log_line; + default: + WARN(1, "Unsupported line type\n"); + return NULL; + } } /* For now, always erase next line */ -struct pblk_line *pblk_line_get_erase(struct pblk *pblk) +struct pblk_line *pblk_line_get_next_line(struct pblk *pblk, int type) { - return pblk->l_mg.data_next; + switch (type) { + case PBLK_LINETYPE_DATA: + return pblk->l_mg.data_next; + case PBLK_LINETYPE_GC: + return pblk->l_mg.gc_next; + case PBLK_LINETYPE_LOG: + return pblk->l_mg.log_next; + default: + WARN(1, "Unsupported line type\n"); + return NULL; + } +} + +void pblk_line_set_data_line(struct pblk *pblk, int type, struct pblk_line *line) +{ + switch (type) { + case PBLK_LINETYPE_DATA: + pblk->l_mg.data_line = line; + break; + case PBLK_LINETYPE_GC: + pblk->l_mg.gc_line = line; + break; + case PBLK_LINETYPE_LOG: + pblk->l_mg.log_line = line; + break; + default: + WARN(1, "Unsupported line type\n"); + } +} + +/* For now, always erase next line */ +void pblk_line_set_next_line(struct pblk *pblk, int type, struct pblk_line *line) +{ + switch (type) { + case PBLK_LINETYPE_DATA: + pblk->l_mg.data_next = line; + break; + case PBLK_LINETYPE_GC: + pblk->l_mg.gc_next = line; + break; + case PBLK_LINETYPE_LOG: + pblk->l_mg.log_next = line; + break; + default: + WARN(1, "Unsupported line type\n"); + } +} + +struct pblk_line *pblk_line_init_data_line(struct pblk *pblk, int type) +{ + struct pblk_line *line = pblk_line_get(pblk); + struct pblk_line_mgmt *l_mg = &pblk->l_mg; + + lockdep_assert_held(&l_mg->free_lock); + + if (line) { + line->seq_nr = l_mg->d_seq_nr++; + line->type = type; + pblk_line_set_data_line(pblk, type, line); + } + return line; +} + +struct pblk_line *pblk_line_init_next_line(struct pblk *pblk, int type) +{ + struct pblk_line *line = pblk_line_get(pblk); + struct pblk_line_mgmt *l_mg = &pblk->l_mg; + + lockdep_assert_held(&l_mg->free_lock); + + if (line) { + line->seq_nr = l_mg->d_seq_nr++; + line->type = type; + pblk_line_set_next_line(pblk, type, line); + } + return line; } int pblk_line_is_full(struct pblk_line *line) diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c index 1e227a08e54a..0d127e32d556 100644 --- a/drivers/lightnvm/pblk-init.c +++ b/drivers/lightnvm/pblk-init.c @@ -139,11 +139,16 @@ static int pblk_l2p_recover(struct pblk *pblk, bool factory_init) if (!line) { /* Configure next line for user data */ - line = pblk_line_get_first_data(pblk); + line = pblk_line_get_first_data(pblk, PBLK_LINETYPE_DATA); if (!line) return -EFAULT; } + /* Configure next line for gc data */ + line = pblk_line_get_first_data(pblk, PBLK_LINETYPE_GC); + if (!line) + return -EFAULT; + return 0; } @@ -832,7 +837,7 @@ static int pblk_line_mg_init(struct pblk *pblk) int i, bb_distance; l_mg->nr_lines = geo->num_chk; - l_mg->log_line = l_mg->data_line = NULL; + l_mg->log_line = l_mg->data_line = l_mg->gc_line = NULL; l_mg->l_seq_nr = l_mg->d_seq_nr = 0; l_mg->nr_free_lines = 0; bitmap_zero(&l_mg->meta_bitmap, PBLK_DATA_LINES); diff --git a/drivers/lightnvm/pblk-map.c b/drivers/lightnvm/pblk-map.c index 5408e32b2f13..9b0539137df0 100644 --- a/drivers/lightnvm/pblk-map.c +++ b/drivers/lightnvm/pblk-map.c @@ -23,9 +23,9 @@ static int pblk_map_page_data(struct pblk *pblk, unsigned int sentry, struct ppa_addr *ppa_list, unsigned long *lun_bitmap, void *meta_list, - unsigned int valid_secs) + unsigned int valid_secs, int type) { - struct pblk_line *line = pblk_line_get_data(pblk); + struct pblk_line *line = pblk_line_get_data_line(pblk, type); struct pblk_emeta *emeta; struct pblk_w_ctx *w_ctx; __le64 *lba_list; @@ -42,7 +42,7 @@ static int pblk_map_page_data(struct pblk *pblk, unsigned int sentry, /* If we cannot allocate a new line, make sure to store metadata * on current line and then fail */ - line = pblk_line_replace_data(pblk); + line = pblk_line_replace_data(pblk, type); pblk_line_close_meta(pblk, prev_line); if (!line) { @@ -94,8 +94,8 @@ static int pblk_map_page_data(struct pblk *pblk, unsigned int sentry, } int pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry, - unsigned long *lun_bitmap, unsigned int valid_secs, - unsigned int off) + unsigned long *lun_bitmap, unsigned int valid_secs, + unsigned int off, int type) { void *meta_list = pblk_get_meta_for_writes(pblk, rqd); void *meta_buffer; @@ -110,7 +110,7 @@ int pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry, meta_buffer = pblk_get_meta(pblk, meta_list, i); ret = pblk_map_page_data(pblk, sentry + i, &ppa_list[i], - lun_bitmap, meta_buffer, map_secs); + lun_bitmap, meta_buffer, map_secs, type); if (ret) return ret; } @@ -120,8 +120,9 @@ int pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry, /* only if erase_ppa is set, acquire erase semaphore */ int pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd, - unsigned int sentry, unsigned long *lun_bitmap, - unsigned int valid_secs, struct ppa_addr *erase_ppa) + unsigned int sentry, unsigned long *lun_bitmap, + unsigned int valid_secs, struct ppa_addr *erase_ppa, + int type) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; @@ -141,7 +142,7 @@ int pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd, meta_buffer = pblk_get_meta(pblk, meta_list, i); ret = pblk_map_page_data(pblk, sentry + i, &ppa_list[i], - lun_bitmap, meta_buffer, map_secs); + lun_bitmap, meta_buffer, map_secs, type); if (ret) return ret; @@ -150,10 +151,10 @@ int pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd, /* line can change after page map. We might also be writing the * last line. */ - e_line = pblk_line_get_erase(pblk); + e_line = pblk_line_get_next_line(pblk, type); if (!e_line) return pblk_map_rq(pblk, rqd, sentry, lun_bitmap, - valid_secs, i + min); + valid_secs, i + min, type); spin_lock(&e_line->lock); if (!test_bit(erase_lun, e_line->erase_bitmap)) { @@ -168,17 +169,17 @@ int pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd, /* Avoid evaluating e_line->left_eblks */ return pblk_map_rq(pblk, rqd, sentry, lun_bitmap, - valid_secs, i + min); + valid_secs, i + min, type); } spin_unlock(&e_line->lock); } - d_line = pblk_line_get_data(pblk); + d_line = pblk_line_get_data_line(pblk, type); /* line can change after page map. We might also be writing the * last line. */ - e_line = pblk_line_get_erase(pblk); + e_line = pblk_line_get_next_line(pblk, type); if (!e_line) return -ENOSPC; diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c index 865fe310cab4..38bf7b28e73f 100644 --- a/drivers/lightnvm/pblk-recovery.c +++ b/drivers/lightnvm/pblk-recovery.c @@ -677,12 +677,12 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk) { struct pblk_line_meta *lm = &pblk->lm; struct pblk_line_mgmt *l_mg = &pblk->l_mg; - struct pblk_line *line, *tline, *data_line = NULL; + struct pblk_line *line, *tline, *data_line = NULL, *gc_line = NULL; struct pblk_smeta *smeta; struct pblk_emeta *emeta; struct line_smeta *smeta_buf; int found_lines = 0, recovered_lines = 0, open_lines = 0; - int is_next = 0; + int is_data_next = 0, is_gc_next = 0; int meta_line; int i, valid_uuid = 0; LIST_HEAD(recov_list); @@ -838,7 +838,11 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk) trace_pblk_line_state(pblk_disk_name(pblk), line->id, line->state); - data_line = line; + if (line->type == PBLK_LINETYPE_DATA) + data_line = line; + else if (line->type == PBLK_LINETYPE_GC) + gc_line = line; + line->meta_line = meta_line; open_lines++; @@ -852,19 +856,30 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk) spin_unlock(&l_mg->free_lock); } else { spin_lock(&l_mg->free_lock); - l_mg->data_line = data_line; - /* Allocate next line for preparation */ - l_mg->data_next = pblk_line_get(pblk); - if (l_mg->data_next) { - l_mg->data_next->seq_nr = l_mg->d_seq_nr++; - l_mg->data_next->type = PBLK_LINETYPE_DATA; - is_next = 1; + if (data_line) { + pblk_line_set_data_line(pblk, PBLK_LINETYPE_DATA, + data_line); + /* Allocate next line for preparation */ + if (pblk_line_init_next_line(pblk, PBLK_LINETYPE_DATA)) + is_data_next = 1; + } + if (gc_line) { + pblk_line_set_data_line(pblk, PBLK_LINETYPE_GC, + gc_line); + /* Allocate next line for preparation */ + if (pblk_line_init_next_line(pblk, PBLK_LINETYPE_GC)) + is_gc_next = 1; } + spin_unlock(&l_mg->free_lock); } - if (is_next) - pblk_line_erase(pblk, l_mg->data_next); + if (is_data_next) + pblk_line_erase(pblk, pblk_line_get_next_line(pblk, + PBLK_LINETYPE_DATA)); + if (is_gc_next) + pblk_line_erase(pblk, pblk_line_get_next_line(pblk, + PBLK_LINETYPE_GC)); out: if (found_lines != recovered_lines) @@ -877,7 +892,7 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk) /* * Pad current line */ -int pblk_recov_pad(struct pblk *pblk) +int pblk_recov_pad(struct pblk *pblk, int type) { struct pblk_line *line; struct pblk_line_mgmt *l_mg = &pblk->l_mg; @@ -885,7 +900,7 @@ int pblk_recov_pad(struct pblk *pblk) int ret = 0; spin_lock(&l_mg->free_lock); - line = l_mg->data_line; + line = pblk_line_get_data_line(pblk, type); left_msecs = line->left_msecs; spin_unlock(&l_mg->free_lock); diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c index 4e63f9b5954c..1e38adc63800 100644 --- a/drivers/lightnvm/pblk-write.c +++ b/drivers/lightnvm/pblk-write.c @@ -313,10 +313,10 @@ static int pblk_alloc_w_rq(struct pblk *pblk, struct nvm_rq *rqd, } static int pblk_setup_w_rq(struct pblk *pblk, struct nvm_rq *rqd, - struct ppa_addr *erase_ppa) + struct ppa_addr *erase_ppa, int type) { struct pblk_line_meta *lm = &pblk->lm; - struct pblk_line *e_line = pblk_line_get_erase(pblk); + struct pblk_line *e_line = pblk_line_get_next_line(pblk, type); struct pblk_c_ctx *c_ctx = nvm_rq_to_pdu(rqd); unsigned int valid = c_ctx->nr_valid; unsigned int padded = c_ctx->nr_padded; @@ -337,10 +337,10 @@ static int pblk_setup_w_rq(struct pblk *pblk, struct nvm_rq *rqd, if (likely(!e_line || !atomic_read(&e_line->left_eblks))) ret = pblk_map_rq(pblk, rqd, c_ctx->sentry, lun_bitmap, - valid, 0); + valid, 0, type); else ret = pblk_map_erase_rq(pblk, rqd, c_ctx->sentry, lun_bitmap, - valid, erase_ppa); + valid, erase_ppa, type); return ret; } @@ -446,12 +446,13 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) static inline bool pblk_valid_meta_ppa(struct pblk *pblk, struct pblk_line *meta_line, - struct nvm_rq *data_rqd) + struct nvm_rq *data_rqd, + int type) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; struct pblk_c_ctx *data_c_ctx = nvm_rq_to_pdu(data_rqd); - struct pblk_line *data_line = pblk_line_get_data(pblk); + struct pblk_line *data_line = pblk_line_get_data_line(pblk, type); struct ppa_addr ppa, ppa_opt; u64 paddr; int pos_opt; @@ -481,7 +482,8 @@ static inline bool pblk_valid_meta_ppa(struct pblk *pblk, } static struct pblk_line *pblk_should_submit_meta_io(struct pblk *pblk, - struct nvm_rq *data_rqd) + struct nvm_rq *data_rqd, + int type) { struct pblk_line_meta *lm = &pblk->lm; struct pblk_line_mgmt *l_mg = &pblk->l_mg; @@ -499,13 +501,13 @@ static struct pblk_line *pblk_should_submit_meta_io(struct pblk *pblk, } spin_unlock(&l_mg->close_lock); - if (!pblk_valid_meta_ppa(pblk, meta_line, data_rqd)) + if (!pblk_valid_meta_ppa(pblk, meta_line, data_rqd, type)) return NULL; return meta_line; } -static int pblk_submit_io_set(struct pblk *pblk, struct nvm_rq *rqd) +static int pblk_submit_io_set(struct pblk *pblk, struct nvm_rq *rqd, int type) { struct ppa_addr erase_ppa; struct pblk_line *meta_line; @@ -514,13 +516,13 @@ static int pblk_submit_io_set(struct pblk *pblk, struct nvm_rq *rqd) pblk_ppa_set_empty(&erase_ppa); /* Assign lbas to ppas and populate request structure */ - err = pblk_setup_w_rq(pblk, rqd, &erase_ppa); + err = pblk_setup_w_rq(pblk, rqd, &erase_ppa, type); if (err) { pblk_err(pblk, "could not setup write request: %d\n", err); return NVM_IO_ERR; } - meta_line = pblk_should_submit_meta_io(pblk, rqd); + meta_line = pblk_should_submit_meta_io(pblk, rqd, type); /* Submit data write for current data line */ err = pblk_submit_io(pblk, rqd); @@ -532,11 +534,12 @@ static int pblk_submit_io_set(struct pblk *pblk, struct nvm_rq *rqd) if (!pblk_ppa_empty(erase_ppa)) { /* Submit erase for next data line */ if (pblk_blk_erase_async(pblk, erase_ppa)) { - struct pblk_line *e_line = pblk_line_get_erase(pblk); + struct pblk_line *e_line; struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; int bit; + e_line = pblk_line_get_next_line(pblk, type); atomic_inc(&e_line->left_eblks); bit = pblk_ppa_to_pos(geo, erase_ppa); WARN_ON(!test_and_clear_bit(bit, e_line->erase_bitmap)); @@ -574,6 +577,9 @@ static int pblk_submit_write(struct pblk *pblk, int *secs_left) unsigned int secs_to_flush, packed_meta_pgs; unsigned long pos; unsigned int resubmit; + int type; + struct pblk_w_ctx *w_ctx; + struct pblk_rb_entry *entry; *secs_left = 0; @@ -633,13 +639,18 @@ static int pblk_submit_write(struct pblk *pblk, int *secs_left) rqd = pblk_alloc_rqd(pblk, PBLK_WRITE); rqd->bio = bio; + entry = &pblk->rwb.entries[pos]; + w_ctx = &entry->w_ctx; + type = w_ctx->flags & PBLK_IOTYPE_GC ? + PBLK_LINETYPE_GC : PBLK_LINETYPE_DATA; + if (pblk_rb_read_to_bio(&pblk->rwb, rqd, pos, secs_to_sync, secs_avail)) { pblk_err(pblk, "corrupted write bio\n"); goto fail_put_bio; } - if (pblk_submit_io_set(pblk, rqd)) + if (pblk_submit_io_set(pblk, rqd, type)) goto fail_free_bio; #ifdef CONFIG_NVM_PBLK_DEBUG diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h index e304754aaa3c..93ef5a2bffe6 100644 --- a/drivers/lightnvm/pblk.h +++ b/drivers/lightnvm/pblk.h @@ -316,6 +316,7 @@ enum { PBLK_LINETYPE_FREE = 0, PBLK_LINETYPE_LOG = 1, PBLK_LINETYPE_DATA = 2, + PBLK_LINETYPE_GC = 3, /* Line state */ PBLK_LINESTATE_NEW = 9, @@ -526,8 +527,10 @@ struct pblk_line_mgmt { struct pblk_line *log_line; /* Current FTL log line */ struct pblk_line *data_line; /* Current data line */ + struct pblk_line *gc_line; /* Current gc line */ struct pblk_line *log_next; /* Next FTL log line */ struct pblk_line *data_next; /* Next data line */ + struct pblk_line *gc_next; /* Next gc line */ struct list_head emeta_list; /* Lines queued to schedule emeta */ @@ -804,14 +807,20 @@ struct bio *pblk_bio_map_addr(struct pblk *pblk, void *data, unsigned int nr_secs, unsigned int len, int alloc_type, gfp_t gfp_mask); struct pblk_line *pblk_line_get(struct pblk *pblk); -struct pblk_line *pblk_line_get_first_data(struct pblk *pblk); -struct pblk_line *pblk_line_replace_data(struct pblk *pblk); +struct pblk_line *pblk_line_get_first_data(struct pblk *pblk, int type); +struct pblk_line *pblk_line_replace_data(struct pblk *pblk, int type); void pblk_ppa_to_line_put(struct pblk *pblk, struct ppa_addr ppa); void pblk_rq_to_line_put(struct pblk *pblk, struct nvm_rq *rqd); int pblk_line_recov_alloc(struct pblk *pblk, struct pblk_line *line); void pblk_line_recov_close(struct pblk *pblk, struct pblk_line *line); -struct pblk_line *pblk_line_get_data(struct pblk *pblk); -struct pblk_line *pblk_line_get_erase(struct pblk *pblk); +struct pblk_line *pblk_line_get_data_line(struct pblk *pblk, int type); +struct pblk_line *pblk_line_get_next_line(struct pblk *pblk, int type); +void pblk_line_set_data_line(struct pblk *pblk, int type, + struct pblk_line *line); +void pblk_line_set_next_line(struct pblk *pblk, int type, + struct pblk_line *line); +struct pblk_line *pblk_line_init_next_line(struct pblk *pblk, int type); +struct pblk_line *pblk_line_init_data_line(struct pblk *pblk, int type); int pblk_line_erase(struct pblk *pblk, struct pblk_line *line); int pblk_line_is_full(struct pblk_line *line); void pblk_line_free(struct pblk_line *line); @@ -875,11 +884,12 @@ int pblk_write_gc_to_cache(struct pblk *pblk, struct pblk_gc_rq *gc_rq); * pblk map */ int pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd, - unsigned int sentry, unsigned long *lun_bitmap, - unsigned int valid_secs, struct ppa_addr *erase_ppa); + unsigned int sentry, unsigned long *lun_bitmap, + unsigned int valid_secs, struct ppa_addr *erase_ppa, + int type); int pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry, - unsigned long *lun_bitmap, unsigned int valid_secs, - unsigned int off); + unsigned long *lun_bitmap, unsigned int valid_secs, + unsigned int off, int type); /* * pblk write thread @@ -899,7 +909,7 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq); * pblk recovery */ struct pblk_line *pblk_recov_l2p(struct pblk *pblk); -int pblk_recov_pad(struct pblk *pblk); +int pblk_recov_pad(struct pblk *pblk, int type); int pblk_recov_check_emeta(struct pblk *pblk, struct line_emeta *emeta); /* -- 2.17.1