[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <66434cc7-2bac-dd10-6edc-4560e6a0f89f@intel.com>
Date: Fri, 26 Apr 2019 11:11:01 +0200
From: Igor Konopko <igor.j.konopko@...el.com>
To: Heiner Litz <hlitz@...c.edu>, mb@...htnvm.io
Cc: javier@...igon.com, hans.holmberg@...xlabs.com,
linux-block@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH] lightnvm: pblk: Introduce hot-cold data separation
On 25.04.2019 07:21, Heiner Litz wrote:
> 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.
>
Hi Heiner
Generally I really like this changes, I was thinking about sth similar
since a while, so it is very good to see that patch.
I have a one question related to this patch, since it is not very clear
for me - how you ensure the data integrity in following scenarios:
-we have open line X for user data and line Y for GC
-GC writes LBA=N to line Y
-user writes LBA=N to line X
-we have power failure when both line X and Y were not written completely
-during pblk creation we are executing OOB metadata recovery
And here is the question, how we distinguish whether LBA=N from line Y
or LBA=N from line X is the valid one?
Line X and Y might have seq_id either descending or ascending - this
would create two possible scenarios too.
Thanks
Igor
> 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@...c.edu>
> ---
> 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);
>
> /*
>
Powered by blists - more mailing lists