Skip to content

Commit 12e3129

Browse files
Keith Buschdavejiang
authored andcommitted
libnvdimm: Use max contiguous area for namespace size
This patch will find the max contiguous area to determine the largest pmem namespace size that can be created. If the requested size exceeds the largest available, ENOSPC error will be returned. This fixes the allocation underrun error and wrong error return code that have otherwise been observed as the following kernel warning: WARNING: CPU: <CPU> PID: <PID> at drivers/nvdimm/namespace_devs.c:913 size_store Fixes: a1f3e4d ("libnvdimm, region: update nd_region_available_dpa() for multi-pmem support") Cc: <stable@vger.kernel.org> Signed-off-by: Keith Busch <keith.busch@intel.com> Reviewed-by: Vishal Verma <vishal.l.verma@intel.com> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
1 parent 06cb081 commit 12e3129

File tree

4 files changed

+66
-3
lines changed

4 files changed

+66
-3
lines changed

drivers/nvdimm/dimm_devs.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,37 @@ resource_size_t nd_blk_available_dpa(struct nd_region *nd_region)
536536
return info.available;
537537
}
538538

539+
/**
540+
* nd_pmem_max_contiguous_dpa - For the given dimm+region, return the max
541+
* contiguous unallocated dpa range.
542+
* @nd_region: constrain available space check to this reference region
543+
* @nd_mapping: container of dpa-resource-root + labels
544+
*/
545+
resource_size_t nd_pmem_max_contiguous_dpa(struct nd_region *nd_region,
546+
struct nd_mapping *nd_mapping)
547+
{
548+
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
549+
struct nvdimm_bus *nvdimm_bus;
550+
resource_size_t max = 0;
551+
struct resource *res;
552+
553+
/* if a dimm is disabled the available capacity is zero */
554+
if (!ndd)
555+
return 0;
556+
557+
nvdimm_bus = walk_to_nvdimm_bus(ndd->dev);
558+
if (__reserve_free_pmem(&nd_region->dev, nd_mapping->nvdimm))
559+
return 0;
560+
for_each_dpa_resource(ndd, res) {
561+
if (strcmp(res->name, "pmem-reserve") != 0)
562+
continue;
563+
if (resource_size(res) > max)
564+
max = resource_size(res);
565+
}
566+
release_free_pmem(nvdimm_bus, nd_mapping);
567+
return max;
568+
}
569+
539570
/**
540571
* nd_pmem_available_dpa - for the given dimm+region account unallocated dpa
541572
* @nd_mapping: container of dpa-resource-root + labels

drivers/nvdimm/namespace_devs.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ static int merge_dpa(struct nd_region *nd_region,
799799
return 0;
800800
}
801801

802-
static int __reserve_free_pmem(struct device *dev, void *data)
802+
int __reserve_free_pmem(struct device *dev, void *data)
803803
{
804804
struct nvdimm *nvdimm = data;
805805
struct nd_region *nd_region;
@@ -836,7 +836,7 @@ static int __reserve_free_pmem(struct device *dev, void *data)
836836
return 0;
837837
}
838838

839-
static void release_free_pmem(struct nvdimm_bus *nvdimm_bus,
839+
void release_free_pmem(struct nvdimm_bus *nvdimm_bus,
840840
struct nd_mapping *nd_mapping)
841841
{
842842
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
@@ -1032,7 +1032,7 @@ static ssize_t __size_store(struct device *dev, unsigned long long val)
10321032

10331033
allocated += nvdimm_allocated_dpa(ndd, &label_id);
10341034
}
1035-
available = nd_region_available_dpa(nd_region);
1035+
available = nd_region_allocatable_dpa(nd_region);
10361036

10371037
if (val > available + allocated)
10381038
return -ENOSPC;

drivers/nvdimm/nd-core.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,14 @@ struct nd_region;
100100
struct nvdimm_drvdata;
101101
struct nd_mapping;
102102
void nd_mapping_free_labels(struct nd_mapping *nd_mapping);
103+
104+
int __reserve_free_pmem(struct device *dev, void *data);
105+
void release_free_pmem(struct nvdimm_bus *nvdimm_bus,
106+
struct nd_mapping *nd_mapping);
107+
108+
resource_size_t nd_pmem_max_contiguous_dpa(struct nd_region *nd_region,
109+
struct nd_mapping *nd_mapping);
110+
resource_size_t nd_region_allocatable_dpa(struct nd_region *nd_region);
103111
resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region,
104112
struct nd_mapping *nd_mapping, resource_size_t *overlap);
105113
resource_size_t nd_blk_available_dpa(struct nd_region *nd_region);

drivers/nvdimm/region_devs.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,30 @@ resource_size_t nd_region_available_dpa(struct nd_region *nd_region)
389389
return available;
390390
}
391391

392+
resource_size_t nd_region_allocatable_dpa(struct nd_region *nd_region)
393+
{
394+
resource_size_t available = 0;
395+
int i;
396+
397+
if (is_memory(&nd_region->dev))
398+
available = PHYS_ADDR_MAX;
399+
400+
WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev));
401+
for (i = 0; i < nd_region->ndr_mappings; i++) {
402+
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
403+
404+
if (is_memory(&nd_region->dev))
405+
available = min(available,
406+
nd_pmem_max_contiguous_dpa(nd_region,
407+
nd_mapping));
408+
else if (is_nd_blk(&nd_region->dev))
409+
available += nd_blk_available_dpa(nd_region);
410+
}
411+
if (is_memory(&nd_region->dev))
412+
return available * nd_region->ndr_mappings;
413+
return available;
414+
}
415+
392416
static ssize_t available_size_show(struct device *dev,
393417
struct device_attribute *attr, char *buf)
394418
{

0 commit comments

Comments
 (0)