Skip to content

Commit 762d067

Browse files
committed
libnvdimm, namespace: enable allocation of multiple pmem namespaces
Now that we have nd_region_available_dpa() able to handle the presence of multiple PMEM allocations in aliased PMEM regions, reuse that same infrastructure to track allocations from free space. In particular handle allocating from an aliased PMEM region in the case where there are dis-contiguous holes. The allocation for BLK and PMEM are documented in the space_valid() helper: BLK-space is valid as long as it does not precede a PMEM allocation in a given region. PMEM-space must be contiguous and adjacent to an existing existing allocation (if one exists). Signed-off-by: Dan Williams <[email protected]>
1 parent 16660ea commit 762d067

File tree

3 files changed

+133
-45
lines changed

3 files changed

+133
-45
lines changed

drivers/nvdimm/dimm_devs.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -386,13 +386,7 @@ struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,
386386
}
387387
EXPORT_SYMBOL_GPL(nvdimm_create);
388388

389-
struct blk_alloc_info {
390-
struct nd_mapping *nd_mapping;
391-
resource_size_t available, busy;
392-
struct resource *res;
393-
};
394-
395-
static int alias_dpa_busy(struct device *dev, void *data)
389+
int alias_dpa_busy(struct device *dev, void *data)
396390
{
397391
resource_size_t map_end, blk_start, new, busy;
398392
struct blk_alloc_info *info = data;
@@ -418,6 +412,20 @@ static int alias_dpa_busy(struct device *dev, void *data)
418412
ndd = to_ndd(nd_mapping);
419413
map_end = nd_mapping->start + nd_mapping->size - 1;
420414
blk_start = nd_mapping->start;
415+
416+
/*
417+
* In the allocation case ->res is set to free space that we are
418+
* looking to validate against PMEM aliasing collision rules
419+
* (i.e. BLK is allocated after all aliased PMEM).
420+
*/
421+
if (info->res) {
422+
if (info->res->start >= nd_mapping->start
423+
&& info->res->start < map_end)
424+
/* pass */;
425+
else
426+
return 0;
427+
}
428+
421429
retry:
422430
/*
423431
* Find the free dpa from the end of the last pmem allocation to
@@ -447,7 +455,16 @@ static int alias_dpa_busy(struct device *dev, void *data)
447455
}
448456
}
449457

458+
/* update the free space range with the probed blk_start */
459+
if (info->res && blk_start > info->res->start) {
460+
info->res->start = max(info->res->start, blk_start);
461+
if (info->res->start > info->res->end)
462+
info->res->end = info->res->start - 1;
463+
return 1;
464+
}
465+
450466
info->available -= blk_start - nd_mapping->start + busy;
467+
451468
return 0;
452469
}
453470

@@ -508,6 +525,7 @@ resource_size_t nd_blk_available_dpa(struct nd_region *nd_region)
508525
struct blk_alloc_info info = {
509526
.nd_mapping = nd_mapping,
510527
.available = nd_mapping->size,
528+
.res = NULL,
511529
};
512530
struct resource *res;
513531

drivers/nvdimm/namespace_devs.c

Lines changed: 90 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -529,19 +529,68 @@ static resource_size_t init_dpa_allocation(struct nd_label_id *label_id,
529529
return rc ? n : 0;
530530
}
531531

