summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-06-19 02:27:58 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2026-06-19 02:27:58 +0300
commitcfd96ad1389cd6045a3af05bd34b2e52b291e365 (patch)
tree3b1e544b7b0df919046e3d0aa6c96bca61673086
parent7849ce38717e64213bf9cbb166d1cda14e05143f (diff)
parent86e411b6ec277dbb8ac1f1d855dc337181a62a29 (diff)
downloadlinux-cfd96ad1389cd6045a3af05bd34b2e52b291e365.tar.xz
Merge tag 'libnvdimm-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull nvdimm/dax updates from Alison Schofield: - Fix a race condition and a couple of static analysis issues in BTT - Use sysfs_emit() in preparation for removal of cpumap_print_to_pagebuf() - Escalate a dev_dbg to dev_err in a resource conflict message - MAINTAINER file updates * tag 'libnvdimm-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: MAINTAINERS: nvdimm: Include maintainer profile MAINTAINERS: Update address for Ira Weiny MAINTAINERS: Add maintainer info for libnvdimm and DAX nvdimm: Use sysfs_emit() for cpumask show callback dax/bus: Upgrade resource conflict message to dev_err() in alloc_dax_region() nvdimm/btt: Free arenas on btt_init() error paths nvdimm/btt: Free arena sub-allocations on discover_arenas() error path nvdimm/btt: Handle preemption in BTT lane acquisition
-rw-r--r--.mailmap1
-rw-r--r--Documentation/driver-api/nvdimm/btt.rst5
-rw-r--r--MAINTAINERS11
-rw-r--r--drivers/dax/bus.c2
-rw-r--r--drivers/nvdimm/btt.c14
-rw-r--r--drivers/nvdimm/nd.h11
-rw-r--r--drivers/nvdimm/nd_perf.c2
-rw-r--r--drivers/nvdimm/region_devs.c66
8 files changed, 50 insertions, 62 deletions
diff --git a/.mailmap b/.mailmap
index 33b03396b18f..7d653f7e693d 100644
--- a/.mailmap
+++ b/.mailmap
@@ -450,6 +450,7 @@ Juha Yrjola <juha.yrjola@nokia.com>
Juha Yrjola <juha.yrjola@solidboot.com>
Julien Thierry <julien.thierry.kdev@gmail.com> <julien.thierry@arm.com>
Justin Iurman <justin.iurman@gmail.com> <justin.iurman@uliege.be>
+Ira Weiny <iweiny@kernel.org> <ira.weiny@intel.com>
Iskren Chernev <me@iskren.info> <iskren.chernev@gmail.com>
Kalle Valo <kvalo@kernel.org> <kvalo@codeaurora.org>
Kalle Valo <kvalo@kernel.org> <quic_kvalo@quicinc.com>
diff --git a/Documentation/driver-api/nvdimm/btt.rst b/Documentation/driver-api/nvdimm/btt.rst
index 2d8269f834bd..d29fab95f149 100644
--- a/Documentation/driver-api/nvdimm/btt.rst
+++ b/Documentation/driver-api/nvdimm/btt.rst
@@ -161,9 +161,8 @@ process::
nlanes = min(nfree, num_cpus)
A lane number is obtained at the start of any IO, and is used for indexing into
-all the on-disk and in-memory data structures for the duration of the IO. If
-there are more CPUs than the max number of available lanes, than lanes are
-protected by spinlocks.
+all the on-disk and in-memory data structures for the duration of the IO. Lanes
+are protected by mutexes.
d. In-memory data structure: Read Tracking Table (RTT)
diff --git a/MAINTAINERS b/MAINTAINERS
index 3147a467d458..926a17df059e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4302,7 +4302,7 @@ M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
M: "Rafael J. Wysocki" <rafael@kernel.org>
M: Danilo Krummrich <dakr@kernel.org>
R: Dave Ertman <david.m.ertman@intel.com>
-R: Ira Weiny <ira.weiny@intel.com>
+R: Ira Weiny <iweiny@kernel.org>
R: Leon Romanovsky <leon@kernel.org>
L: driver-core@lists.linux.dev
S: Supported
@@ -6454,8 +6454,8 @@ M: Jonathan Cameron <jic23@kernel.org>
M: Dave Jiang <dave.jiang@intel.com>
M: Alison Schofield <alison.schofield@intel.com>
M: Vishal Verma <vishal.l.verma@intel.com>
-M: Ira Weiny <ira.weiny@intel.com>
M: Dan Williams <djbw@kernel.org>
+R: Ira Weiny <iweiny@kernel.org>
L: linux-cxl@vger.kernel.org
S: Maintained
F: Documentation/driver-api/cxl
@@ -7320,6 +7320,7 @@ DEVICE DIRECT ACCESS (DAX)
M: Dan Williams <djbw@kernel.org>
M: Vishal Verma <vishal.l.verma@intel.com>
M: Dave Jiang <dave.jiang@intel.com>
+M: Alison Schofield <alison.schofield@intel.com>
L: nvdimm@lists.linux.dev
L: linux-cxl@vger.kernel.org
S: Supported
@@ -14725,6 +14726,7 @@ LIBNVDIMM BTT: BLOCK TRANSLATION TABLE
M: Vishal Verma <vishal.l.verma@intel.com>
M: Dan Williams <djbw@kernel.org>
M: Dave Jiang <dave.jiang@intel.com>
+M: Alison Schofield <alison.schofield@intel.com>
L: nvdimm@lists.linux.dev
S: Supported
Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
@@ -14735,6 +14737,7 @@ LIBNVDIMM PMEM: PERSISTENT MEMORY DRIVER
M: Dan Williams <djbw@kernel.org>
M: Vishal Verma <vishal.l.verma@intel.com>
M: Dave Jiang <dave.jiang@intel.com>
+M: Alison Schofield <alison.schofield@intel.com>
L: nvdimm@lists.linux.dev
S: Supported
Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
@@ -14753,12 +14756,14 @@ LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM
M: Dan Williams <djbw@kernel.org>
M: Vishal Verma <vishal.l.verma@intel.com>
M: Dave Jiang <dave.jiang@intel.com>
-M: Ira Weiny <ira.weiny@intel.com>
+M: Alison Schofield <alison.schofield@intel.com>
+R: Ira Weiny <iweiny@kernel.org>
L: nvdimm@lists.linux.dev
S: Supported
Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
P: Documentation/nvdimm/maintainer-entry-profile.rst
T: git git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git
+F: Documentation/nvdimm/maintainer-entry-profile.rst
F: drivers/acpi/nfit/*
F: drivers/nvdimm/*
F: include/linux/libnvdimm.h
diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c
index ccfe65004888..b809e1a264af 100644
--- a/drivers/dax/bus.c
+++ b/drivers/dax/bus.c
@@ -670,7 +670,7 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
rc = request_resource(&dax_regions, &dax_region->res);
if (rc) {
- dev_dbg(parent, "dax_region resource conflict for %pR\n",
+ dev_err(parent, "dax_region resource conflict for %pR\n",
&dax_region->res);
goto err_res;
}
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index fdcb080a4314..7e1112960d7f 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -919,6 +919,9 @@ static int discover_arenas(struct btt *btt)
return ret;
out:
+ kfree(arena->freelist);
+ kfree(arena->rtt);
+ kfree(arena->map_locks);
kfree(arena);
free_arenas(btt);
return ret;
@@ -1589,7 +1592,7 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize,
if (btt->init_state != INIT_READY && nd_region->ro) {
dev_warn(dev, "%s is read-only, unable to init btt metadata\n",
dev_name(&nd_region->dev));
- return NULL;
+ goto err;
} else if (btt->init_state != INIT_READY) {
btt->num_arenas = (rawsize / ARENA_MAX_SIZE) +
((rawsize % ARENA_MAX_SIZE) ? 1 : 0);
@@ -1599,25 +1602,28 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize,
ret = create_arenas(btt);
if (ret) {
dev_info(dev, "init: create_arenas: %d\n", ret);
- return NULL;
+ goto err;
}
ret = btt_meta_init(btt);
if (ret) {
dev_err(dev, "init: error in meta_init: %d\n", ret);
- return NULL;
+ goto err;
}
}
ret = btt_blk_init(btt);
if (ret) {
dev_err(dev, "init: error in blk_init: %d\n", ret);
- return NULL;
+ goto err;
}
btt_debugfs_init(btt);
return btt;
+err:
+ free_arenas(btt);
+ return NULL;
}
/**
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 18b64559664b..ed69dea5b75f 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -365,11 +365,6 @@ unsigned sizeof_namespace_label(struct nvdimm_drvdata *ndd);
for (res = (ndd)->dpa.child, next = res ? res->sibling : NULL; \
res; res = next, next = next ? next->sibling : NULL)
-struct nd_percpu_lane {
- int count;
- spinlock_t lock;
-};
-
enum nd_label_flags {
ND_LABEL_REAP,
};
@@ -400,6 +395,10 @@ struct nd_mapping {
struct nvdimm_drvdata *ndd;
};
+struct nd_lane {
+ struct mutex lock; /* serialize lane access */
+} ____cacheline_aligned_in_smp;
+
struct nd_region {
struct device dev;
struct ida ns_ida;
@@ -420,7 +419,7 @@ struct nd_region {
struct kernfs_node *bb_state;
struct badblocks bb;
struct nd_interleave_set *nd_set;
- struct nd_percpu_lane __percpu *lane;
+ struct nd_lane *lane;
int (*flush)(struct nd_region *nd_region, struct bio *bio);
struct nd_mapping mapping[] __counted_by(ndr_mappings);
};
diff --git a/drivers/nvdimm/nd_perf.c b/drivers/nvdimm/nd_perf.c
index e0b51438dc9b..9e497cae65b3 100644
--- a/drivers/nvdimm/nd_perf.c
+++ b/drivers/nvdimm/nd_perf.c
@@ -123,7 +123,7 @@ static ssize_t nvdimm_pmu_cpumask_show(struct device *dev,
nd_pmu = container_of(pmu, struct nvdimm_pmu, pmu);
- return cpumap_print_to_pagebuf(true, buf, cpumask_of(nd_pmu->cpu));
+ return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(cpumask_of(nd_pmu->cpu)));
}
static int nvdimm_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node)
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index e35c2e18518f..5e079d61cbaa 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -192,7 +192,9 @@ static void nd_region_release(struct device *dev)
put_device(&nvdimm->dev);
}
- free_percpu(nd_region->lane);
+ for (i = 0; i < nd_region->num_lanes; i++)
+ mutex_destroy(&nd_region->lane[i].lock);
+ kfree(nd_region->lane);
if (!test_bit(ND_REGION_CXL, &nd_region->flags))
memregion_free(nd_region->id);
kfree(nd_region);
@@ -904,52 +906,30 @@ void nd_region_advance_seeds(struct nd_region *nd_region, struct device *dev)
* nd_region_acquire_lane - allocate and lock a lane
* @nd_region: region id and number of lanes possible
*
- * A lane correlates to a BLK-data-window and/or a log slot in the BTT.
- * We optimize for the common case where there are 256 lanes, one
- * per-cpu. For larger systems we need to lock to share lanes. For now
- * this implementation assumes the cost of maintaining an allocator for
- * free lanes is on the order of the lock hold time, so it implements a
- * static lane = cpu % num_lanes mapping.
+ * A lane correlates to a log slot in the BTT. Lanes are shared across
+ * CPUs using a static lane = cpu % num_lanes mapping, with a per-lane
+ * mutex to serialize access.
*
- * In the case of a BTT instance on top of a BLK namespace a lane may be
- * acquired recursively. We lock on the first instance.
- *
- * In the case of a BTT instance on top of PMEM, we only acquire a lane
- * for the BTT metadata updates.
+ * Callers must be in sleepable context. The only in-tree caller is
+ * BTT's ->submit_bio handler (btt_read_pg / btt_write_pg).
*/
unsigned int nd_region_acquire_lane(struct nd_region *nd_region)
+ __acquires(&nd_region->lane[lane].lock)
{
- unsigned int cpu, lane;
-
- migrate_disable();
- cpu = smp_processor_id();
- if (nd_region->num_lanes < nr_cpu_ids) {
- struct nd_percpu_lane *ndl_lock, *ndl_count;
+ unsigned int lane;
- lane = cpu % nd_region->num_lanes;
- ndl_count = per_cpu_ptr(nd_region->lane, cpu);
- ndl_lock = per_cpu_ptr(nd_region->lane, lane);
- if (ndl_count->count++ == 0)
- spin_lock(&ndl_lock->lock);
- } else
- lane = cpu;
+ might_sleep();
+ lane = raw_smp_processor_id() % nd_region->num_lanes;
+ mutex_lock(&nd_region->lane[lane].lock);
return lane;
}
EXPORT_SYMBOL(nd_region_acquire_lane);
void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane)
+ __releases(&nd_region->lane[lane].lock)
{
- if (nd_region->num_lanes < nr_cpu_ids) {
- unsigned int cpu = smp_processor_id();
- struct nd_percpu_lane *ndl_lock, *ndl_count;
-
- ndl_count = per_cpu_ptr(nd_region->lane, cpu);
- ndl_lock = per_cpu_ptr(nd_region->lane, lane);
- if (--ndl_count->count == 0)
- spin_unlock(&ndl_lock->lock);
- }
- migrate_enable();
+ mutex_unlock(&nd_region->lane[lane].lock);
}
EXPORT_SYMBOL(nd_region_release_lane);
@@ -1019,17 +999,16 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
goto err_id;
}
- nd_region->lane = alloc_percpu(struct nd_percpu_lane);
+ nd_region->num_lanes = ndr_desc->num_lanes;
+ if (!nd_region->num_lanes)
+ goto err_percpu;
+ nd_region->lane = kcalloc(nd_region->num_lanes,
+ sizeof(*nd_region->lane), GFP_KERNEL);
if (!nd_region->lane)
goto err_percpu;
- for (i = 0; i < nr_cpu_ids; i++) {
- struct nd_percpu_lane *ndl;
-
- ndl = per_cpu_ptr(nd_region->lane, i);
- spin_lock_init(&ndl->lock);
- ndl->count = 0;
- }
+ for (i = 0; i < nd_region->num_lanes; i++)
+ mutex_init(&nd_region->lane[i].lock);
for (i = 0; i < ndr_desc->num_mappings; i++) {
struct nd_mapping_desc *mapping = &ndr_desc->mapping[i];
@@ -1046,7 +1025,6 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
}
nd_region->provider_data = ndr_desc->provider_data;
nd_region->nd_set = ndr_desc->nd_set;
- nd_region->num_lanes = ndr_desc->num_lanes;
nd_region->flags = ndr_desc->flags;
nd_region->ro = ro;
nd_region->numa_node = ndr_desc->numa_node;