linux-block.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 0/3] lightnvm: next set of improvements for 5.2
@ 2019-04-26 13:35 Igor Konopko
  2019-04-26 13:35 ` [PATCH v5 1/3] lightnvm: pblk: simplify partial read path Igor Konopko
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Igor Konopko @ 2019-04-26 13:35 UTC (permalink / raw)
  To: mb, javier, hans.holmberg; +Cc: linux-block, igor.j.konopko

This is another set of fixes and improvements to both pblk and lightnvm
core. 

Changes v4 -> v5:
-dropped patches which were already pulled into for-5.2/core branch
-rebasing of other patches
-multiple copies of smeta patch moved into last position in series
so it would be easier to pull only previous patches if needed

Changes v3 -> v4:
-dropped patches which were already pulled into for-5.2/core branch
-major changes for patch #2 based on code review
-patch #6 modified to use krefs
-new patch #7 which extends the patch #6

Changes v2 -> v3:
-dropped some not needed patches
-dropped patches which were already pulled into for-5.2/core branch
-commit messages cleanup

Changes v1 -> v2:
-dropped some not needed patches
-review feedback incorporated for some of the patches
-partial read path changes patch splited into two patches


Igor Konopko (3):
  lightnvm: pblk: simplify partial read path
  lightnvm: pblk: use nvm_rq_to_ppa_list()
  lightnvm: pblk: store multiple copies of smeta

 drivers/lightnvm/pblk-core.c     | 159 ++++++++++++++----
 drivers/lightnvm/pblk-init.c     |  23 ++-
 drivers/lightnvm/pblk-rb.c       |  11 +-
 drivers/lightnvm/pblk-read.c     | 339 ++++++++++-----------------------------
 drivers/lightnvm/pblk-recovery.c |  27 ++--
 drivers/lightnvm/pblk-rl.c       |   3 +-
 drivers/lightnvm/pblk.h          |  19 +--
 7 files changed, 252 insertions(+), 329 deletions(-)

-- 
2.9.5


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v5 1/3] lightnvm: pblk: simplify partial read path
  2019-04-26 13:35 [PATCH v5 0/3] lightnvm: next set of improvements for 5.2 Igor Konopko
@ 2019-04-26 13:35 ` Igor Konopko
  2019-04-26 16:30   ` Heiner Litz
  2019-05-01  6:20   ` Javier González
  2019-04-26 13:35 ` [PATCH v5 2/3] lightnvm: pblk: use nvm_rq_to_ppa_list() Igor Konopko
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 9+ messages in thread
From: Igor Konopko @ 2019-04-26 13:35 UTC (permalink / raw)
  To: mb, javier, hans.holmberg; +Cc: linux-block, igor.j.konopko

This patch changes the approach to handling partial read path.

In old approach merging of data from round buffer and drive was fully
made by drive. This had some disadvantages - code was complex and
relies on bio internals, so it was hard to maintain and was strongly
dependent on bio changes.

In new approach most of the handling is done mostly by block layer
functions such as bio_split(), bio_chain() and generic_make request()
and generally is less complex and easier to maintain. Below some more
details of the new approach.

When read bio arrives, it is cloned for pblk internal purposes. All
the L2P mapping, which includes copying data from round buffer to bio
and thus bio_advance() calls is done on the cloned bio, so the original
bio is untouched. If we found that we have partial read case, we
still have original bio untouched, so we can split it and continue to
process only first part of it in current context, when the rest will be
called as separate bio request which is passed to generic_make_request()
for further processing.

Signed-off-by: Igor Konopko <igor.j.konopko@intel.com>
---
 drivers/lightnvm/pblk-core.c |  13 +-
 drivers/lightnvm/pblk-rb.c   |  11 +-
 drivers/lightnvm/pblk-read.c | 339 +++++++++++--------------------------------
 drivers/lightnvm/pblk.h      |  18 +--
 4 files changed, 100 insertions(+), 281 deletions(-)

diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 73be3a0..07270ba 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -2147,8 +2147,8 @@ void pblk_update_map_dev(struct pblk *pblk, sector_t lba,
 	spin_unlock(&pblk->trans_lock);
 }
 
-void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
-			 sector_t blba, int nr_secs)
+int pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
+			 sector_t blba, int nr_secs, bool *from_cache)
 {
 	int i;
 
@@ -2162,10 +2162,19 @@ void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
 		if (!pblk_ppa_empty(ppa) && !pblk_addr_in_cache(ppa)) {
 			struct pblk_line *line = pblk_ppa_to_line(pblk, ppa);
 
+			if (i > 0 && *from_cache)
+				break;
+			*from_cache = false;
+
 			kref_get(&line->ref);
+		} else {
+			if (i > 0 && !*from_cache)
+				break;
+			*from_cache = true;
 		}
 	}
 	spin_unlock(&pblk->trans_lock);
+	return i;
 }
 
 void pblk_lookup_l2p_rand(struct pblk *pblk, struct ppa_addr *ppas,
diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c
index 3555014..5abb170 100644
--- a/drivers/lightnvm/pblk-rb.c
+++ b/drivers/lightnvm/pblk-rb.c
@@ -642,7 +642,7 @@ unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct nvm_rq *rqd,
  * be directed to disk.
  */
 int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
-			struct ppa_addr ppa, int bio_iter, bool advanced_bio)
+			struct ppa_addr ppa)
 {
 	struct pblk *pblk = container_of(rb, struct pblk, rwb);
 	struct pblk_rb_entry *entry;
@@ -673,15 +673,6 @@ int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
 		ret = 0;
 		goto out;
 	}
-
-	/* Only advance the bio if it hasn't been advanced already. If advanced,
-	 * this bio is at least a partial bio (i.e., it has partially been
-	 * filled with data from the cache). If part of the data resides on the
-	 * media, we will read later on
-	 */
-	if (unlikely(!advanced_bio))
-		bio_advance(bio, bio_iter * PBLK_EXPOSED_PAGE_SIZE);
-
 	data = bio_data(bio);
 	memcpy(data, entry->data, rb->seg_size);
 
diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c
index f5f155d..d98ea39 100644
--- a/drivers/lightnvm/pblk-read.c
+++ b/drivers/lightnvm/pblk-read.c
@@ -26,8 +26,7 @@
  * issued.
  */
 static int pblk_read_from_cache(struct pblk *pblk, struct bio *bio,
-				sector_t lba, struct ppa_addr ppa,
-				int bio_iter, bool advanced_bio)
+				sector_t lba, struct ppa_addr ppa)
 {
 #ifdef CONFIG_NVM_PBLK_DEBUG
 	/* Callers must ensure that the ppa points to a cache address */
@@ -35,73 +34,75 @@ static int pblk_read_from_cache(struct pblk *pblk, struct bio *bio,
 	BUG_ON(!pblk_addr_in_cache(ppa));
 #endif
 
-	return pblk_rb_copy_to_bio(&pblk->rwb, bio, lba, ppa,
-						bio_iter, advanced_bio);
+	return pblk_rb_copy_to_bio(&pblk->rwb, bio, lba, ppa);
 }
 
-static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
+static int pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
 				 struct bio *bio, sector_t blba,
-				 unsigned long *read_bitmap)
+				 bool *from_cache)
 {
 	void *meta_list = rqd->meta_list;
-	struct ppa_addr ppas[NVM_MAX_VLBA];
-	int nr_secs = rqd->nr_ppas;
-	bool advanced_bio = false;
-	int i, j = 0;
+	int nr_secs, i;
 
-	pblk_lookup_l2p_seq(pblk, ppas, blba, nr_secs);
+retry:
+	nr_secs = pblk_lookup_l2p_seq(pblk, rqd->ppa_list, blba, rqd->nr_ppas,
+					from_cache);
+
+	if (!*from_cache)
+		goto end;
 
 	for (i = 0; i < nr_secs; i++) {
-		struct ppa_addr p = ppas[i];
 		struct pblk_sec_meta *meta = pblk_get_meta(pblk, meta_list, i);
 		sector_t lba = blba + i;
 
-retry:
-		if (pblk_ppa_empty(p)) {
+		if (pblk_ppa_empty(rqd->ppa_list[i])) {
 			__le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
 
-			WARN_ON(test_and_set_bit(i, read_bitmap));
 			meta->lba = addr_empty;
-
-			if (unlikely(!advanced_bio)) {
-				bio_advance(bio, (i) * PBLK_EXPOSED_PAGE_SIZE);
-				advanced_bio = true;
+		} else if (pblk_addr_in_cache(rqd->ppa_list[i])) {
+			/*
+			 * Try to read from write buffer. The address is later
+			 * checked on the write buffer to prevent retrieving
+			 * overwritten data.
+			 */
+			if (!pblk_read_from_cache(pblk, bio, lba,
+							rqd->ppa_list[i])) {
+				if (i == 0) {
+					/*
+					 * We didn't call with bio_advance()
+					 * yet, so we can just retry.
+					 */
+					goto retry;
+				} else {
+					/*
+					 * We already call bio_advance()
+					 * so we cannot retry and we need
+					 * to quit that function in order
+					 * to allow caller to handle the bio
+					 * splitting in the current sector
+					 * position.
+					 */
+					nr_secs = i;
+					goto end;
+				}
 			}
-
-			goto next;
-		}
-
-		/* Try to read from write buffer. The address is later checked
-		 * on the write buffer to prevent retrieving overwritten data.
-		 */
-		if (pblk_addr_in_cache(p)) {
-			if (!pblk_read_from_cache(pblk, bio, lba, p, i,
-								advanced_bio)) {
-				pblk_lookup_l2p_seq(pblk, &p, lba, 1);
-				goto retry;
-			}
-			WARN_ON(test_and_set_bit(i, read_bitmap));
 			meta->lba = cpu_to_le64(lba);
-			advanced_bio = true;
 #ifdef CONFIG_NVM_PBLK_DEBUG
 			atomic_long_inc(&pblk->cache_reads);
 #endif
-		} else {
-			/* Read from media non-cached sectors */
-			rqd->ppa_list[j++] = p;
 		}
-
-next:
-		if (advanced_bio)
-			bio_advance(bio, PBLK_EXPOSED_PAGE_SIZE);
+		bio_advance(bio, PBLK_EXPOSED_PAGE_SIZE);
 	}
 
+end:
 	if (pblk_io_aligned(pblk, nr_secs))
 		rqd->is_seq = 1;
 
 #ifdef CONFIG_NVM_PBLK_DEBUG
 	atomic_long_add(nr_secs, &pblk->inflight_reads);
 #endif
+
+	return nr_secs;
 }
 
 
@@ -197,9 +198,7 @@ static void __pblk_end_io_read(struct pblk *pblk, struct nvm_rq *rqd,
 		pblk_log_read_err(pblk, rqd);
 
 	pblk_read_check_seq(pblk, rqd, r_ctx->lba);
-
-	if (int_bio)
-		bio_put(int_bio);
+	bio_put(int_bio);
 
 	if (put_line)
 		pblk_rq_to_line_put(pblk, rqd);
@@ -223,183 +222,13 @@ static void pblk_end_io_read(struct nvm_rq *rqd)
 	__pblk_end_io_read(pblk, rqd, true);
 }
 
-static void pblk_end_partial_read(struct nvm_rq *rqd)
-{
-	struct pblk *pblk = rqd->private;
-	struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd);
-	struct pblk_pr_ctx *pr_ctx = r_ctx->private;
-	struct pblk_sec_meta *meta;
-	struct bio *new_bio = rqd->bio;
-	struct bio *bio = pr_ctx->orig_bio;
-	void *meta_list = rqd->meta_list;
-	unsigned long *read_bitmap = pr_ctx->bitmap;
-	struct bvec_iter orig_iter = BVEC_ITER_ALL_INIT;
-	struct bvec_iter new_iter = BVEC_ITER_ALL_INIT;
-	int nr_secs = pr_ctx->orig_nr_secs;
-	int nr_holes = nr_secs - bitmap_weight(read_bitmap, nr_secs);
-	void *src_p, *dst_p;
-	int bit, i;
-
-	if (unlikely(nr_holes == 1)) {
-		struct ppa_addr ppa;
-
-		ppa = rqd->ppa_addr;
-		rqd->ppa_list = pr_ctx->ppa_ptr;
-		rqd->dma_ppa_list = pr_ctx->dma_ppa_list;
-		rqd->ppa_list[0] = ppa;
-	}
-
-	for (i = 0; i < nr_secs; i++) {
-		meta = pblk_get_meta(pblk, meta_list, i);
-		pr_ctx->lba_list_media[i] = le64_to_cpu(meta->lba);
-		meta->lba = cpu_to_le64(pr_ctx->lba_list_mem[i]);
-	}
-
-	/* Fill the holes in the original bio */
-	i = 0;
-	for (bit = 0; bit < nr_secs; bit++) {
-		if (!test_bit(bit, read_bitmap)) {
-			struct bio_vec dst_bv, src_bv;
-			struct pblk_line *line;
-
-			line = pblk_ppa_to_line(pblk, rqd->ppa_list[i]);
-			kref_put(&line->ref, pblk_line_put);
-
-			meta = pblk_get_meta(pblk, meta_list, bit);
-			meta->lba = cpu_to_le64(pr_ctx->lba_list_media[i]);
-
-			dst_bv = bio_iter_iovec(bio, orig_iter);
-			src_bv = bio_iter_iovec(new_bio, new_iter);
-
-			src_p = kmap_atomic(src_bv.bv_page);
-			dst_p = kmap_atomic(dst_bv.bv_page);
-
-			memcpy(dst_p + dst_bv.bv_offset,
-				src_p + src_bv.bv_offset,
-				PBLK_EXPOSED_PAGE_SIZE);
-
-			kunmap_atomic(src_p);
-			kunmap_atomic(dst_p);
-
-			flush_dcache_page(dst_bv.bv_page);
-			mempool_free(src_bv.bv_page, &pblk->page_bio_pool);
-
-			bio_advance_iter(new_bio, &new_iter,
-					PBLK_EXPOSED_PAGE_SIZE);
-			i++;
-		}
-		bio_advance_iter(bio, &orig_iter, PBLK_EXPOSED_PAGE_SIZE);
-	}
-
-	bio_put(new_bio);
-	kfree(pr_ctx);
-
-	/* restore original request */
-	rqd->bio = NULL;
-	rqd->nr_ppas = nr_secs;
-
-	pblk_end_user_read(bio, rqd->error);
-	__pblk_end_io_read(pblk, rqd, false);
-}
-
-static int pblk_setup_partial_read(struct pblk *pblk, struct nvm_rq *rqd,
-			    unsigned int bio_init_idx,
-			    unsigned long *read_bitmap,
-			    int nr_holes)
-{
-	void *meta_list = rqd->meta_list;
-	struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd);
-	struct pblk_pr_ctx *pr_ctx;
-	struct bio *new_bio, *bio = r_ctx->private;
-	int nr_secs = rqd->nr_ppas;
-	int i;
-
-	new_bio = bio_alloc(GFP_KERNEL, nr_holes);
-
-	if (pblk_bio_add_pages(pblk, new_bio, GFP_KERNEL, nr_holes))
-		goto fail_bio_put;
-
-	if (nr_holes != new_bio->bi_vcnt) {
-		WARN_ONCE(1, "pblk: malformed bio\n");
-		goto fail_free_pages;
-	}
-
-	pr_ctx = kzalloc(sizeof(struct pblk_pr_ctx), GFP_KERNEL);
-	if (!pr_ctx)
-		goto fail_free_pages;
-
-	for (i = 0; i < nr_secs; i++) {
-		struct pblk_sec_meta *meta = pblk_get_meta(pblk, meta_list, i);
-
-		pr_ctx->lba_list_mem[i] = le64_to_cpu(meta->lba);
-	}
-
-	new_bio->bi_iter.bi_sector = 0; /* internal bio */
-	bio_set_op_attrs(new_bio, REQ_OP_READ, 0);
-
-	rqd->bio = new_bio;
-	rqd->nr_ppas = nr_holes;
-
-	pr_ctx->orig_bio = bio;
-	bitmap_copy(pr_ctx->bitmap, read_bitmap, NVM_MAX_VLBA);
-	pr_ctx->bio_init_idx = bio_init_idx;
-	pr_ctx->orig_nr_secs = nr_secs;
-	r_ctx->private = pr_ctx;
-
-	if (unlikely(nr_holes == 1)) {
-		pr_ctx->ppa_ptr = rqd->ppa_list;
-		pr_ctx->dma_ppa_list = rqd->dma_ppa_list;
-		rqd->ppa_addr = rqd->ppa_list[0];
-	}
-	return 0;
-
-fail_free_pages:
-	pblk_bio_free_pages(pblk, new_bio, 0, new_bio->bi_vcnt);
-fail_bio_put:
-	bio_put(new_bio);
-
-	return -ENOMEM;
-}
-
-static int pblk_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd,
-				 unsigned int bio_init_idx,
-				 unsigned long *read_bitmap, int nr_secs)
-{
-	int nr_holes;
-	int ret;
-
-	nr_holes = nr_secs - bitmap_weight(read_bitmap, nr_secs);
-
-	if (pblk_setup_partial_read(pblk, rqd, bio_init_idx, read_bitmap,
-				    nr_holes))
-		return NVM_IO_ERR;
-
-	rqd->end_io = pblk_end_partial_read;
-
-	ret = pblk_submit_io(pblk, rqd);
-	if (ret) {
-		bio_put(rqd->bio);
-		pblk_err(pblk, "partial read IO submission failed\n");
-		goto err;
-	}
-
-	return NVM_IO_OK;
-
-err:
-	pblk_err(pblk, "failed to perform partial read\n");
-
-	/* Free allocated pages in new bio */
-	pblk_bio_free_pages(pblk, rqd->bio, 0, rqd->bio->bi_vcnt);
-	return NVM_IO_ERR;
-}
-
 static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, struct bio *bio,
-			 sector_t lba, unsigned long *read_bitmap)
+			 sector_t lba, bool *from_cache)
 {
 	struct pblk_sec_meta *meta = pblk_get_meta(pblk, rqd->meta_list, 0);
 	struct ppa_addr ppa;
 
-	pblk_lookup_l2p_seq(pblk, &ppa, lba, 1);
+	pblk_lookup_l2p_seq(pblk, &ppa, lba, 1, from_cache);
 
 #ifdef CONFIG_NVM_PBLK_DEBUG
 	atomic_long_inc(&pblk->inflight_reads);
@@ -409,7 +238,6 @@ static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, struct bio *bio,
 	if (pblk_ppa_empty(ppa)) {
 		__le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
 
-		WARN_ON(test_and_set_bit(0, read_bitmap));
 		meta->lba = addr_empty;
 		return;
 	}
@@ -418,12 +246,11 @@ static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, struct bio *bio,
 	 * write buffer to prevent retrieving overwritten data.
 	 */
 	if (pblk_addr_in_cache(ppa)) {
-		if (!pblk_read_from_cache(pblk, bio, lba, ppa, 0, 1)) {
-			pblk_lookup_l2p_seq(pblk, &ppa, lba, 1);
+		if (!pblk_read_from_cache(pblk, bio, lba, ppa)) {
+			pblk_lookup_l2p_seq(pblk, &ppa, lba, 1, from_cache);
 			goto retry;
 		}
 
-		WARN_ON(test_and_set_bit(0, read_bitmap));
 		meta->lba = cpu_to_le64(lba);
 
 #ifdef CONFIG_NVM_PBLK_DEBUG
@@ -440,17 +267,14 @@ void pblk_submit_read(struct pblk *pblk, struct bio *bio)
 	struct request_queue *q = dev->q;
 	sector_t blba = pblk_get_lba(bio);
 	unsigned int nr_secs = pblk_get_secs(bio);
+	bool from_cache;
 	struct pblk_g_ctx *r_ctx;
 	struct nvm_rq *rqd;
-	struct bio *int_bio;
-	unsigned int bio_init_idx;
-	DECLARE_BITMAP(read_bitmap, NVM_MAX_VLBA);
+	struct bio *int_bio, *split_bio;
 
 	generic_start_io_acct(q, REQ_OP_READ, bio_sectors(bio),
 			      &pblk->disk->part0);
 
-	bitmap_zero(read_bitmap, nr_secs);
-
 	rqd = pblk_alloc_rqd(pblk, PBLK_READ);
 
 	rqd->opcode = NVM_OP_PREAD;
@@ -462,11 +286,6 @@ void pblk_submit_read(struct pblk *pblk, struct bio *bio)
 	r_ctx->start_time = jiffies;
 	r_ctx->lba = blba;
 
-	/* Save the index for this bio's start. This is needed in case
-	 * we need to fill a partial read.
-	 */
-	bio_init_idx = pblk_get_bi_idx(bio);
-
 	if (pblk_alloc_rqd_meta(pblk, rqd)) {
 		bio_io_error(bio);
 		pblk_free_rqd(pblk, rqd, PBLK_READ);
@@ -475,46 +294,58 @@ void pblk_submit_read(struct pblk *pblk, struct bio *bio)
 
 	/* Clone read bio to deal internally with:
 	 * -read errors when reading from drive
-	 * -bio_advance() calls during l2p lookup and cache reads
+	 * -bio_advance() calls during cache reads
 	 */
 	int_bio = bio_clone_fast(bio, GFP_KERNEL, &pblk_bio_set);
 
 	if (nr_secs > 1)
-		pblk_read_ppalist_rq(pblk, rqd, bio, blba, read_bitmap);
+		nr_secs = pblk_read_ppalist_rq(pblk, rqd, int_bio, blba,
+						&from_cache);
 	else
-		pblk_read_rq(pblk, rqd, bio, blba, read_bitmap);
+		pblk_read_rq(pblk, rqd, int_bio, blba, &from_cache);
 
+split_retry:
 	r_ctx->private = bio; /* original bio */
 	rqd->bio = int_bio; /* internal bio */
 
-	if (bitmap_full(read_bitmap, nr_secs)) {
+	if (from_cache && nr_secs == rqd->nr_ppas) {
+		/* All data was read from cache, we can complete the IO. */
 		pblk_end_user_read(bio, 0);
 		atomic_inc(&pblk->inflight_io);
 		__pblk_end_io_read(pblk, rqd, false);
-		return;
-	}
-
-	if (!bitmap_empty(read_bitmap, rqd->nr_ppas)) {
+	} else if (nr_secs != rqd->nr_ppas) {
 		/* The read bio request could be partially filled by the write
 		 * buffer, but there are some holes that need to be read from
-		 * the drive.
+		 * the drive. In order to handle this, we will use block layer
+		 * mechanism to split this request in to smaller ones and make
+		 * a chain of it.
 		 */
-		bio_put(int_bio);
-		rqd->bio = NULL;
-		if (pblk_partial_read_bio(pblk, rqd, bio_init_idx, read_bitmap,
-					    nr_secs)) {
-			pblk_err(pblk, "read IO submission failed\n");
-			bio_io_error(bio);
-			__pblk_end_io_read(pblk, rqd, false);
-		}
-		return;
-	}
+		split_bio = bio_split(bio, nr_secs * NR_PHY_IN_LOG, GFP_KERNEL,
+					&pblk_bio_set);
+		bio_chain(split_bio, bio);
+		generic_make_request(bio);
+
+		/* New bio contains first N sectors of the previous one, so
+		 * we can continue to use existing rqd, but we need to shrink
+		 * the number of PPAs in it. New bio is also guaranteed that
+		 * it contains only either data from cache or from drive, newer
+		 * mix of them.
+		 */
+		bio = split_bio;
+		rqd->nr_ppas = nr_secs;
+		if (rqd->nr_ppas == 1)
+			rqd->ppa_addr = rqd->ppa_list[0];
 
-	/* All sectors are to be read from the device */
-	if (pblk_submit_io(pblk, rqd)) {
-		pblk_err(pblk, "read IO submission failed\n");
-		bio_io_error(bio);
-		__pblk_end_io_read(pblk, rqd, false);
+		/* Recreate int_bio - existing might have some needed internal
+		 * fields modified already.
+		 */
+		bio_put(int_bio);
+		int_bio = bio_clone_fast(bio, GFP_KERNEL, &pblk_bio_set);
+		goto split_retry;
+	} else if (pblk_submit_io(pblk, rqd)) {
+		/* Submitting IO to drive failed, let's report an error */
+		rqd->error = -ENODEV;
+		pblk_end_io_read(rqd);
 	}
 }
 
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index 17ced12..a678553 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -121,18 +121,6 @@ struct pblk_g_ctx {
 	u64 lba;
 };
 
-/* partial read context */
-struct pblk_pr_ctx {
-	struct bio *orig_bio;
-	DECLARE_BITMAP(bitmap, NVM_MAX_VLBA);
-	unsigned int orig_nr_secs;
-	unsigned int bio_init_idx;
-	void *ppa_ptr;
-	dma_addr_t dma_ppa_list;
-	u64 lba_list_mem[NVM_MAX_VLBA];
-	u64 lba_list_media[NVM_MAX_VLBA];
-};
-
 /* Pad context */
 struct pblk_pad_rq {
 	struct pblk *pblk;
@@ -759,7 +747,7 @@ unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct nvm_rq *rqd,
 				 unsigned int pos, unsigned int nr_entries,
 				 unsigned int count);
 int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
-			struct ppa_addr ppa, int bio_iter, bool advanced_bio);
+			struct ppa_addr ppa);
 unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int entries);
 
 unsigned int pblk_rb_sync_init(struct pblk_rb *rb, unsigned long *flags);
@@ -859,8 +847,8 @@ int pblk_update_map_gc(struct pblk *pblk, sector_t lba, struct ppa_addr ppa,
 		       struct pblk_line *gc_line, u64 paddr);
 void pblk_lookup_l2p_rand(struct pblk *pblk, struct ppa_addr *ppas,
 			  u64 *lba_list, int nr_secs);
-void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
-			 sector_t blba, int nr_secs);
+int pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
+			 sector_t blba, int nr_secs, bool *from_cache);
 void *pblk_get_meta_for_writes(struct pblk *pblk, struct nvm_rq *rqd);
 void pblk_get_packed_meta(struct pblk *pblk, struct nvm_rq *rqd);
 
-- 
2.9.5


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v5 2/3] lightnvm: pblk: use nvm_rq_to_ppa_list()
  2019-04-26 13:35 [PATCH v5 0/3] lightnvm: next set of improvements for 5.2 Igor Konopko
  2019-04-26 13:35 ` [PATCH v5 1/3] lightnvm: pblk: simplify partial read path Igor Konopko
