Received: by 2002:a25:4158:0:0:0:0:0 with SMTP id o85csp412180yba; Fri, 26 Apr 2019 02:12:32 -0700 (PDT) X-Google-Smtp-Source: APXvYqy+7sk1T4p/rXEVOLQujFy5O27aEdyDifdR954pta+qc4DADTBLWajzJuE1iDrqi5iwKl3C X-Received: by 2002:a65:6546:: with SMTP id a6mr6999871pgw.5.1556269952192; Fri, 26 Apr 2019 02:12:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1556269952; cv=none; d=google.com; s=arc-20160816; b=WoYRkWPcwyKZiXf1K/DbgynmW6XxjVri+CT/T4HwRQkCdyWJPdKVZLZFAA/rHL3sJj THtQiMU4FpEwfOXI9jlkAMi/VE0Aq/mluI9/V9okX0qCaujOBYUhgy7IQsPIAodlkJ96 5EGmSG4qpgJ15XJC66kUG/lifrVdbrFrs4ywC5qGr8m+W/bW6sW1iKLt0FxaXLFw0a3q wN+eJEqFZmuImV5zpiChfprdYeNp1ipELfHQB6QLOtU6SVmkYOTwWyzyf38PZMBgtnl+ fIY/+pkktrRKYV0hequu3Zdend1Lz4uh7Es7UpRf0dpH73eyzu/rdzZTFGgLvBZKxj8a yQTQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject; bh=ycg0+h4mo+qh7lmvUkdZeBxyUIM1q2sek3/jKS20cSE=; b=R3plLRDmVzCh/daUqatRQCol2BwXvHm/EjZM+HnbnRT23fozfnbU1bYTl55QW2SfIk OW9c2mmyXf0swo4kt/VaIJ4bH3k2coX+G1JAJrVq5KnjZ2K1RxT7kWfriIMDmWfu/CKo iW3VQMCHC4oQiBzVHIVAp+Ngqgq5wJiz8Bb3HXaMotN+uvN1V07aAbOs9g1ziWxhwsPy r1of2JO8iDoZL8IfisiLpcex3A0Ywss6re7NfjLW1vsgbAkVJtPm01P3MqwH5ykxXkDv RalUX5ZDkRu+fBRdfhRiCtDYW04ytBbArT0ngZIv+Hzy6HnCllFyg2OYWRPz3VvWiGhI EXVg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w21si24566798pgj.513.2019.04.26.02.12.16; Fri, 26 Apr 2019 02:12:32 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726120AbfDZJLH (ORCPT + 99 others); Fri, 26 Apr 2019 05:11:07 -0400 Received: from mga11.intel.com ([192.55.52.93]:17994 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725881AbfDZJLG (ORCPT ); Fri, 26 Apr 2019 05:11:06 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Apr 2019 02:11:04 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,397,1549958400"; d="scan'208";a="319152851" Received: from ikonopko-mobl.ger.corp.intel.com (HELO [10.237.142.109]) ([10.237.142.109]) by orsmga005.jf.intel.com with ESMTP; 26 Apr 2019 02:11:02 -0700 Subject: Re: [PATCH] lightnvm: pblk: Introduce hot-cold data separation To: Heiner Litz , mb@lightnvm.io Cc: javier@javigon.com, hans.holmberg@cnexlabs.com, linux-block@vger.kernel.org, linux-kernel@vger.kernel.org References: <20190425052152.6571-1-hlitz@ucsc.edu> From: Igor Konopko Message-ID: <66434cc7-2bac-dd10-6edc-4560e6a0f89f@intel.com> Date: Fri, 26 Apr 2019 11:11:01 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 In-Reply-To: <20190425052152.6571-1-hlitz@ucsc.edu> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 > --- > 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); > > /* >