532-
static bool space_valid(bool is_pmem, bool is_reserve,
533-
struct nd_label_id *label_id, struct resource *res)
532+
533+
/**
534+
* space_valid() - validate free dpa space against constraints
535+
* @nd_region: hosting region of the free space
536+
* @ndd: dimm device data for debug
537+
* @label_id: namespace id to allocate space
538+
* @prev: potential allocation that precedes free space
539+
* @next: allocation that follows the given free space range
540+
* @exist: first allocation with same id in the mapping
541+
* @n: range that must satisfied for pmem allocations
542+
* @valid: free space range to validate
543+
*
544+
* BLK-space is valid as long as it does not precede a PMEM
545+
* allocation in a given region. PMEM-space must be contiguous
546+
* and adjacent to an existing existing allocation (if one
547+
* exists). If reserving PMEM any space is valid.
548+
*/
549+
static void space_valid(struct nd_region *nd_region, struct nvdimm_drvdata *ndd,
550+
struct nd_label_id *label_id, struct resource *prev,
551+
struct resource *next, struct resource *exist,
552+
resource_size_t n, struct resource *valid)
534553
{
535-
/*
536-
* For BLK-space any space is valid, for PMEM-space, it must be
537-
* contiguous with an existing allocation unless we are
538-
* reserving pmem.
539-
*/
540-
if (is_reserve || !is_pmem)
541-
return true;
542-
if (!res || strcmp(res->name, label_id->id) == 0)
543-
return true;
544-
return false;
554+
bool is_reserve = strcmp(label_id->id, "pmem-reserve") == 0;
555+
bool is_pmem = strncmp(label_id->id, "pmem", 4) == 0;
556+
557+
if (valid->start >= valid->end)
558+
goto invalid;
559+
560+
if (is_reserve)
561+
return;
562+
563+
if (!is_pmem) {
564+
struct nd_mapping *nd_mapping = &nd_region->mapping[0];
565+
struct nvdimm_bus *nvdimm_bus;
566+
struct blk_alloc_info info = {
567+
.nd_mapping = nd_mapping,
568+
.available = nd_mapping->size,
569+
.res = valid,
570+
};
571+
572+
WARN_ON(!is_nd_blk(&nd_region->dev));
573+
nvdimm_bus = walk_to_nvdimm_bus(&nd_region->dev);
574+
device_for_each_child(&nvdimm_bus->dev, &info, alias_dpa_busy);
575+
return;
576+
}
577+
578+
/* allocation needs to be contiguous, so this is all or nothing */
579+
if (resource_size(valid) < n)
580+
goto invalid;
581+
582+
/* we've got all the space we need and no existing allocation */
583+
if (!exist)
584+
return;
585+
586+
/* allocation needs to be contiguous with the existing namespace */
587+
if (valid->start == exist->end + 1
588+
|| valid->end == exist->start - 1)
589+
return;
590+
591+
invalid:
592+
/* truncate @valid size to 0 */
593+
valid->end = valid->start - 1;
545594
}
546595