@ 2019-04-26 13:35 ` Igor Konopko
  2019-04-26 13:35 ` [PATCH v5 3/3] lightnvm: pblk: store multiple copies of smeta Igor Konopko
  2019-04-26 19:53 ` [PATCH v5 0/3] lightnvm: next set of improvements for 5.2 Matias Bjørling
  3 siblings, 0 replies; 9+ messages in thread
From: Igor Konopko @ 2019-04-26 13:35 UTC (permalink / raw)
  To: mb, javier, hans.holmberg; +Cc: linux-block, igor.j.konopko

This patch replaces few remaining usages of rqd->ppa_list[] with
existing nvm_rq_to_ppa_list() helpers. This is needed for theoretical
devices with ws_min/ws_opt equal to 1.

Signed-off-by: Igor Konopko <igor.j.konopko@intel.com>
Reviewed-by: Javier González <javier@javigon.com>
---
 drivers/lightnvm/pblk-core.c     | 26 ++++++++++++++------------
 drivers/lightnvm/pblk-recovery.c | 13 ++++++++-----
 2 files changed, 22 insertions(+), 17 deletions(-)

diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 07270ba..7735378 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -562,11 +562,9 @@ int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd)
 
 int pblk_submit_io_sync_sem(struct pblk *pblk, struct nvm_rq *rqd)
 {
-	struct ppa_addr *ppa_list;
+	struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
 	int ret;
 
-	ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr;
-
 	pblk_down_chunk(pblk, ppa_list[0]);
 	ret = pblk_submit_io_sync(pblk, rqd);
 	pblk_up_chunk(pblk, ppa_list[0]);
@@ -725,6 +723,7 @@ int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line)
 	struct nvm_tgt_dev *dev = pblk->dev;
 	struct pblk_line_meta *lm = &pblk->lm;
 	struct bio *bio;
+	struct ppa_addr *ppa_list;
 	struct nvm_rq rqd;
 	u64 paddr = pblk_line_smeta_start(pblk, line);
 	int i, ret;
@@ -748,9 +747,10 @@ int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line)
 	rqd.opcode = NVM_OP_PREAD;
 	rqd.nr_ppas = lm->smeta_sec;
 	rqd.is_seq = 1;
+	ppa_list = nvm_rq_to_ppa_list(&rqd);
 
 	for (i = 0; i < lm->smeta_sec; i++, paddr++)
-		rqd.ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id);
+		ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id);
 
 	ret = pblk_submit_io_sync(pblk, &rqd);
 	if (ret) {
@@ -777,6 +777,7 @@ static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line,
 	struct nvm_tgt_dev *dev = pblk->dev;
 	struct pblk_line_meta *lm = &pblk->lm;
 	struct bio *bio;
+	struct ppa_addr *ppa_list;
 	struct nvm_rq rqd;
 	__le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf);
 	__le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
@@ -801,12 +802,13 @@ static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line,
 	rqd.opcode = NVM_OP_PWRITE;
 	rqd.nr_ppas = lm->smeta_sec;
 	rqd.is_seq = 1;
+	ppa_list = nvm_rq_to_ppa_list(&rqd);
 
 	for (i = 0; i < lm->smeta_sec; i++, paddr++) {
 		struct pblk_sec_meta *meta = pblk_get_meta(pblk,
 							   rqd.meta_list, i);
 
-		rqd.ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id);
+		ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id);
 		meta->lba = lba_list[paddr] = addr_empty;
 	}
 
@@ -836,8 +838,9 @@ int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line,
 	struct nvm_geo *geo = &dev->geo;
 	struct pblk_line_mgmt *l_mg = &pblk->l_mg;
 	struct pblk_line_meta *lm = &pblk->lm;
-	void *ppa_list, *meta_list;
+	void *ppa_list_buf, *meta_list;
 	struct bio *bio;
+	struct ppa_addr *ppa_list;
 	struct nvm_rq rqd;
 	u64 paddr = line->emeta_ssec;
 	dma_addr_t dma_ppa_list, dma_meta_list;
@@ -853,7 +856,7 @@ int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line,
 	if (!meta_list)
 		return -ENOMEM;
 
-	ppa_list = meta_list + pblk_dma_meta_size(pblk);
+	ppa_list_buf = meta_list + pblk_dma_meta_size(pblk);
 	dma_ppa_list = dma_meta_list + pblk_dma_meta_size(pblk);
 
 next_rq:
@@ -874,11 +877,12 @@ int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line,
 
 	rqd.bio = bio;
 	rqd.meta_list = meta_list;
-	rqd.ppa_list = ppa_list;
+	rqd.ppa_list = ppa_list_buf;
 	rqd.dma_meta_list = dma_meta_list;
 	rqd.dma_ppa_list = dma_ppa_list;
 	rqd.opcode = NVM_OP_PREAD;
 	rqd.nr_ppas = rq_ppas;
+	ppa_list = nvm_rq_to_ppa_list(&rqd);
 
 	for (i = 0; i < rqd.nr_ppas; ) {
 		struct ppa_addr ppa = addr_to_gen_ppa(pblk, paddr, line_id);
@@ -906,7 +910,7 @@ int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line,
 		}
 
 		for (j = 0; j < min; j++, i++, paddr++)
-			rqd.ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line_id);
+			ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line_id);
 	}
 
 	ret = pblk_submit_io_sync(pblk, &rqd);
@@ -1525,11 +1529,9 @@ 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)
 {
-	struct ppa_addr *ppa_list;
+	struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
 	int i;
 
-	ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr;
-
 	for (i = 0; i < rqd->nr_ppas; i++)
 		pblk_ppa_to_line_put(pblk, ppa_list[i]);
 }
diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c
index a9085b0..e6dda04 100644
--- a/drivers/lightnvm/pblk-recovery.c
+++ b/drivers/lightnvm/pblk-recovery.c
@@ -179,6 +179,7 @@ static int pblk_recov_pad_line(struct pblk *pblk, struct pblk_line *line,
 	struct pblk_pad_rq *pad_rq;
 	struct nvm_rq *rqd;
 	struct bio *bio;
+	struct ppa_addr *ppa_list;
 	void *data;
 	__le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf);
 	u64 w_ptr = line->cur_sec;
@@ -239,6 +240,7 @@ static int pblk_recov_pad_line(struct pblk *pblk, struct pblk_line *line,
 	rqd->end_io = pblk_end_io_recov;
 	rqd->private = pad_rq;
 
+	ppa_list = nvm_rq_to_ppa_list(rqd);
 	meta_list = rqd->meta_list;
 
 	for (i = 0; i < rqd->nr_ppas; ) {
@@ -266,17 +268,17 @@ static int pblk_recov_pad_line(struct pblk *pblk, struct pblk_line *line,
 			lba_list[w_ptr] = addr_empty;
 			meta = pblk_get_meta(pblk, meta_list, i);
 			meta->lba = addr_empty;
-			rqd->ppa_list[i] = dev_ppa;
+			ppa_list[i] = dev_ppa;
 		}
 	}
 
 	kref_get(&pad_rq->ref);
-	pblk_down_chunk(pblk, rqd->ppa_list[0]);
+	pblk_down_chunk(pblk, ppa_list[0]);
 
 	ret = pblk_submit_io(pblk, rqd);
 	if (ret) {
 		pblk_err(pblk, "I/O submission failed: %d\n", ret);
-		pblk_up_chunk(pblk, rqd->ppa_list[0]);
+		pblk_up_chunk(pblk, ppa_list[0]);
 		kref_put(&pad_rq->ref, pblk_recov_complete);
 		pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT);
 		bio_put(bio);
@@ -420,6 +422,7 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line,
 	rqd->ppa_list = ppa_list;
 	rqd->dma_ppa_list = dma_ppa_list;
 	rqd->dma_meta_list = dma_meta_list;
+	ppa_list = nvm_rq_to_ppa_list(rqd);
 
 	if (pblk_io_aligned(pblk, rq_ppas))
 		rqd->is_seq = 1;
@@ -438,7 +441,7 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line,
 		}
 
 		for (j = 0; j < pblk->min_write_pgs; j++, i++)
-			rqd->ppa_list[i] =
+			ppa_list[i] =
 				addr_to_gen_ppa(pblk, paddr + j, line->id);
 	}
 
@@ -486,7 +489,7 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line,
 			continue;
 
 		line->nr_valid_lbas++;
-		pblk_update_map(pblk, lba, rqd->ppa_list[i]);
+		pblk_update_map(pblk, lba, ppa_list[i]);
 	}
 
 	left_ppas -= rq_ppas;
-- 
2.9.5


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v5 3/3] lightnvm: pblk: store multiple copies of smeta
  2019-04-26 13:35 [PATCH v5 0/3] lightnvm: next set of improvements for 5.2 Igor Konopko
  2019-04-26 13:35 ` [PATCH v5 1/3] lightnvm: pblk: simplify partial read path Igor Konopko
  2019-04-26 13:35 ` [PATCH v5 2/3] lightnvm: pblk: use nvm_rq_to_ppa_list() Igor Konopko
@ 2019-04-26 13:35 ` Igor Konopko
  2019-04-26 19:53 ` [PATCH v5 0/3] lightnvm: next set of improvements for 5.2 Matias Bjørling
  3 siblings, 0 replies; 9+ messages in thread
From: Igor Konopko @ 2019-04-26 13:35 UTC (permalink / raw)
  To: mb, javier, hans.holmberg; +Cc: linux-block, igor.j.konopko

Currently there is only one copy of smeta stored per line in pblk. This
is risky, because in case of read error on such a chunk, we are losing
all the data from whole line, what leads to silent data corruption.

This patch changes this behaviour and allows to store more then one
copy of the smeta (specified by module parameter) in order to provide
higher reliability by storing mirrored copies of smeta struct and
providing possibility to failover to another copy of that struct in
case of read error. Such an approach ensures that copies of that
critical structures will be stored on different dies and thus predicted
UBER is multiple times higher

Signed-off-by: Igor Konopko <igor.j.konopko@intel.com>
Reviewed-by: Javier González <javier@javigon.com>
---
 drivers/lightnvm/pblk-core.c     | 124 ++++++++++++++++++++++++++++++++-------
 drivers/lightnvm/pblk-init.c     |  23 ++++++--
 drivers/lightnvm/pblk-recovery.c |  14 +++--
 drivers/lightnvm/pblk-rl.c       |   3 +-
 drivers/lightnvm/pblk.h          |   1 +
 5 files changed, 132 insertions(+), 33 deletions(-)

diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 7735378..9cf894a 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -718,14 +718,15 @@ u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line)
 	return bit * geo->ws_opt;
 }
 
-int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line)
+static int pblk_line_smeta_read_copy(struct pblk *pblk,
+				     struct pblk_line *line, u64 paddr)
 {
 	struct nvm_tgt_dev *dev = pblk->dev;
+	struct nvm_geo *geo = &dev->geo;
 	struct pblk_line_meta *lm = &pblk->lm;
 	struct bio *bio;
 	struct ppa_addr *ppa_list;
 	struct nvm_rq rqd;
-	u64 paddr = pblk_line_smeta_start(pblk, line);
 	int i, ret;
 
 	memset(&rqd, 0, sizeof(struct nvm_rq));
@@ -749,8 +750,20 @@ int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line)
 	rqd.is_seq = 1;
 	ppa_list = nvm_rq_to_ppa_list(&rqd);
 
-	for (i = 0; i < lm->smeta_sec; i++, paddr++)
-		ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id);
+	for (i = 0; i < rqd.nr_ppas; i++, paddr++) {
+		struct ppa_addr ppa = addr_to_gen_ppa(pblk, paddr, line->id);
+		int pos = pblk_ppa_to_pos(geo, ppa);
+
+		while (test_bit(pos, line->blk_bitmap)) {
+			paddr += pblk->min_write_pgs;
+			ppa = addr_to_gen_ppa(pblk, paddr, line->id);
+			pos = pblk_ppa_to_pos(geo, ppa);
+		}
+
+		ppa_list[i] = ppa;
+		pblk_get_meta(pblk, rqd.meta_list, i)->lba =
+				  cpu_to_le64(ADDR_EMPTY);
+	}
 
 	ret = pblk_submit_io_sync(pblk, &rqd);
 	if (ret) {
@@ -771,17 +784,64 @@ int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line)
 	return ret;
 }
 
-static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line,
-				 u64 paddr)
+int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line)
+{
+	struct pblk_line_meta *lm = &pblk->lm;
+	int i, ret = 0;
+	u64 paddr = pblk_line_smeta_start(pblk, line);
+
+	for (i = 0; i < lm->smeta_copies; i++) {
+		ret = pblk_line_smeta_read_copy(pblk, line,
+						paddr + (i * lm->smeta_sec));
+		if (!ret) {
+			/*
+			 * Just one successfully read copy of smeta is
+			 * enough for us for recovery, don't need to
+			 * read another one.
+			 */
+			return ret;
+		}
+	}
+	return ret;
+}
+
+static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line)
 {
 	struct nvm_tgt_dev *dev = pblk->dev;
+	struct nvm_geo *geo = &dev->geo;
 	struct pblk_line_meta *lm = &pblk->lm;
 	struct bio *bio;
 	struct ppa_addr *ppa_list;
 	struct nvm_rq rqd;
 	__le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf);
 	__le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
-	int i, ret;
+	u64 paddr = 0;
+	int smeta_wr_len = lm->smeta_len;
+	int smeta_wr_sec = lm->smeta_sec;
+	int i, ret, rq_writes;
+
+	/*
+	 * Check if we can write all the smeta copies with
+	 * a single write command.
+	 * If yes -> copy smeta sector into multiple copies
+	 * in buffer to write.
+	 * If no -> issue writes one by one using the same
+	 * buffer space.
+	 * Only if all the copies are written correctly
+	 * we are treating this line as valid for proper
+	 * UBER reliability.
+	 */
+	if (lm->smeta_sec * lm->smeta_copies > pblk->max_write_pgs) {
+		rq_writes = lm->smeta_copies;
+	} else {
+		rq_writes = 1;
+		for (i = 1; i < lm->smeta_copies; i++) {
+			memcpy(line->smeta + i * lm->smeta_len,
+			       line->smeta, lm->smeta_len);
+		}
+		smeta_wr_len *= lm->smeta_copies;
+		smeta_wr_sec *= lm->smeta_copies;
+	}
 
 	memset(&rqd, 0, sizeof(struct nvm_rq));
 
@@ -789,7 +849,8 @@ static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line,
 	if (ret)
 		return ret;
 
-	bio = bio_map_kern(dev->q, line->smeta, lm->smeta_len, GFP_KERNEL);
+next_rq:
+	bio = bio_map_kern(dev->q, line->smeta, smeta_wr_len, GFP_KERNEL);
 	if (IS_ERR(bio)) {
 		ret = PTR_ERR(bio);
 		goto clear_rqd;
@@ -800,16 +861,24 @@ static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line,
 
 	rqd.bio = bio;
 	rqd.opcode = NVM_OP_PWRITE;
-	rqd.nr_ppas = lm->smeta_sec;
+	rqd.nr_ppas = smeta_wr_sec;
 	rqd.is_seq = 1;
 	ppa_list = nvm_rq_to_ppa_list(&rqd);
 
-	for (i = 0; i < lm->smeta_sec; i++, paddr++) {
-		struct pblk_sec_meta *meta = pblk_get_meta(pblk,
-							   rqd.meta_list, i);
+	for (i = 0; i < rqd.nr_ppas; i++, paddr++) {
+		void *meta_list = rqd.meta_list;
+		struct ppa_addr ppa = addr_to_gen_ppa(pblk, paddr, line->id);
+		int pos = pblk_ppa_to_pos(geo, ppa);
 
-		ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id);
-		meta->lba = lba_list[paddr] = addr_empty;
+		while (test_bit(pos, line->blk_bitmap)) {
+			paddr += pblk->min_write_pgs;
+			ppa = addr_to_gen_ppa(pblk, paddr, line->id);
+			pos = pblk_ppa_to_pos(geo, ppa);
+		}
+
+		ppa_list[i] = ppa;
+		pblk_get_meta(pblk, meta_list, i)->lba = addr_empty;
+		lba_list[paddr] = addr_empty;
 	}
 
 	ret = pblk_submit_io_sync_sem(pblk, &rqd);
@@ -824,8 +893,13 @@ static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line,
 	if (rqd.error) {
 		pblk_log_write_err(pblk, &rqd);
 		ret = -EIO;
+		goto clear_rqd;
 	}
 
+	rq_writes--;
+	if (rq_writes > 0)
+		goto next_rq;
+
 clear_rqd:
 	pblk_free_rqd_meta(pblk, &rqd);
 	return ret;
@@ -1024,7 +1098,7 @@ static void pblk_line_setup_metadata(struct pblk_line *line,
 	line->smeta = l_mg->sline_meta[meta_line];
 	line->emeta = l_mg->eline_meta[meta_line];
 
-	memset(line->smeta, 0, lm->smeta_len);
+	memset(line->smeta, 0, lm->smeta_len * lm->smeta_copies);
 	memset(line->emeta->buf, 0, lm->emeta_len[0]);
 
 	line->emeta->mem = 0;
@@ -1151,7 +1225,7 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
 	struct pblk_line_mgmt *l_mg = &pblk->l_mg;
 	u64 off;
 	int bit = -1;
-	int emeta_secs;
+	int emeta_secs, smeta_secs;
 
 	line->sec_in_line = lm->sec_per_line;
 
@@ -1167,13 +1241,19 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
 	}
 
 	/* Mark smeta metadata sectors as bad sectors */
-	bit = find_first_zero_bit(line->blk_bitmap, lm->blk_per_line);
-	off = bit * geo->ws_opt;
-	bitmap_set(line->map_bitmap, off, lm->smeta_sec);
-	line->sec_in_line -= lm->smeta_sec;
-	line->cur_sec = off + lm->smeta_sec;
+	smeta_secs = lm->smeta_sec * lm->smeta_copies;
+	bit = -1;
+	while (smeta_secs) {
+		bit = find_next_zero_bit(line->blk_bitmap, lm->blk_per_line,
+					bit + 1);
+		off = bit * geo->ws_opt;
+		bitmap_set(line->map_bitmap, off, geo->ws_opt);
+		line->cur_sec = off + geo->ws_opt;
+		smeta_secs -= lm->smeta_sec;
+	}
+	line->sec_in_line -= (lm->smeta_sec * lm->smeta_copies);
 
-	if (init && pblk_line_smeta_write(pblk, line, off)) {
+	if (init && pblk_line_smeta_write(pblk, line)) {
 		pblk_debug(pblk, "line smeta I/O failed. Retry\n");
 		return 0;
 	}
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index b351c7f..4f6d214 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -27,6 +27,11 @@ static unsigned int write_buffer_size;
 module_param(write_buffer_size, uint, 0644);
 MODULE_PARM_DESC(write_buffer_size, "number of entries in a write buffer");
 
+static unsigned int smeta_copies = 1;
+
+module_param(smeta_copies, int, 0644);
+MODULE_PARM_DESC(smeta_copies, "number of smeta copies");
+
 struct pblk_global_caches {
 	struct kmem_cache	*ws;
 	struct kmem_cache	*rec;
@@ -864,7 +869,8 @@ static int pblk_line_mg_init(struct pblk *pblk)
 	 * emeta depends on the number of LUNs allocated to the pblk instance
 	 */
 	for (i = 0; i < PBLK_DATA_LINES; i++) {
-		l_mg->sline_meta[i] = kmalloc(lm->smeta_len, GFP_KERNEL);
+		l_mg->sline_meta[i] = kmalloc(lm->smeta_len
+						* lm->smeta_copies, GFP_KERNEL);
 		if (!l_mg->sline_meta[i])
 			goto fail_free_smeta;
 	}
@@ -964,6 +970,12 @@ static int pblk_line_meta_init(struct pblk *pblk)
 	lm->mid_thrs = lm->sec_per_line / 2;
 	lm->high_thrs = lm->sec_per_line / 4;
 	lm->meta_distance = (geo->all_luns / 2) * pblk->min_write_pgs;
+	lm->smeta_copies = smeta_copies;
+
+	if (lm->smeta_copies < 1 || lm->smeta_copies > geo->all_luns) {
+		pblk_err(pblk, "unsupported smeta copies parameter\n");
+		return -EINVAL;
+	}
 
 	/* Calculate necessary pages for smeta. See comment over struct
 	 * line_smeta definition
@@ -995,10 +1007,11 @@ static int pblk_line_meta_init(struct pblk *pblk)
 
 	lm->emeta_bb = geo->all_luns > i ? geo->all_luns - i : 0;
 
-	lm->min_blk_line = 1;
-	if (geo->all_luns > 1)
-		lm->min_blk_line += DIV_ROUND_UP(lm->smeta_sec +
-					lm->emeta_sec[0], geo->clba);
+	lm->min_blk_line = lm->smeta_copies;
+	if (geo->all_luns > lm->smeta_copies) {
+		lm->min_blk_line += DIV_ROUND_UP((lm->smeta_sec
+			* lm->smeta_copies) + lm->emeta_sec[0], geo->clba);
+	}
 
 	if (lm->min_blk_line > lm->blk_per_line) {
 		pblk_err(pblk, "config. not supported. Min. LUN in line:%d\n",
diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c
index e6dda04..2fca21e 100644
--- a/drivers/lightnvm/pblk-recovery.c
+++ b/drivers/lightnvm/pblk-recovery.c
@@ -51,7 +51,8 @@ static int pblk_recov_l2p_from_emeta(struct pblk *pblk, struct pblk_line *line)
 	if (!lba_list)
 		return 1;
 
-	data_start = pblk_line_smeta_start(pblk, line) + lm->smeta_sec;
+	data_start = pblk_line_smeta_start(pblk, line)
+					+ (lm->smeta_sec * lm->smeta_copies);
 	data_end = line->emeta_ssec;
 	nr_valid_lbas = le64_to_cpu(emeta_buf->nr_valid_lbas);
 
@@ -134,7 +135,8 @@ static u64 pblk_sec_in_open_line(struct pblk *pblk, struct pblk_line *line)
 	if (lm->blk_per_line - nr_bb != valid_chunks)
 		pblk_err(pblk, "recovery line %d is bad\n", line->id);
 
-	pblk_update_line_wp(pblk, line, written_secs - lm->smeta_sec);
+	pblk_update_line_wp(pblk, line, written_secs -
+					(lm->smeta_sec * lm->smeta_copies));
 
 	return written_secs;
 }
@@ -379,12 +381,14 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line,
 	void *data;
 	dma_addr_t dma_ppa_list, dma_meta_list;
 	__le64 *lba_list;
-	u64 paddr = pblk_line_smeta_start(pblk, line) + lm->smeta_sec;
+	u64 paddr = pblk_line_smeta_start(pblk, line) +
+					(lm->smeta_sec * lm->smeta_copies);
 	bool padded = false;
 	int rq_ppas, rq_len;
 	int i, j;
 	int ret;
-	u64 left_ppas = pblk_sec_in_open_line(pblk, line) - lm->smeta_sec;
+	u64 left_ppas = pblk_sec_in_open_line(pblk, line) -
+					(lm->smeta_sec * lm->smeta_copies);
 
 	if (pblk_line_wps_are_unbalanced(pblk, line))
 		pblk_warn(pblk, "recovering unbalanced line (%d)\n", line->id);
@@ -709,7 +713,7 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk)
 
 		line = &pblk->lines[i];
 
-		memset(smeta, 0, lm->smeta_len);
+		memset(smeta, 0, lm->smeta_len * lm->smeta_copies);
 		line->smeta = smeta;
 		line->lun_bitmap = ((void *)(smeta_buf)) +
 						sizeof(struct line_smeta);
diff --git a/drivers/lightnvm/pblk-rl.c b/drivers/lightnvm/pblk-rl.c
index a5f8bc2..c74ec73 100644
--- a/drivers/lightnvm/pblk-rl.c
+++ b/drivers/lightnvm/pblk-rl.c
@@ -218,7 +218,8 @@ void pblk_rl_init(struct pblk_rl *rl, int budget, int threshold)
 	unsigned int rb_windows;
 
 	/* Consider sectors used for metadata */
-	sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines;
+	sec_meta = ((lm->smeta_sec * lm->smeta_copies)
+			+ lm->emeta_sec[0]) * l_mg->nr_free_lines;
 	blk_meta = DIV_ROUND_UP(sec_meta, geo->clba);
 
 	rl->high = pblk->op_blks - blk_meta - lm->blk_per_line;
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index a678553..183bc99 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -548,6 +548,7 @@ struct pblk_line_mgmt {
 struct pblk_line_meta {
 	unsigned int smeta_len;		/* Total length for smeta */
 	unsigned int smeta_sec;		/* Sectors needed for smeta */
+	unsigned int smeta_copies;	/* Number of smeta copies */
 
 	unsigned int emeta_len[4];	/* Lengths for emeta:
 					 *  [0]: Total
-- 
2.9.5


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v5 1/3] lightnvm: pblk: simplify partial read path
  2019-04-26 13:35 ` [PATCH v5 1/3] lightnvm: pblk: simplify partial read path Igor Konopko
