@@ -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
547596enum 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 ) {
0 commit comments