547596
enum alloc_loc {
@@ -553,18 +602,24 @@ static resource_size_t scan_allocate(struct nd_region *nd_region,
553602
resource_size_t n)
554603
{
555604
resource_size_t mapping_end = nd_mapping->start + nd_mapping->size - 1;
556-
bool is_reserve = strcmp(label_id->id, "pmem-reserve") == 0;
557605
bool is_pmem = strncmp(label_id->id, "pmem", 4) == 0;
558606
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
607+
struct resource *res, *exist = NULL, valid;
559608
const resource_size_t to_allocate = n;
560-
struct resource *res;
561609
int first;
562610

611+
for_each_dpa_resource(ndd, res)
612+
if (strcmp(label_id->id, res->name) == 0)
613+
exist = res;
614+
615+
valid.start = nd_mapping->start;
616+
valid.end = mapping_end;
617+
valid.name = "free space";
563618
retry:
564619
first = 0;
565620
for_each_dpa_resource(ndd, res) {
566-
resource_size_t allocate, available = 0, free_start, free_end;
567621
struct resource *next = res->sibling, *new_res = NULL;
622+
resource_size_t allocate, available = 0;
568623
enum alloc_loc loc = ALLOC_ERR;
569624
const char *action;
570625
int rc = 0;
@@ -577,32 +632,35 @@ static resource_size_t scan_allocate(struct nd_region *nd_region,
577632

578633
/* space at the beginning of the mapping */
579634
if (!first++ && res->start > nd_mapping->start) {
580-
free_start = nd_mapping->start;
581-
available = res->start - free_start;
582-
if (space_valid(is_pmem, is_reserve, label_id, NULL))
635+
valid.start = nd_mapping->start;
636+
valid.end = res->start - 1;
637+
space_valid(nd_region, ndd, label_id, NULL, next, exist,
638+
to_allocate, &valid);
639+
available = resource_size(&valid);
640+
if (available)
583641
loc = ALLOC_BEFORE;
584642
}
585643

586644
/* space between allocations */
587645
if (!loc && next) {
588-
free_start = res->start + resource_size(res);
589-
free_end = min(mapping_end, next->start - 1);
590-
if (space_valid(is_pmem, is_reserve, label_id, res)
591-
&& free_start < free_end) {
592-
available = free_end + 1 - free_start;
646+
valid.start = res->start + resource_size(res);
647+
valid.end = min(mapping_end, next->start - 1);
648+
space_valid(nd_region, ndd, label_id, res, next, exist,
649+
to_allocate, &valid);
650+
available = resource_size(&valid);
651+
if (available)
593652
loc = ALLOC_MID;
594-
}
595653
}
596654

597655
/* space at the end of the mapping */
598656
if (!loc && !next) {
599-
free_start = res->start + resource_size(res);
600-
free_end = mapping_end;
601-
if (space_valid(is_pmem, is_reserve, label_id, res)
602-
&& free_start < free_end) {
603-
available = free_end + 1 - free_start;
657+
valid.start = res->start + resource_size(res);
658+
valid.end = mapping_end;
659+
space_valid(nd_region, ndd, label_id, res, next, exist,
660+
to_allocate, &valid);
661+
available = resource_size(&valid);
662+
if (available)
604663
loc = ALLOC_AFTER;
605-
}
606664
}
607665

608666
if (!loc || !available)
@@ -612,8 +670,6 @@ static resource_size_t scan_allocate(struct nd_region *nd_region,
612670
case ALLOC_BEFORE:
613671
if (strcmp(res->name, label_id->id) == 0) {
614672
/* adjust current resource up */
615-
if (is_pmem && !is_reserve)
616-
return n;
617673
rc = adjust_resource(res, res->start - allocate,
618674
resource_size(res) + allocate);
619675
action = "cur grow up";
@@ -623,8 +679,6 @@ static resource_size_t scan_allocate(struct nd_region *nd_region,
623679
case ALLOC_MID:
624680
if (strcmp(next->name, label_id->id) == 0) {
625681
/* adjust next resource up */
626-
if (is_pmem && !is_reserve)
627-
return n;
628682
rc = adjust_resource(next, next->start
629683
- allocate, resource_size(next)
630684
+ allocate);
@@ -648,12 +702,10 @@ static resource_size_t scan_allocate(struct nd_region *nd_region,
648702
if (strcmp(action, "allocate") == 0) {
649703
/* BLK allocate bottom up */
650704
if (!is_pmem)
651-
free_start += available - allocate;
652-
else if (!is_reserve && free_start != nd_mapping->start)
653-
return n;
705+
valid.start += available - allocate;
654706

655707
new_res = nvdimm_allocate_dpa(ndd, label_id,
656-
free_start, allocate);
708+
valid.start, allocate);
657709
if (!new_res)
658710
rc = -EBUSY;
659711
} else if (strcmp(action, "grow down") == 0) {

drivers/nvdimm/nd-core.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,23 @@ struct nvdimm {
4444
struct resource *flush_wpq;
4545
};
4646

47+
/**
48+
* struct blk_alloc_info - tracking info for BLK dpa scanning
49+
* @nd_mapping: blk region mapping boundaries
50+
* @available: decremented in alias_dpa_busy as aliased PMEM is scanned
51+
* @busy: decremented in blk_dpa_busy to account for ranges already
52+
* handled by alias_dpa_busy
53+
* @res: alias_dpa_busy interprets this a free space range that needs to
54+
* be truncated to the valid BLK allocation starting DPA, blk_dpa_busy
55+
* treats it as a busy range that needs the aliased PMEM ranges
56+
* truncated.
57+
*/
58+
struct blk_alloc_info {
59+
struct nd_mapping *nd_mapping;
60+
resource_size_t available, busy;
61+
struct resource *res;
62+
};
63+
4764
bool is_nvdimm(struct device *dev);
4865
bool is_nd_pmem(struct device *dev);
4966
bool is_nd_blk(struct device *dev);
@@ -80,6 +97,7 @@ resource_size_t nd_blk_available_dpa(struct nd_region *nd_region);
8097
resource_size_t nd_region_available_dpa(struct nd_region *nd_region);
8198
resource_size_t nvdimm_allocated_dpa(struct nvdimm_drvdata *ndd,
8299
struct nd_label_id *label_id);
100+
int alias_dpa_busy(struct device *dev, void *data);
83101
struct resource *nsblk_add_resource(struct nd_region *nd_region,
84102
struct nvdimm_drvdata *ndd, struct nd_namespace_blk *nsblk,
85103
resource_size_t start);

0 commit comments

Comments
 (0)