@ 2019-04-26 16:30   ` Heiner Litz
  2019-05-01  6:20   ` Javier González
  1 sibling, 0 replies; 9+ messages in thread
From: Heiner Litz @ 2019-04-26 16:30 UTC (permalink / raw)
  To: Igor Konopko
  Cc: Matias Bjørling, Javier González, Hans Holmberg, linux-block

Hi Igor,
I agree with your previous comments on this patch. I didn't run a lot
of tests but the patch LGTM.

Reviewed-by: Heiner Litz <hlitz@ucsc.edu>



On Fri, Apr 26, 2019 at 6:38 AM Igor Konopko <igor.j.konopko@intel.com> wrote:
>
> This patch changes the approach to handling partial read path.
>
> In old approach merging of data from round buffer and drive was fully
> made by drive. This had some disadvantages - code was complex and
> relies on bio internals, so it was hard to maintain and was strongly
> dependent on bio changes.
>
> In new approach most of the handling is done mostly by block layer
> functions such as bio_split(), bio_chain() and generic_make request()
> and generally is less complex and easier to maintain. Below some more
> details of the new approach.
>
> When read bio arrives, it is cloned for pblk internal purposes. All
> the L2P mapping, which includes copying data from round buffer to bio
> and thus bio_advance() calls is done on the cloned bio, so the original
> bio is untouched. If we found that we have partial read case, we
> still have original bio untouched, so we can split it and continue to
> process only first part of it in current context, when the rest will be
> called as separate bio request which is passed to generic_make_request()
> for further processing.
>
> Signed-off-by: Igor Konopko <igor.j.konopko@intel.com>
> ---
>  drivers/lightnvm/pblk-core.c |  13 +-
>  drivers/lightnvm/pblk-rb.c   |  11 +-
>  drivers/lightnvm/pblk-read.c | 339 +++++++++++--------------------------------
>  drivers/lightnvm/pblk.h      |  18 +--
>  4 files changed, 100 insertions(+), 281 deletions(-)
>
> diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
> index 73be3a0..07270ba 100644
> --- a/drivers/lightnvm/pblk-core.c
> +++ b/drivers/lightnvm/pblk-core.c
> @@ -2147,8 +2147,8 @@ void pblk_update_map_dev(struct pblk *pblk, sector_t lba,
>         spin_unlock(&pblk->trans_lock);
>  }
>
> -void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
> -                        sector_t blba, int nr_secs)
> +int pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
> +                        sector_t blba, int nr_secs, bool *from_cache)
>  {
>         int i;
>
> @@ -2162,10 +2162,19 @@ void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
>                 if (!pblk_ppa_empty(ppa) && !pblk_addr_in_cache(ppa)) {
>                         struct pblk_line *line = pblk_ppa_to_line(pblk, ppa);
>
> +                       if (i > 0 && *from_cache)
> +                               break;
> +                       *from_cache = false;
> +
>                         kref_get(&line->ref);
> +               } else {
> +                       if (i > 0 && !*from_cache)
> +                               break;
> +                       *from_cache = true;
>                 }
>         }
>         spin_unlock(&pblk->trans_lock);
> +       return i;
>  }
>
>  void pblk_lookup_l2p_rand(struct pblk *pblk, struct ppa_addr *ppas,
> diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c
> index 3555014..5abb170 100644
> --- a/drivers/lightnvm/pblk-rb.c
> +++ b/drivers/lightnvm/pblk-rb.c
> @@ -642,7 +642,7 @@ unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct nvm_rq *rqd,
>   * be directed to disk.
>   */
>  int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
> -                       struct ppa_addr ppa, int bio_iter, bool advanced_bio)
> +                       struct ppa_addr ppa)
>  {
>         struct pblk *pblk = container_of(rb, struct pblk, rwb);
>         struct pblk_rb_entry *entry;
> @@ -673,15 +673,6 @@ int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
>                 ret = 0;
>                 goto out;
>         }
> -
> -       /* Only advance the bio if it hasn't been advanced already. If advanced,
> -        * this bio is at least a partial bio (i.e., it has partially been
> -        * filled with data from the cache). If part of the data resides on the
> -        * media, we will read later on
> -        */
> -       if (unlikely(!advanced_bio))
> -               bio_advance(bio, bio_iter * PBLK_EXPOSED_PAGE_SIZE);
> -
>         data = bio_data(bio);
>         memcpy(data, entry->data, rb->seg_size);
>
> diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c
> index f5f155d..d98ea39 100644
> --- a/drivers/lightnvm/pblk-read.c
> +++ b/drivers/lightnvm/pblk-read.c
> @@ -26,8 +26,7 @@
>   * issued.
>   */
>  static int pblk_read_from_cache(struct pblk *pblk, struct bio *bio,
> -                               sector_t lba, struct ppa_addr ppa,
> -                               int bio_iter, bool advanced_bio)
> +                               sector_t lba, struct ppa_addr ppa)
>  {
>  #ifdef CONFIG_NVM_PBLK_DEBUG
>         /* Callers must ensure that the ppa points to a cache address */
> @@ -35,73 +34,75 @@ static int pblk_read_from_cache(struct pblk *pblk, struct bio *bio,
>         BUG_ON(!pblk_addr_in_cache(ppa));
>  #endif
>
> -       return pblk_rb_copy_to_bio(&pblk->rwb, bio, lba, ppa,
> -                                               bio_iter, advanced_bio);
> +       return pblk_rb_copy_to_bio(&pblk->rwb, bio, lba, ppa);
>  }
>
> -static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
> +static int pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
>                                  struct bio *bio, sector_t blba,
> -                                unsigned long *read_bitmap)
> +                                bool *from_cache)
>  {
>         void *meta_list = rqd->meta_list;
> -       struct ppa_addr ppas[NVM_MAX_VLBA];
> -       int nr_secs = rqd->nr_ppas;
> -       bool advanced_bio = false;
> -       int i, j = 0;
> +       int nr_secs, i;
>
> -       pblk_lookup_l2p_seq(pblk, ppas, blba, nr_secs);
> +retry:
> +       nr_secs = pblk_lookup_l2p_seq(pblk, rqd->ppa_list, blba, rqd->nr_ppas,
> +                                       from_cache);
> +
> +       if (!*from_cache)
> +               goto end;
>
>         for (i = 0; i < nr_secs; i++) {
> -               struct ppa_addr p = ppas[i];
>                 struct pblk_sec_meta *meta = pblk_get_meta(pblk, meta_list, i);
>                 sector_t lba = blba + i;
>
> -retry:
> -               if (pblk_ppa_empty(p)) {
> +               if (pblk_ppa_empty(rqd->ppa_list[i])) {
>                         __le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
>
> -                       WARN_ON(test_and_set_bit(i, read_bitmap));
>                         meta->lba = addr_empty;
> -
> -                       if (unlikely(!advanced_bio)) {
> -                               bio_advance(bio, (i) * PBLK_EXPOSED_PAGE_SIZE);
> -                               advanced_bio = true;
> +               } else if (pblk_addr_in_cache(rqd->ppa_list[i])) {
> +                       /*
> +                        * Try to read from write buffer. The address is later
> +                        * checked on the write buffer to prevent retrieving
> +                        * overwritten data.
> +                        */
> +                       if (!pblk_read_from_cache(pblk, bio, lba,
> +                                                       rqd->ppa_list[i])) {
> +                               if (i == 0) {
> +                                       /*
> +                                        * We didn't call with bio_advance()
> +                                        * yet, so we can just retry.
> +                                        */
> +                                       goto retry;
> +                               } else {
> +                                       /*
> +                                        * We already call bio_advance()
> +                                        * so we cannot retry and we need
> +                                        * to quit that function in order
> +                                        * to allow caller to handle the bio
> +                                        * splitting in the current sector
> +                                        * position.
> +                                        */
> +                                       nr_secs = i;
> +                                       goto end;
> +                               }
>                         }
> -
> -                       goto next;
> -               }
> -
> -               /* Try to read from write buffer. The address is later checked
> -                * on the write buffer to prevent retrieving overwritten data.
> -                */
> -               if (pblk_addr_in_cache(p)) {
> -                       if (!pblk_read_from_cache(pblk, bio, lba, p, i,
> -                                                               advanced_bio)) {
> -                               pblk_lookup_l2p_seq(pblk, &p, lba, 1);
> -                               goto retry;
> -                       }
> -                       WARN_ON(test_and_set_bit(i, read_bitmap));
>                         meta->lba = cpu_to_le64(lba);
> -                       advanced_bio = true;
>  #ifdef CONFIG_NVM_PBLK_DEBUG
>                         atomic_long_inc(&pblk->cache_reads);
>  #endif
> -               } else {
> -                       /* Read from media non-cached sectors */
> -                       rqd->ppa_list[j++] = p;
>                 }
> -
> -next:
> -               if (advanced_bio)
> -                       bio_advance(bio, PBLK_EXPOSED_PAGE_SIZE);
> +               bio_advance(bio, PBLK_EXPOSED_PAGE_SIZE);
>         }
>
> +end:
>         if (pblk_io_aligned(pblk, nr_secs))
>                 rqd->is_seq = 1;
>
>  #ifdef CONFIG_NVM_PBLK_DEBUG
>         atomic_long_add(nr_secs, &pblk->inflight_reads);
>  #endif
> +
> +       return nr_secs;
>  }
>
>
> @@ -197,9 +198,7 @@ static void __pblk_end_io_read(struct pblk *pblk, struct nvm_rq *rqd,
>                 pblk_log_read_err(pblk, rqd);
>
>         pblk_read_check_seq(pblk, rqd, r_ctx->lba);
> -
> -       if (int_bio)
> -               bio_put(int_bio);
> +       bio_put(int_bio);
>
>         if (put_line)
>                 pblk_rq_to_line_put(pblk, rqd);
> @@ -223,183 +222,13 @@ static void pblk_end_io_read(struct nvm_rq *rqd)
>         __pblk_end_io_read(pblk, rqd, true);
>  }
>
> -static void pblk_end_partial_read(struct nvm_rq *rqd)
> -{
> -       struct pblk *pblk = rqd->private;
> -       struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd);
> -       struct pblk_pr_ctx *pr_ctx = r_ctx->private;
> -       struct pblk_sec_meta *meta;
> -       struct bio *new_bio = rqd->bio;
> -       struct bio *bio = pr_ctx->orig_bio;
> -       void *meta_list = rqd->meta_list;
> -       unsigned long *read_bitmap = pr_ctx->bitmap;
> -       struct bvec_iter orig_iter = BVEC_ITER_ALL_INIT;
> -       struct bvec_iter new_iter = BVEC_ITER_ALL_INIT;
> -       int nr_secs = pr_ctx->orig_nr_secs;
> -       int nr_holes = nr_secs - bitmap_weight(read_bitmap, nr_secs);
> -       void *src_p, *dst_p;
> -       int bit, i;
> -
> -       if (unlikely(nr_holes == 1)) {
> -               struct ppa_addr ppa;
> -
> -               ppa = rqd->ppa_addr;
> -               rqd->ppa_list = pr_ctx->ppa_ptr;
> -               rqd->dma_ppa_list = pr_ctx->dma_ppa_list;
> -               rqd->ppa_list[0] = ppa;
> -       }
> -
> -       for (i = 0; i < nr_secs; i++) {
> -               meta = pblk_get_meta(pblk, meta_list, i);
> -               pr_ctx->lba_list_media[i] = le64_to_cpu(meta->lba);
> -               meta->lba = cpu_to_le64(pr_ctx->lba_list_mem[i]);
> -       }
> -
> -       /* Fill the holes in the original bio */
> -       i = 0;
> -       for (bit = 0; bit < nr_secs; bit++) {
> -               if (!test_bit(bit, read_bitmap)) {
> -                       struct bio_vec dst_bv, src_bv;
> -                       struct pblk_line *line;
> -
> -                       line = pblk_ppa_to_line(pblk, rqd->ppa_list[i]);
> -                       kref_put(&line->ref, pblk_line_put);
> -
> -                       meta = pblk_get_meta(pblk, meta_list, bit);
> -                       meta->lba = cpu_to_le64(pr_ctx->lba_list_media[i]);
> -
> -                       dst_bv = bio_iter_iovec(bio, orig_iter);
> -                       src_bv = bio_iter_iovec(new_bio, new_iter);
> -
> -                       src_p = kmap_atomic(src_bv.bv_page);
> -                       dst_p = kmap_atomic(dst_bv.bv_page);
> -
> -                       memcpy(dst_p + dst_bv.bv_offset,
> -                               src_p + src_bv.bv_offset,
> -                               PBLK_EXPOSED_PAGE_SIZE);
> -
> -                       kunmap_atomic(src_p);
> -                       kunmap_atomic(dst_p);
> -
> -                       flush_dcache_page(dst_bv.bv_page);
> -                       mempool_free(src_bv.bv_page, &pblk->page_bio_pool);
> -
> -                       bio_advance_iter(new_bio, &new_iter,
> -                                       PBLK_EXPOSED_PAGE_SIZE);
> -                       i++;
> -               }
> -               bio_advance_iter(bio, &orig_iter, PBLK_EXPOSED_PAGE_SIZE);
> -       }
> -
> -       bio_put(new_bio);
> -       kfree(pr_ctx);
> -
> -       /* restore original request */
> -       rqd->bio = NULL;
> -       rqd->nr_ppas = nr_secs;
> -
> -       pblk_end_user_read(bio, rqd->error);
> -       __pblk_end_io_read(pblk, rqd, false);
> -}
> -
> -static int pblk_setup_partial_read(struct pblk *pblk, struct nvm_rq *rqd,
> -                           unsigned int bio_init_idx,
> -                           unsigned long *read_bitmap,
> -                           int nr_holes)
> -{
> -       void *meta_list = rqd->meta_list;
> -       struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd);
> -       struct pblk_pr_ctx *pr_ctx;
> -       struct bio *new_bio, *bio = r_ctx->private;
> -       int nr_secs = rqd->nr_ppas;
> -       int i;
> -
> -       new_bio = bio_alloc(GFP_KERNEL, nr_holes);
> -
> -       if (pblk_bio_add_pages(pblk, new_bio, GFP_KERNEL, nr_holes))
> -               goto fail_bio_put;
> -
> -       if (nr_holes != new_bio->bi_vcnt) {
> -               WARN_ONCE(1, "pblk: malformed bio\n");
> -               goto fail_free_pages;
> -       }
> -
> -       pr_ctx = kzalloc(sizeof(struct pblk_pr_ctx), GFP_KERNEL);
> -       if (!pr_ctx)
> -               goto fail_free_pages;
> -
> -       for (i = 0; i < nr_secs; i++) {
> -               struct pblk_sec_meta *meta = pblk_get_meta(pblk, meta_list, i);
> -
> -               pr_ctx->lba_list_mem[i] = le64_to_cpu(meta->lba);
> -       }
> -
> -       new_bio->bi_iter.bi_sector = 0; /* internal bio */
> -       bio_set_op_attrs(new_bio, REQ_OP_READ, 0);
> -
> -       rqd->bio = new_bio;
> -       rqd->nr_ppas = nr_holes;
> -
> -       pr_ctx->orig_bio = bio;
> -       bitmap_copy(pr_ctx->bitmap, read_bitmap, NVM_MAX_VLBA);
> -       pr_ctx->bio_init_idx = bio_init_idx;
> -       pr_ctx->orig_nr_secs = nr_secs;
> -       r_ctx->private = pr_ctx;
> -
> -       if (unlikely(nr_holes == 1)) {
> -               pr_ctx->ppa_ptr = rqd->ppa_list;
> -               pr_ctx->dma_ppa_list = rqd->dma_ppa_list;
> -               rqd->ppa_addr = rqd->ppa_list[0];
> -       }
> -       return 0;
> -
> -fail_free_pages:
> -       pblk_bio_free_pages(pblk, new_bio, 0, new_bio->bi_vcnt);
> -fail_bio_put:
> -       bio_put(new_bio);
> -
> -       return -ENOMEM;
> -}
> -
> -static int pblk_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd,
> -                                unsigned int bio_init_idx,
> -                                unsigned long *read_bitmap, int nr_secs)
> -{
> -       int nr_holes;
> -       int ret;
> -
> -       nr_holes = nr_secs - bitmap_weight(read_bitmap, nr_secs);
> -
> -       if (pblk_setup_partial_read(pblk, rqd, bio_init_idx, read_bitmap,
> -                                   nr_holes))
> -               return NVM_IO_ERR;
> -
> -       rqd->end_io = pblk_end_partial_read;
> -
> -       ret = pblk_submit_io(pblk, rqd);
> -       if (ret) {
> -               bio_put(rqd->bio);
> -               pblk_err(pblk, "partial read IO submission failed\n");
> -               goto err;
> -       }
> -
> -       return NVM_IO_OK;
> -
> -err:
> -       pblk_err(pblk, "failed to perform partial read\n");
> -
> -       /* Free allocated pages in new bio */
> -       pblk_bio_free_pages(pblk, rqd->bio, 0, rqd->bio->bi_vcnt);
> -       return NVM_IO_ERR;
> -}
> -
>  static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, struct bio *bio,
> -                        sector_t lba, unsigned long *read_bitmap)
> +                        sector_t lba, bool *from_cache)
>  {
>         struct pblk_sec_meta *meta = pblk_get_meta(pblk, rqd->meta_list, 0);
>         struct ppa_addr ppa;
>
> -       pblk_lookup_l2p_seq(pblk, &ppa, lba, 1);
> +       pblk_lookup_l2p_seq(pblk, &ppa, lba, 1, from_cache);
>
>  #ifdef CONFIG_NVM_PBLK_DEBUG
>         atomic_long_inc(&pblk->inflight_reads);
> @@ -409,7 +238,6 @@ static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, struct bio *bio,
>         if (pblk_ppa_empty(ppa)) {
>                 __le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
>
> -               WARN_ON(test_and_set_bit(0, read_bitmap));
>                 meta->lba = addr_empty;
>                 return;
>         }
> @@ -418,12 +246,11 @@ static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, struct bio *bio,
>          * write buffer to prevent retrieving overwritten data.
>          */
>         if (pblk_addr_in_cache(ppa)) {
> -               if (!pblk_read_from_cache(pblk, bio, lba, ppa, 0, 1)) {
> -                       pblk_lookup_l2p_seq(pblk, &ppa, lba, 1);
> +               if (!pblk_read_from_cache(pblk, bio, lba, ppa)) {
> +                       pblk_lookup_l2p_seq(pblk, &ppa, lba, 1, from_cache);
>                         goto retry;
>                 }
>
> -               WARN_ON(test_and_set_bit(0, read_bitmap));
>                 meta->lba = cpu_to_le64(lba);
>
>  #ifdef CONFIG_NVM_PBLK_DEBUG
> @@ -440,17 +267,14 @@ void pblk_submit_read(struct pblk *pblk, struct bio *bio)
>         struct request_queue *q = dev->q;
>         sector_t blba = pblk_get_lba(bio);
>         unsigned int nr_secs = pblk_get_secs(bio);
> +       bool from_cache;
>         struct pblk_g_ctx *r_ctx;
>         struct nvm_rq *rqd;
> -       struct bio *int_bio;
> -       unsigned int bio_init_idx;
> -       DECLARE_BITMAP(read_bitmap, NVM_MAX_VLBA);
> +       struct bio *int_bio, *split_bio;
>
>         generic_start_io_acct(q, REQ_OP_READ, bio_sectors(bio),
>                               &pblk->disk->part0);
>
> -       bitmap_zero(read_bitmap, nr_secs);
> -
>         rqd = pblk_alloc_rqd(pblk, PBLK_READ);
>
>         rqd->opcode = NVM_OP_PREAD;
> @@ -462,11 +286,6 @@ void pblk_submit_read(struct pblk *pblk, struct bio *bio)
>         r_ctx->start_time = jiffies;
>         r_ctx->lba = blba;
>
> -       /* Save the index for this bio's start. This is needed in case
> -        * we need to fill a partial read.
> -        */
> -       bio_init_idx = pblk_get_bi_idx(bio);
> -
>         if (pblk_alloc_rqd_meta(pblk, rqd)) {
>                 bio_io_error(bio);
>                 pblk_free_rqd(pblk, rqd, PBLK_READ);
> @@ -475,46 +294,58 @@ void pblk_submit_read(struct pblk *pblk, struct bio *bio)
>
>         /* Clone read bio to deal internally with:
>          * -read errors when reading from drive
> -        * -bio_advance() calls during l2p lookup and cache reads
> +        * -bio_advance() calls during cache reads
>          */
>         int_bio = bio_clone_fast(bio, GFP_KERNEL, &pblk_bio_set);
>
>         if (nr_secs > 1)
> -               pblk_read_ppalist_rq(pblk, rqd, bio, blba, read_bitmap);
> +               nr_secs = pblk_read_ppalist_rq(pblk, rqd, int_bio, blba,
> +                                               &from_cache);
>         else
> -               pblk_read_rq(pblk, rqd, bio, blba, read_bitmap);
> +               pblk_read_rq(pblk, rqd, int_bio, blba, &from_cache);
>
> +split_retry:
>         r_ctx->private = bio; /* original bio */
>         rqd->bio = int_bio; /* internal bio */
>
> -       if (bitmap_full(read_bitmap, nr_secs)) {
> +       if (from_cache && nr_secs == rqd->nr_ppas) {
> +               /* All data was read from cache, we can complete the IO. */
>                 pblk_end_user_read(bio, 0);
>                 atomic_inc(&pblk->inflight_io);
>                 __pblk_end_io_read(pblk, rqd, false);
> -               return;
> -       }
> -
> -       if (!bitmap_empty(read_bitmap, rqd->nr_ppas)) {
> +       } else if (nr_secs != rqd->nr_ppas) {
>                 /* The read bio request could be partially filled by the write
>                  * buffer, but there are some holes that need to be read from
> -                * the drive.
> +                * the drive. In order to handle this, we will use block layer
> +                * mechanism to split this request in to smaller ones and make
> +                * a chain of it.
>                  */
> -               bio_put(int_bio);
> -               rqd->bio = NULL;
> -               if (pblk_partial_read_bio(pblk, rqd, bio_init_idx, read_bitmap,
> -                                           nr_secs)) {
> -                       pblk_err(pblk, "read IO submission failed\n");
> -                       bio_io_error(bio);
> -                       __pblk_end_io_read(pblk, rqd, false);
> -               }
> -               return;
> -       }
> +               split_bio = bio_split(bio, nr_secs * NR_PHY_IN_LOG, GFP_KERNEL,
> +                                       &pblk_bio_set);
> +               bio_chain(split_bio, bio);
> +               generic_make_request(bio);
> +
> +               /* New bio contains first N sectors of the previous one, so
> +                * we can continue to use existing rqd, but we need to shrink
> +                * the number of PPAs in it. New bio is also guaranteed that
> +                * it contains only either data from cache or from drive, newer
> +                * mix of them.
> +                */
> +               bio = split_bio;
> +               rqd->nr_ppas = nr_secs;
> +               if (rqd->nr_ppas == 1)
> +                       rqd->ppa_addr = rqd->ppa_list[0];
>
> -       /* All sectors are to be read from the device */
> -       if (pblk_submit_io(pblk, rqd)) {
> -               pblk_err(pblk, "read IO submission failed\n");
> -               bio_io_error(bio);
> -               __pblk_end_io_read(pblk, rqd, false);
> +               /* Recreate int_bio - existing might have some needed internal
> +                * fields modified already.
> +                */
> +               bio_put(int_bio);
> +               int_bio = bio_clone_fast(bio, GFP_KERNEL, &pblk_bio_set);
> +               goto split_retry;
> +       } else if (pblk_submit_io(pblk, rqd)) {
> +               /* Submitting IO to drive failed, let's report an error */
> +               rqd->error = -ENODEV;
> +               pblk_end_io_read(rqd);
>         }
>  }
>
> diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
> index 17ced12..a678553 100644
> --- a/drivers/lightnvm/pblk.h
> +++ b/drivers/lightnvm/pblk.h
> @@ -121,18 +121,6 @@ struct pblk_g_ctx {
>         u64 lba;
>  };
>
> -/* partial read context */
> -struct pblk_pr_ctx {
> -       struct bio *orig_bio;
> -       DECLARE_BITMAP(bitmap, NVM_MAX_VLBA);
> -       unsigned int orig_nr_secs;
> -       unsigned int bio_init_idx;
> -       void *ppa_ptr;
> -       dma_addr_t dma_ppa_list;
> -       u64 lba_list_mem[NVM_MAX_VLBA];
> -       u64 lba_list_media[NVM_MAX_VLBA];
> -};
> -
>  /* Pad context */
>  struct pblk_pad_rq {
>         struct pblk *pblk;
> @@ -759,7 +747,7 @@ unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct nvm_rq *rqd,
>                                  unsigned int pos, unsigned int nr_entries,
>                                  unsigned int count);
>  int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
> -                       struct ppa_addr ppa, int bio_iter, bool advanced_bio);
> +                       struct ppa_addr ppa);
>  unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int entries);
>
>  unsigned int pblk_rb_sync_init(struct pblk_rb *rb, unsigned long *flags);
> @@ -859,8 +847,8 @@ int pblk_update_map_gc(struct pblk *pblk, sector_t lba, struct ppa_addr ppa,
>                        struct pblk_line *gc_line, u64 paddr);
>  void pblk_lookup_l2p_rand(struct pblk *pblk, struct ppa_addr *ppas,
>                           u64 *lba_list, int nr_secs);
> -void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
> -                        sector_t blba, int nr_secs);
> +int pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
> +                        sector_t blba, int nr_secs, bool *from_cache);
>  void *pblk_get_meta_for_writes(struct pblk *pblk, struct nvm_rq *rqd);
>  void pblk_get_packed_meta(struct pblk *pblk, struct nvm_rq *rqd);
>
> --
> 2.9.5
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v5 0/3] lightnvm: next set of improvements for 5.2
  2019-04-26 13:35 [PATCH v5 0/3] lightnvm: next set of improvements for 5.2 Igor Konopko
                   ` (2 preceding siblings ...)
  2019-04-26 13:35 ` [PATCH v5 3/3] lightnvm: pblk: store multiple copies of smeta Igor Konopko
