aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@linux.intel.com>2018-10-10 19:39:35 -0400
committerDan Williams <dan.j.williams@intel.com>2018-10-12 11:39:31 -0400
commit7d47aad4570e5e6e9a8162bb417ca9b74132f27c (patch)
treed3ced75bf26076e6be01c513f7fdfe22de5a6f1f
parent2d657d17f72d2ae70c02f0d0ea6a04ad0f016b57 (diff)
nvdimm: Use namespace index data to reduce number of label reads needed
This patch adds logic that is meant to make use of the namespace index data to reduce the number of reads that are needed to initialize a given namespace. The general idea is that once we have enough data to validate the namespace index we do so and then proceed to fetch only those labels that are not listed as being "free". By doing this I am seeing a total time reduction from about 4-5 seconds to 2-3 seconds for 24 NVDIMM modules each with 128K of label config area. Reviewed-by: Toshi Kani <toshi.kani@hpe.com> Signed-off-by: Alexander Duyck <alexander.h.duyck@linux.intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--drivers/nvdimm/dimm.c4
-rw-r--r--drivers/nvdimm/label.c93
-rw-r--r--drivers/nvdimm/label.h3
3 files changed, 88 insertions, 12 deletions
diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c
index 07bf96948553..9899c97138a3 100644
--- a/drivers/nvdimm/dimm.c
+++ b/drivers/nvdimm/dimm.c
@@ -84,10 +84,6 @@ static int nvdimm_probe(struct device *dev)
84 dev_dbg(dev, "config data size: %d\n", ndd->nsarea.config_size); 84 dev_dbg(dev, "config data size: %d\n", ndd->nsarea.config_size);
85 85
86 nvdimm_bus_lock(dev); 86 nvdimm_bus_lock(dev);
87 ndd->ns_current = nd_label_validate(ndd);
88 ndd->ns_next = nd_label_next_nsindex(ndd->ns_current);
89 nd_label_copy(ndd, to_next_namespace_index(ndd),
90 to_current_namespace_index(ndd));
91 if (ndd->ns_current >= 0) { 87 if (ndd->ns_current >= 0) {
92 rc = nd_label_reserve_dpa(ndd); 88 rc = nd_label_reserve_dpa(ndd);
93 if (rc == 0) 89 if (rc == 0)
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 563f24af01b5..7f03d117824f 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -235,7 +235,7 @@ static int __nd_label_validate(struct nvdimm_drvdata *ndd)
235 return -1; 235 return -1;
236} 236}
237 237
238int nd_label_validate(struct nvdimm_drvdata *ndd) 238static int nd_label_validate(struct nvdimm_drvdata *ndd)
239{ 239{
240 /* 240 /*
241 * In order to probe for and validate namespace index blocks we 241 * In order to probe for and validate namespace index blocks we
@@ -258,8 +258,9 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
258 return -1; 258 return -1;
259} 259}
260 260
261void nd_label_copy(struct nvdimm_drvdata *ndd, struct nd_namespace_index *dst, 261static void nd_label_copy(struct nvdimm_drvdata *ndd,
262 struct nd_namespace_index *src) 262 struct nd_namespace_index *dst,
263 struct nd_namespace_index *src)
263{ 264{
264 /* just exit if either destination or source is NULL */ 265 /* just exit if either destination or source is NULL */
265 if (!dst || !src) 266 if (!dst || !src)
@@ -419,7 +420,9 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd)
419 420
420int nd_label_data_init(struct nvdimm_drvdata *ndd) 421int nd_label_data_init(struct nvdimm_drvdata *ndd)
421{ 422{
422 size_t config_size, read_size; 423 size_t config_size, read_size, max_xfer, offset;
424 struct nd_namespace_index *nsindex;
425 unsigned int i;
423 int rc = 0; 426 int rc = 0;
424 427
425 if (ndd->data) 428 if (ndd->data)
@@ -452,7 +455,87 @@ int nd_label_data_init(struct nvdimm_drvdata *ndd)
452 if (!ndd->data) 455 if (!ndd->data)
453 return -ENOMEM; 456 return -ENOMEM;
454 457
455 return nvdimm_get_config_data(ndd, ndd->data, 0, config_size); 458 /*
459 * We want to guarantee as few reads as possible while conserving
460 * memory. To do that we figure out how much unused space will be left
461 * in the last read, divide that by the total number of reads it is
462 * going to take given our maximum transfer size, and then reduce our
463 * maximum transfer size based on that result.
464 */
465 max_xfer = min_t(size_t, ndd->nsarea.max_xfer, config_size);
466 if (read_size < max_xfer) {
467 /* trim waste */
468 max_xfer -= ((max_xfer - 1) - (config_size - 1) % max_xfer) /
469 DIV_ROUND_UP(config_size, max_xfer);
470 /* make certain we read indexes in exactly 1 read */
471 if (max_xfer < read_size)
472 max_xfer = read_size;
473 }
474
475 /* Make our initial read size a multiple of max_xfer size */
476 read_size = min(DIV_ROUND_UP(read_size, max_xfer) * max_xfer,
477 config_size);
478
479 /* Read the index data */
480 rc = nvdimm_get_config_data(ndd, ndd->data, 0, read_size);
481 if (rc)
482 goto out_err;
483
484 /* Validate index data, if not valid assume all labels are invalid */
485 ndd->ns_current = nd_label_validate(ndd);
486 if (ndd->ns_current < 0)
487 return 0;
488
489 /* Record our index values */
490 ndd->ns_next = nd_label_next_nsindex(ndd->ns_current);
491
492 /* Copy "current" index on top of the "next" index */
493 nsindex = to_current_namespace_index(ndd);
494 nd_label_copy(ndd, to_next_namespace_index(ndd), nsindex);
495
496 /* Determine starting offset for label data */
497 offset = __le64_to_cpu(nsindex->labeloff);
498
499 /* Loop through the free list pulling in any active labels */
500 for (i = 0; i < nsindex->nslot; i++, offset += ndd->nslabel_size) {
501 size_t label_read_size;
502
503 /* zero out the unused labels */
504 if (test_bit_le(i, nsindex->free)) {
505 memset(ndd->data + offset, 0, ndd->nslabel_size);
506 continue;
507 }
508
509 /* if we already read past here then just continue */
510 if (offset + ndd->nslabel_size <= read_size)
511 continue;
512
513 /* if we haven't read in a while reset our read_size offset */
514 if (read_size < offset)
515 read_size = offset;
516
517 /* determine how much more will be read after this next call. */
518 label_read_size = offset + ndd->nslabel_size - read_size;
519 label_read_size = DIV_ROUND_UP(label_read_size, max_xfer) *
520 max_xfer;
521
522 /* truncate last read if needed */
523 if (read_size + label_read_size > config_size)
524 label_read_size = config_size - read_size;
525
526 /* Read the label data */
527 rc = nvdimm_get_config_data(ndd, ndd->data + read_size,
528 read_size, label_read_size);
529 if (rc)
530 goto out_err;
531
532 /* push read_size to next read offset */
533 read_size += label_read_size;
534 }
535
536 dev_dbg(ndd->dev, "len: %zu rc: %d\n", offset, rc);
537out_err:
538 return rc;
456} 539}
457 540
458int nd_label_active_count(struct nvdimm_drvdata *ndd) 541int nd_label_active_count(struct nvdimm_drvdata *ndd)
diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h
index 685afb3de0fe..e9a2ad3c2150 100644
--- a/drivers/nvdimm/label.h
+++ b/drivers/nvdimm/label.h
@@ -138,9 +138,6 @@ static inline int nd_label_next_nsindex(int index)
138} 138}
139 139
140struct nvdimm_drvdata; 140struct nvdimm_drvdata;
141int nd_label_validate(struct nvdimm_drvdata *ndd);
142void nd_label_copy(struct nvdimm_drvdata *ndd, struct nd_namespace_index *dst,
143 struct nd_namespace_index *src);
144int nd_label_data_init(struct nvdimm_drvdata *ndd); 141int nd_label_data_init(struct nvdimm_drvdata *ndd);
145size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd); 142size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd);
146int nd_label_active_count(struct nvdimm_drvdata *ndd); 143int nd_label_active_count(struct nvdimm_drvdata *ndd);