@ 2019-04-26 19:53 ` Matias Bjørling
  2019-04-29 11:13   ` Hans Holmberg
  3 siblings, 1 reply; 9+ messages in thread
From: Matias Bjørling @ 2019-04-26 19:53 UTC (permalink / raw)
  To: Igor Konopko, javier, hans.holmberg; +Cc: linux-block

Thanks Igor. I've picked up 1 + 2.

The third I'm still noodling on. I think maybe one should bump the disk 
format, since it's changed. Also, if it is, it should be a static setup 
(i.e., 1,2,3), and not user configurable. Although, I do expect the 
separate parallel units to have enough device-side redundancy to provide 
adequate UBER.



On 4/26/19 3:35 PM, Igor Konopko wrote:
> This is another set of fixes and improvements to both pblk and lightnvm
> core.
> 
> Changes v4 -> v5:
> -dropped patches which were already pulled into for-5.2/core branch
> -rebasing of other patches
> -multiple copies of smeta patch moved into last position in series
> so it would be easier to pull only previous patches if needed
> 
> Changes v3 -> v4:
> -dropped patches which were already pulled into for-5.2/core branch
> -major changes for patch #2 based on code review
> -patch #6 modified to use krefs
> -new patch #7 which extends the patch #6
> 
> Changes v2 -> v3:
> -dropped some not needed patches
> -dropped patches which were already pulled into for-5.2/core branch
> -commit messages cleanup
> 
> Changes v1 -> v2:
> -dropped some not needed patches
> -review feedback incorporated for some of the patches
> -partial read path changes patch splited into two patches
> 
> 
> Igor Konopko (3):
>    lightnvm: pblk: simplify partial read path
>    lightnvm: pblk: use nvm_rq_to_ppa_list()
>    lightnvm: pblk: store multiple copies of smeta
> 
>   drivers/lightnvm/pblk-core.c     | 159 ++++++++++++++----
>   drivers/lightnvm/pblk-init.c     |  23 ++-
>   drivers/lightnvm/pblk-rb.c       |  11 +-
>   drivers/lightnvm/pblk-read.c     | 339 ++++++++++-----------------------------
>   drivers/lightnvm/pblk-recovery.c |  27 ++--
>   drivers/lightnvm/pblk-rl.c       |   3 +-
>   drivers/lightnvm/pblk.h          |  19 +--
>   7 files changed, 252 insertions(+), 329 deletions(-)
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v5 0/3] lightnvm: next set of improvements for 5.2
  2019-04-26 19:53 ` [PATCH v5 0/3] lightnvm: next set of improvements for 5.2 Matias Bjørling
@ 2019-04-29 11:13   ` Hans Holmberg
  2019-05-02 10:03     ` Igor Konopko
  0 siblings, 1 reply; 9+ messages in thread
From: Hans Holmberg @ 2019-04-29 11:13 UTC (permalink / raw)
  To: Matias Bjørling; +Cc: Igor Konopko, Javier González, linux-block

On Fri, Apr 26, 2019 at 3:54 PM Matias Bjørling <mb@lightnvm.io> wrote:
>
> Thanks Igor. I've picked up 1 + 2.
>
> The third I'm still noodling on. I think maybe one should bump the disk
> format, since it's changed. Also, if it is, it should be a static setup
> (i.e., 1,2,3), and not user configurable. Although, I do expect the
> separate parallel units to have enough device-side redundancy to provide
> adequate UBER.

The change is backwards- and forwards-compatible (a disk written with
both an older and a newer
kernel would be readable, since smeta sectors are marked as ADD_EMPTY)
 as far as I can tell,
buy did you test this Igor?

I think we might as well bump SMETA_VERSION_MINOR anyway, so we can keep
track of this format change for the future(i.e if we build an offline
recovery tool)

Thanks,
Hans
>
>
>
> On 4/26/19 3:35 PM, Igor Konopko wrote:
> > This is another set of fixes and improvements to both pblk and lightnvm
> > core.
> >
> > Changes v4 -> v5:
> > -dropped patches which were already pulled into for-5.2/core branch
> > -rebasing of other patches
> > -multiple copies of smeta patch moved into last position in series
> > so it would be easier to pull only previous patches if needed
> >
> > Changes v3 -> v4:
> > -dropped patches which were already pulled into for-5.2/core branch
> > -major changes for patch #2 based on code review
> > -patch #6 modified to use krefs
> > -new patch #7 which extends the patch #6
> >
> > Changes v2 -> v3:
> > -dropped some not needed patches
> > -dropped patches which were already pulled into for-5.2/core branch
> > -commit messages cleanup
> >
> > Changes v1 -> v2:
> > -dropped some not needed patches
> > -review feedback incorporated for some of the patches
> > -partial read path changes patch splited into two patches
> >
> >
> > Igor Konopko (3):
> >    lightnvm: pblk: simplify partial read path
> >    lightnvm: pblk: use nvm_rq_to_ppa_list()
> >    lightnvm: pblk: store multiple copies of smeta
> >
> >   drivers/lightnvm/pblk-core.c     | 159 ++++++++++++++----
> >   drivers/lightnvm/pblk-init.c     |  23 ++-
> >   drivers/lightnvm/pblk-rb.c       |  11 +-
> >   drivers/lightnvm/pblk-read.c     | 339 ++++++++++-----------------------------
> >   drivers/lightnvm/pblk-recovery.c |  27 ++--
> >   drivers/lightnvm/pblk-rl.c       |   3 +-
> >   drivers/lightnvm/pblk.h          |  19 +--
> >   7 files changed, 252 insertions(+), 329 deletions(-)
> >
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v5 1/3] lightnvm: pblk: simplify partial read path
  2019-04-26 13:35 ` [PATCH v5 1/3] lightnvm: pblk: simplify partial read path Igor Konopko
  2019-04-26 16:30   ` Heiner Litz
@ 2019-05-01  6:20   ` Javier González
  1 sibling, 0 replies; 9+ messages in thread
From: Javier González @ 2019-05-01  6:20 UTC (permalink / raw)
  To: Konopko, Igor J; +Cc: Matias Bjørling, Hans Holmberg, linux-block

[-- Attachment #1: Type: text/plain, Size: 20377 bytes --]

> On 26 Apr 2019, at 15.35, Igor Konopko <igor.j.konopko@intel.com> wrote:
> 
> This patch changes the approach to handling partial read path.
> 
> In old approach merging of data from round buffer and drive was fully
> made by drive. This had some disadvantages - code was complex and
> relies on bio internals, so it was hard to maintain and was strongly
> dependent on bio changes.
> 
> In new approach most of the handling is done mostly by block layer
> functions such as bio_split(), bio_chain() and generic_make request()
> and generally is less complex and easier to maintain. Below some more
> details of the new approach.
> 
> When read bio arrives, it is cloned for pblk internal purposes. All
> the L2P mapping, which includes copying data from round buffer to bio
> and thus bio_advance() calls is done on the cloned bio, so the original
> bio is untouched. If we found that we have partial read case, we
> still have original bio untouched, so we can split it and continue to
> process only first part of it in current context, when the rest will be
> called as separate bio request which is passed to generic_make_request()
> for further processing.
> 
> Signed-off-by: Igor Konopko <igor.j.konopko@intel.com>
> ---
> drivers/lightnvm/pblk-core.c |  13 +-
> drivers/lightnvm/pblk-rb.c   |  11 +-
> drivers/lightnvm/pblk-read.c | 339 +++++++++++--------------------------------
> drivers/lightnvm/pblk.h      |  18 +--
> 4 files changed, 100 insertions(+), 281 deletions(-)
> 
> diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
> index 73be3a0..07270ba 100644
> --- a/drivers/lightnvm/pblk-core.c
> +++ b/drivers/lightnvm/pblk-core.c
> @@ -2147,8 +2147,8 @@ void pblk_update_map_dev(struct pblk *pblk, sector_t lba,
> 	spin_unlock(&pblk->trans_lock);
> }
> 
> -void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
> -			 sector_t blba, int nr_secs)
> +int pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
> +			 sector_t blba, int nr_secs, bool *from_cache)
> {
> 	int i;
> 
> @@ -2162,10 +2162,19 @@ void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
> 		if (!pblk_ppa_empty(ppa) && !pblk_addr_in_cache(ppa)) {
> 			struct pblk_line *line = pblk_ppa_to_line(pblk, ppa);
> 
> +			if (i > 0 && *from_cache)
> +				break;
> +			*from_cache = false;
> +
> 			kref_get(&line->ref);
> +		} else {
> +			if (i > 0 && !*from_cache)
> +				break;
> +			*from_cache = true;
> 		}
> 	}
> 	spin_unlock(&pblk->trans_lock);
> +	return i;
> }
> 
> void pblk_lookup_l2p_rand(struct pblk *pblk, struct ppa_addr *ppas,
> diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c
> index 3555014..5abb170 100644
> --- a/drivers/lightnvm/pblk-rb.c
> +++ b/drivers/lightnvm/pblk-rb.c
> @@ -642,7 +642,7 @@ unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct nvm_rq *rqd,
>  * be directed to disk.
>  */
> int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
> -			struct ppa_addr ppa, int bio_iter, bool advanced_bio)
> +			struct ppa_addr ppa)
> {
> 	struct pblk *pblk = container_of(rb, struct pblk, rwb);
> 	struct pblk_rb_entry *entry;
> @@ -673,15 +673,6 @@ int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
> 		ret = 0;
> 		goto out;
> 	}
> -
> -	/* Only advance the bio if it hasn't been advanced already. If advanced,
> -	 * this bio is at least a partial bio (i.e., it has partially been
> -	 * filled with data from the cache). If part of the data resides on the
> -	 * media, we will read later on
> -	 */
> -	if (unlikely(!advanced_bio))
> -		bio_advance(bio, bio_iter * PBLK_EXPOSED_PAGE_SIZE);
> -
> 	data = bio_data(bio);
> 	memcpy(data, entry->data, rb->seg_size);
> 
> diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c
> index f5f155d..d98ea39 100644
> --- a/drivers/lightnvm/pblk-read.c
> +++ b/drivers/lightnvm/pblk-read.c
> @@ -26,8 +26,7 @@
>  * issued.
>  */
> static int pblk_read_from_cache(struct pblk *pblk, struct bio *bio,
> -				sector_t lba, struct ppa_addr ppa,
> -				int bio_iter, bool advanced_bio)
> +				sector_t lba, struct ppa_addr ppa)
> {
> #ifdef CONFIG_NVM_PBLK_DEBUG
> 	/* Callers must ensure that the ppa points to a cache address */
> @@ -35,73 +34,75 @@ static int pblk_read_from_cache(struct pblk *pblk, struct bio *bio,
> 	BUG_ON(!pblk_addr_in_cache(ppa));
> #endif
> 
> -	return pblk_rb_copy_to_bio(&pblk->rwb, bio, lba, ppa,
> -						bio_iter, advanced_bio);
> +	return pblk_rb_copy_to_bio(&pblk->rwb, bio, lba, ppa);
> }
> 
> -static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
> +static int pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
> 				 struct bio *bio, sector_t blba,
> -				 unsigned long *read_bitmap)
> +				 bool *from_cache)
> {
> 	void *meta_list = rqd->meta_list;
> -	struct ppa_addr ppas[NVM_MAX_VLBA];
> -	int nr_secs = rqd->nr_ppas;
> -	bool advanced_bio = false;
> -	int i, j = 0;
> +	int nr_secs, i;
> 
> -	pblk_lookup_l2p_seq(pblk, ppas, blba, nr_secs);
> +retry:
> +	nr_secs = pblk_lookup_l2p_seq(pblk, rqd->ppa_list, blba, rqd->nr_ppas,
> +					from_cache);
> +
> +	if (!*from_cache)
> +		goto end;
> 
> 	for (i = 0; i < nr_secs; i++) {
> -		struct ppa_addr p = ppas[i];
> 		struct pblk_sec_meta *meta = pblk_get_meta(pblk, meta_list, i);
> 		sector_t lba = blba + i;
> 
> -retry:
> -		if (pblk_ppa_empty(p)) {
> +		if (pblk_ppa_empty(rqd->ppa_list[i])) {
> 			__le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
> 
> -			WARN_ON(test_and_set_bit(i, read_bitmap));
> 			meta->lba = addr_empty;
> -
> -			if (unlikely(!advanced_bio)) {
> -				bio_advance(bio, (i) * PBLK_EXPOSED_PAGE_SIZE);
> -				advanced_bio = true;
> +		} else if (pblk_addr_in_cache(rqd->ppa_list[i])) {
> +			/*
> +			 * Try to read from write buffer. The address is later
> +			 * checked on the write buffer to prevent retrieving
> +			 * overwritten data.
> +			 */
> +			if (!pblk_read_from_cache(pblk, bio, lba,
> +							rqd->ppa_list[i])) {
> +				if (i == 0) {
> +					/*
> +					 * We didn't call with bio_advance()
> +					 * yet, so we can just retry.
> +					 */
> +					goto retry;
> +				} else {
> +					/*
> +					 * We already call bio_advance()
> +					 * so we cannot retry and we need
> +					 * to quit that function in order
> +					 * to allow caller to handle the bio
> +					 * splitting in the current sector
> +					 * position.
> +					 */
> +					nr_secs = i;
> +					goto end;
> +				}
> 			}
> -
> -			goto next;
> -		}
> -
> -		/* Try to read from write buffer. The address is later checked
> -		 * on the write buffer to prevent retrieving overwritten data.
> -		 */
> -		if (pblk_addr_in_cache(p)) {
> -			if (!pblk_read_from_cache(pblk, bio, lba, p, i,
> -								advanced_bio)) {
> -				pblk_lookup_l2p_seq(pblk, &p, lba, 1);
> -				goto retry;
> -			}
> -			WARN_ON(test_and_set_bit(i, read_bitmap));
> 			meta->lba = cpu_to_le64(lba);
> -			advanced_bio = true;
> #ifdef CONFIG_NVM_PBLK_DEBUG
> 			atomic_long_inc(&pblk->cache_reads);
> #endif
> -		} else {
> -			/* Read from media non-cached sectors */
> -			rqd->ppa_list[j++] = p;
> 		}
> -
> -next:
> -		if (advanced_bio)
> -			bio_advance(bio, PBLK_EXPOSED_PAGE_SIZE);
> +		bio_advance(bio, PBLK_EXPOSED_PAGE_SIZE);
> 	}
> 
> +end:
> 	if (pblk_io_aligned(pblk, nr_secs))
> 		rqd->is_seq = 1;
> 
> #ifdef CONFIG_NVM_PBLK_DEBUG
> 	atomic_long_add(nr_secs, &pblk->inflight_reads);
> #endif
> +
> +	return nr_secs;
> }
> 
> 
> @@ -197,9 +198,7 @@ static void __pblk_end_io_read(struct pblk *pblk, struct nvm_rq *rqd,
> 		pblk_log_read_err(pblk, rqd);
> 
> 	pblk_read_check_seq(pblk, rqd, r_ctx->lba);
> -
> -	if (int_bio)
> -		bio_put(int_bio);
> +	bio_put(int_bio);
> 
> 	if (put_line)
> 		pblk_rq_to_line_put(pblk, rqd);
> @@ -223,183 +222,13 @@ static void pblk_end_io_read(struct nvm_rq *rqd)
> 	__pblk_end_io_read(pblk, rqd, true);
> }
> 
> -static void pblk_end_partial_read(struct nvm_rq *rqd)
> -{
> -	struct pblk *pblk = rqd->private;
> -	struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd);
> -	struct pblk_pr_ctx *pr_ctx = r_ctx->private;
> -	struct pblk_sec_meta *meta;
> -	struct bio *new_bio = rqd->bio;
> -	struct bio *bio = pr_ctx->orig_bio;
> -	void *meta_list = rqd->meta_list;
> -	unsigned long *read_bitmap = pr_ctx->bitmap;
> -	struct bvec_iter orig_iter = BVEC_ITER_ALL_INIT;
> -	struct bvec_iter new_iter = BVEC_ITER_ALL_INIT;
> -	int nr_secs = pr_ctx->orig_nr_secs;
> -	int nr_holes = nr_secs - bitmap_weight(read_bitmap, nr_secs);
> -	void *src_p, *dst_p;
> -	int bit, i;
> -
> -	if (unlikely(nr_holes == 1)) {
> -		struct ppa_addr ppa;
> -
> -		ppa = rqd->ppa_addr;
> -		rqd->ppa_list = pr_ctx->ppa_ptr;
> -		rqd->dma_ppa_list = pr_ctx->dma_ppa_list;
> -		rqd->ppa_list[0] = ppa;
> -	}
> -
> -	for (i = 0; i < nr_secs; i++) {
> -		meta = pblk_get_meta(pblk, meta_list, i);
> -		pr_ctx->lba_list_media[i] = le64_to_cpu(meta->lba);
> -		meta->lba = cpu_to_le64(pr_ctx->lba_list_mem[i]);
> -	}
> -
> -	/* Fill the holes in the original bio */
> -	i = 0;
> -	for (bit = 0; bit < nr_secs; bit++) {
> -		if (!test_bit(bit, read_bitmap)) {
> -			struct bio_vec dst_bv, src_bv;
> -			struct pblk_line *line;
> -
> -			line = pblk_ppa_to_line(pblk, rqd->ppa_list[i]);
> -			kref_put(&line->ref, pblk_line_put);
> -
> -			meta = pblk_get_meta(pblk, meta_list, bit);
> -			meta->lba = cpu_to_le64(pr_ctx->lba_list_media[i]);
> -
> -			dst_bv = bio_iter_iovec(bio, orig_iter);
> -			src_bv = bio_iter_iovec(new_bio, new_iter);
> -
> -			src_p = kmap_atomic(src_bv.bv_page);
> -			dst_p = kmap_atomic(dst_bv.bv_page);
> -
> -			memcpy(dst_p + dst_bv.bv_offset,
> -				src_p + src_bv.bv_offset,
> -				PBLK_EXPOSED_PAGE_SIZE);
> -
> -			kunmap_atomic(src_p);
> -			kunmap_atomic(dst_p);
> -
> -			flush_dcache_page(dst_bv.bv_page);
> -			mempool_free(src_bv.bv_page, &pblk->page_bio_pool);
> -
> -			bio_advance_iter(new_bio, &new_iter,
> -					PBLK_EXPOSED_PAGE_SIZE);
> -			i++;
> -		}
> -		bio_advance_iter(bio, &orig_iter, PBLK_EXPOSED_PAGE_SIZE);
> -	}
> -
> -	bio_put(new_bio);
> -	kfree(pr_ctx);
> -
> -	/* restore original request */
> -	rqd->bio = NULL;
> -	rqd->nr_ppas = nr_secs;
> -
> -	pblk_end_user_read(bio, rqd->error);
> -	__pblk_end_io_read(pblk, rqd, false);
> -}
> -
> -static int pblk_setup_partial_read(struct pblk *pblk, struct nvm_rq *rqd,
> -			    unsigned int bio_init_idx,
> -			    unsigned long *read_bitmap,
> -			    int nr_holes)
> -{
> -	void *meta_list = rqd->meta_list;
> -	struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd);
> -	struct pblk_pr_ctx *pr_ctx;
> -	struct bio *new_bio, *bio = r_ctx->private;
> -	int nr_secs = rqd->nr_ppas;
> -	int i;
> -
> -	new_bio = bio_alloc(GFP_KERNEL, nr_holes);
> -
> -	if (pblk_bio_add_pages(pblk, new_bio, GFP_KERNEL, nr_holes))
> -		goto fail_bio_put;
> -
> -	if (nr_holes != new_bio->bi_vcnt) {
> -		WARN_ONCE(1, "pblk: malformed bio\n");
> -		goto fail_free_pages;
> -	}
> -
> -	pr_ctx = kzalloc(sizeof(struct pblk_pr_ctx), GFP_KERNEL);
> -	if (!pr_ctx)
> -		goto fail_free_pages;
> -
> -	for (i = 0; i < nr_secs; i++) {
> -		struct pblk_sec_meta *meta = pblk_get_meta(pblk, meta_list, i);
> -
> -		pr_ctx->lba_list_mem[i] = le64_to_cpu(meta->lba);
> -	}
> -
> -	new_bio->bi_iter.bi_sector = 0; /* internal bio */
> -	bio_set_op_attrs(new_bio, REQ_OP_READ, 0);
> -
> -	rqd->bio = new_bio;
> -	rqd->nr_ppas = nr_holes;
> -
> -	pr_ctx->orig_bio = bio;
> -	bitmap_copy(pr_ctx->bitmap, read_bitmap, NVM_MAX_VLBA);
> -	pr_ctx->bio_init_idx = bio_init_idx;
> -	pr_ctx->orig_nr_secs = nr_secs;
> -	r_ctx->private = pr_ctx;
> -
> -	if (unlikely(nr_holes == 1)) {
> -		pr_ctx->ppa_ptr = rqd->ppa_list;
> -		pr_ctx->dma_ppa_list = rqd->dma_ppa_list;
> -		rqd->ppa_addr = rqd->ppa_list[0];
> -	}
> -	return 0;
> -
> -fail_free_pages:
> -	pblk_bio_free_pages(pblk, new_bio, 0, new_bio->bi_vcnt);
> -fail_bio_put:
> -	bio_put(new_bio);
> -
> -	return -ENOMEM;
> -}
> -
> -static int pblk_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd,
> -				 unsigned int bio_init_idx,
> -				 unsigned long *read_bitmap, int nr_secs)
> -{
> -	int nr_holes;
> -	int ret;
> -
> -	nr_holes = nr_secs - bitmap_weight(read_bitmap, nr_secs);
> -
> -	if (pblk_setup_partial_read(pblk, rqd, bio_init_idx, read_bitmap,
> -				    nr_holes))
> -		return NVM_IO_ERR;
> -
> -	rqd->end_io = pblk_end_partial_read;
> -
> -	ret = pblk_submit_io(pblk, rqd);
> -	if (ret) {
> -		bio_put(rqd->bio);
> -		pblk_err(pblk, "partial read IO submission failed\n");
> -		goto err;
> -	}
> -
> -	return NVM_IO_OK;
> -
> -err:
> -	pblk_err(pblk, "failed to perform partial read\n");
> -
> -	/* Free allocated pages in new bio */
> -	pblk_bio_free_pages(pblk, rqd->bio, 0, rqd->bio->bi_vcnt);
> -	return NVM_IO_ERR;
> -}
> -
> static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, struct bio *bio,
> -			 sector_t lba, unsigned long *read_bitmap)
> +			 sector_t lba, bool *from_cache)
> {
> 	struct pblk_sec_meta *meta = pblk_get_meta(pblk, rqd->meta_list, 0);
> 	struct ppa_addr ppa;
> 
> -	pblk_lookup_l2p_seq(pblk, &ppa, lba, 1);
> +	pblk_lookup_l2p_seq(pblk, &ppa, lba, 1, from_cache);
> 
> #ifdef CONFIG_NVM_PBLK_DEBUG
> 	atomic_long_inc(&pblk->inflight_reads);
> @@ -409,7 +238,6 @@ static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, struct bio *bio,
> 	if (pblk_ppa_empty(ppa)) {
> 		__le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
> 
> -		WARN_ON(test_and_set_bit(0, read_bitmap));
> 		meta->lba = addr_empty;
> 		return;
> 	}
> @@ -418,12 +246,11 @@ static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, struct bio *bio,
> 	 * write buffer to prevent retrieving overwritten data.
> 	 */
> 	if (pblk_addr_in_cache(ppa)) {
> -		if (!pblk_read_from_cache(pblk, bio, lba, ppa, 0, 1)) {
> -			pblk_lookup_l2p_seq(pblk, &ppa, lba, 1);
> +		if (!pblk_read_from_cache(pblk, bio, lba, ppa)) {
> +			pblk_lookup_l2p_seq(pblk, &ppa, lba, 1, from_cache);
> 			goto retry;
> 		}
> 
> -		WARN_ON(test_and_set_bit(0, read_bitmap));
> 		meta->lba = cpu_to_le64(lba);
> 
> #ifdef CONFIG_NVM_PBLK_DEBUG
> @@ -440,17 +267,14 @@ void pblk_submit_read(struct pblk *pblk, struct bio *bio)
> 	struct request_queue *q = dev->q;
> 	sector_t blba = pblk_get_lba(bio);
> 	unsigned int nr_secs = pblk_get_secs(bio);
> +	bool from_cache;
> 	struct pblk_g_ctx *r_ctx;
> 	struct nvm_rq *rqd;
> -	struct bio *int_bio;
> -	unsigned int bio_init_idx;
> -	DECLARE_BITMAP(read_bitmap, NVM_MAX_VLBA);
> +	struct bio *int_bio, *split_bio;
> 
> 	generic_start_io_acct(q, REQ_OP_READ, bio_sectors(bio),
> 			      &pblk->disk->part0);
> 
> -	bitmap_zero(read_bitmap, nr_secs);
> -
> 	rqd = pblk_alloc_rqd(pblk, PBLK_READ);
> 
> 	rqd->opcode = NVM_OP_PREAD;
> @@ -462,11 +286,6 @@ void pblk_submit_read(struct pblk *pblk, struct bio *bio)
> 	r_ctx->start_time = jiffies;
> 	r_ctx->lba = blba;
> 
> -	/* Save the index for this bio's start. This is needed in case
> -	 * we need to fill a partial read.
> -	 */
> -	bio_init_idx = pblk_get_bi_idx(bio);
> -
> 	if (pblk_alloc_rqd_meta(pblk, rqd)) {
> 		bio_io_error(bio);
> 		pblk_free_rqd(pblk, rqd, PBLK_READ);
> @@ -475,46 +294,58 @@ void pblk_submit_read(struct pblk *pblk, struct bio *bio)
> 
> 	/* Clone read bio to deal internally with:
> 	 * -read errors when reading from drive
> -	 * -bio_advance() calls during l2p lookup and cache reads
> +	 * -bio_advance() calls during cache reads
> 	 */
> 	int_bio = bio_clone_fast(bio, GFP_KERNEL, &pblk_bio_set);
> 
> 	if (nr_secs > 1)
> -		pblk_read_ppalist_rq(pblk, rqd, bio, blba, read_bitmap);
> +		nr_secs = pblk_read_ppalist_rq(pblk, rqd, int_bio, blba,
> +						&from_cache);
> 	else
> -		pblk_read_rq(pblk, rqd, bio, blba, read_bitmap);
> +		pblk_read_rq(pblk, rqd, int_bio, blba, &from_cache);
> 
> +split_retry:
> 	r_ctx->private = bio; /* original bio */
> 	rqd->bio = int_bio; /* internal bio */
> 
> -	if (bitmap_full(read_bitmap, nr_secs)) {
> +	if (from_cache && nr_secs == rqd->nr_ppas) {
> +		/* All data was read from cache, we can complete the IO. */
> 		pblk_end_user_read(bio, 0);
> 		atomic_inc(&pblk->inflight_io);
> 		__pblk_end_io_read(pblk, rqd, false);
> -		return;
> -	}
> -
> -	if (!bitmap_empty(read_bitmap, rqd->nr_ppas)) {
> +	} else if (nr_secs != rqd->nr_ppas) {
> 		/* The read bio request could be partially filled by the write
> 		 * buffer, but there are some holes that need to be read from
> -		 * the drive.
> +		 * the drive. In order to handle this, we will use block layer
> +		 * mechanism to split this request in to smaller ones and make
> +		 * a chain of it.
> 		 */
> -		bio_put(int_bio);
> -		rqd->bio = NULL;
> -		if (pblk_partial_read_bio(pblk, rqd, bio_init_idx, read_bitmap,
> -					    nr_secs)) {
> -			pblk_err(pblk, "read IO submission failed\n");
> -			bio_io_error(bio);
> -			__pblk_end_io_read(pblk, rqd, false);
> -		}
> -		return;
> -	}
> +		split_bio = bio_split(bio, nr_secs * NR_PHY_IN_LOG, GFP_KERNEL,
> +					&pblk_bio_set);
> +		bio_chain(split_bio, bio);
> +		generic_make_request(bio);
> +
> +		/* New bio contains first N sectors of the previous one, so
> +		 * we can continue to use existing rqd, but we need to shrink
> +		 * the number of PPAs in it. New bio is also guaranteed that
> +		 * it contains only either data from cache or from drive, newer
> +		 * mix of them.
> +		 */
> +		bio = split_bio;
> +		rqd->nr_ppas = nr_secs;
> +		if (rqd->nr_ppas == 1)
> +			rqd->ppa_addr = rqd->ppa_list[0];
> 
> -	/* All sectors are to be read from the device */
> -	if (pblk_submit_io(pblk, rqd)) {
> -		pblk_err(pblk, "read IO submission failed\n");
> -		bio_io_error(bio);
> -		__pblk_end_io_read(pblk, rqd, false);
> +		/* Recreate int_bio - existing might have some needed internal
> +		 * fields modified already.
> +		 */
> +		bio_put(int_bio);
> +		int_bio = bio_clone_fast(bio, GFP_KERNEL, &pblk_bio_set);
> +		goto split_retry;
> +	} else if (pblk_submit_io(pblk, rqd)) {
> +		/* Submitting IO to drive failed, let's report an error */
> +		rqd->error = -ENODEV;
> +		pblk_end_io_read(rqd);
> 	}
> }
> 
> diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
> index 17ced12..a678553 100644
> --- a/drivers/lightnvm/pblk.h
> +++ b/drivers/lightnvm/pblk.h
> @@ -121,18 +121,6 @@ struct pblk_g_ctx {
> 	u64 lba;
> };
> 
> -/* partial read context */
> -struct pblk_pr_ctx {
> -	struct bio *orig_bio;
> -	DECLARE_BITMAP(bitmap, NVM_MAX_VLBA);
> -	unsigned int orig_nr_secs;
> -	unsigned int bio_init_idx;
> -	void *ppa_ptr;
> -	dma_addr_t dma_ppa_list;
> -	u64 lba_list_mem[NVM_MAX_VLBA];
> -	u64 lba_list_media[NVM_MAX_VLBA];
> -};
> -
> /* Pad context */
> struct pblk_pad_rq {
> 	struct pblk *pblk;
> @@ -759,7 +747,7 @@ unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct nvm_rq *rqd,
> 				 unsigned int pos, unsigned int nr_entries,
> 				 unsigned int count);
> int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
> -			struct ppa_addr ppa, int bio_iter, bool advanced_bio);
> +			struct ppa_addr ppa);
> unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int entries);
> 
> unsigned int pblk_rb_sync_init(struct pblk_rb *rb, unsigned long *flags);
> @@ -859,8 +847,8 @@ int pblk_update_map_gc(struct pblk *pblk, sector_t lba, struct ppa_addr ppa,
> 		       struct pblk_line *gc_line, u64 paddr);
> void pblk_lookup_l2p_rand(struct pblk *pblk, struct ppa_addr *ppas,
> 			  u64 *lba_list, int nr_secs);
> -void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
> -			 sector_t blba, int nr_secs);
> +int pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
> +			 sector_t blba, int nr_secs, bool *from_cache);
> void *pblk_get_meta_for_writes(struct pblk *pblk, struct nvm_rq *rqd);
> void pblk_get_packed_meta(struct pblk *pblk, struct nvm_rq *rqd);
> 
> --
> 2.9.5

It looks good to me. Thanks for this Igor!

Reviewed-by: Javier González <javier@javigon.com>


[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v5 0/3] lightnvm: next set of improvements for 5.2
  2019-04-29 11:13   ` Hans Holmberg
@ 2019-05-02 10:03     ` Igor Konopko
  0 siblings, 0 replies; 9+ messages in thread
From: Igor Konopko @ 2019-05-02 10:03 UTC (permalink / raw)
  To: Hans Holmberg, Matias Bjørling; +Cc: Javier González, linux-block



On 29.04.2019 13:13, Hans Holmberg wrote:
> On Fri, Apr 26, 2019 at 3:54 PM Matias Bjørling <mb@lightnvm.io> wrote:
>>
>> Thanks Igor. I've picked up 1 + 2.
>>
>> The third I'm still noodling on. I think maybe one should bump the disk
>> format, since it's changed. Also, if it is, it should be a static setup
>> (i.e., 1,2,3), and not user configurable. Although, I do expect the
>> separate parallel units to have enough device-side redundancy to provide
>> adequate UBER.
> 
> The change is backwards- and forwards-compatible (a disk written with
> both an older and a newer
> kernel would be readable, since smeta sectors are marked as ADD_EMPTY)
>   as far as I can tell,
> buy did you test this Igor?

It suppose to work, but I didn't test such a scenario. Generally this 
patch is not so crucial for now, so I can tune it up for 5.3 maybe.
> 
> I think we might as well bump SMETA_VERSION_MINOR anyway, so we can keep
> track of this format change for the future(i.e if we build an offline
> recovery tool)
> 
> Thanks,
> Hans
>>
>>
>>
>> On 4/26/19 3:35 PM, Igor Konopko wrote:
>>> This is another set of fixes and improvements to both pblk and lightnvm
>>> core.
>>>
>>> Changes v4 -> v5:
>>> -dropped patches which were already pulled into for-5.2/core branch
>>> -rebasing of other patches
>>> -multiple copies of smeta patch moved into last position in series
>>> so it would be easier to pull only previous patches if needed
>>>
>>> Changes v3 -> v4:
>>> -dropped patches which were already pulled into for-5.2/core branch
>>> -major changes for patch #2 based on code review
>>> -patch #6 modified to use krefs
>>> -new patch #7 which extends the patch #6
>>>
>>> Changes v2 -> v3:
>>> -dropped some not needed patches
>>> -dropped patches which were already pulled into for-5.2/core branch
>>> -commit messages cleanup
>>>
>>> Changes v1 -> v2:
>>> -dropped some not needed patches
>>> -review feedback incorporated for some of the patches
>>> -partial read path changes patch splited into two patches
>>>
>>>
>>> Igor Konopko (3):
>>>     lightnvm: pblk: simplify partial read path
>>>     lightnvm: pblk: use nvm_rq_to_ppa_list()
>>>     lightnvm: pblk: store multiple copies of smeta
>>>
>>>    drivers/lightnvm/pblk-core.c     | 159 ++++++++++++++----
>>>    drivers/lightnvm/pblk-init.c     |  23 ++-
>>>    drivers/lightnvm/pblk-rb.c       |  11 +-
>>>    drivers/lightnvm/pblk-read.c     | 339 ++++++++++-----------------------------
>>>    drivers/lightnvm/pblk-recovery.c |  27 ++--
>>>    drivers/lightnvm/pblk-rl.c       |   3 +-
>>>    drivers/lightnvm/pblk.h          |  19 +--
>>>    7 files changed, 252 insertions(+), 329 deletions(-)
>>>
>>

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-05-02 10:03 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-26 13:35 [PATCH v5 0/3] lightnvm: next set of improvements for 5.2 Igor Konopko
2019-04-26 13:35 ` [PATCH v5 1/3] lightnvm: pblk: simplify partial read path Igor Konopko
2019-04-26 16:30   ` Heiner Litz
2019-05-01  6:20   ` Javier González
2019-04-26 13:35 ` [PATCH v5 2/3] lightnvm: pblk: use nvm_rq_to_ppa_list() Igor Konopko
2019-04-26 13:35 ` [PATCH v5 3/3] lightnvm: pblk: store multiple copies of smeta Igor Konopko
2019-04-26 19:53 ` [PATCH v5 0/3] lightnvm: next set of improvements for 5.2 Matias Bjørling
2019-04-29 11:13   ` Hans Holmberg
2019-05-02 10:03     ` Igor Konopko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).