From 244b2c5ca8b14627e4a17755e5922221e121c771 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 09 Oct 2024 06:15:07 +0000
Subject: [PATCH] change system file
---
kernel/drivers/nvdimm/bus.c | 185 ++++++++++++++++++++++++++++++++--------------
1 files changed, 128 insertions(+), 57 deletions(-)
diff --git a/kernel/drivers/nvdimm/bus.c b/kernel/drivers/nvdimm/bus.c
index 48a070a..9ec5996 100644
--- a/kernel/drivers/nvdimm/bus.c
+++ b/kernel/drivers/nvdimm/bus.c
@@ -1,14 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/libnvdimm.h>
@@ -23,6 +15,7 @@
#include <linux/ndctl.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/cpu.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/mm.h>
@@ -33,7 +26,7 @@
int nvdimm_major;
static int nvdimm_bus_major;
-static struct class *nd_class;
+struct class *nd_class;
static DEFINE_IDA(nd_ida);
static int to_nd_device_type(struct device *dev)
@@ -54,12 +47,6 @@
static int nvdimm_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- /*
- * Ensure that region devices always have their numa node set as
- * early as possible.
- */
- if (is_nd_region(dev))
- set_dev_node(dev, to_nd_region(dev)->numa_node);
return add_uevent_var(env, "MODALIAS=" ND_DEVICE_MODALIAS_FMT,
to_nd_device_type(dev));
}
@@ -104,11 +91,13 @@
dev->driver->name, dev_name(dev));
nvdimm_bus_probe_start(nvdimm_bus);
+ debug_nvdimm_lock(dev);
rc = nd_drv->probe(dev);
- if (rc == 0)
- nd_region_probe_success(nvdimm_bus, dev);
- else
- nd_region_disable(nvdimm_bus, dev);
+ debug_nvdimm_unlock(dev);
+
+ if ((rc == 0 || rc == -EOPNOTSUPP) &&
+ dev->parent && is_nd_region(dev->parent))
+ nd_region_advance_seeds(to_nd_region(dev->parent), dev);
nvdimm_bus_probe_end(nvdimm_bus);
dev_dbg(&nvdimm_bus->dev, "END: %s.probe(%s) = %d\n", dev->driver->name,
@@ -126,9 +115,11 @@
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
int rc = 0;
- if (nd_drv->remove)
+ if (nd_drv->remove) {
+ debug_nvdimm_lock(dev);
rc = nd_drv->remove(dev);
- nd_region_disable(nvdimm_bus, dev);
+ debug_nvdimm_unlock(dev);
+ }
dev_dbg(&nvdimm_bus->dev, "%s.remove(%s) = %d\n", dev->driver->name,
dev_name(dev), rc);
@@ -153,7 +144,7 @@
void nd_device_notify(struct device *dev, enum nvdimm_event event)
{
- device_lock(dev);
+ nd_device_lock(dev);
if (dev->driver) {
struct nd_device_driver *nd_drv;
@@ -161,7 +152,7 @@
if (nd_drv->notify)
nd_drv->notify(dev, event);
}
- device_unlock(dev);
+ nd_device_unlock(dev);
}
EXPORT_SYMBOL(nd_device_notify);
@@ -196,8 +187,8 @@
ndr_end = nd_region->ndr_start + nd_region->ndr_size - 1;
/* make sure we are in the region */
- if (ctx->phys < nd_region->ndr_start
- || (ctx->phys + ctx->cleared) > ndr_end)
+ if (ctx->phys < nd_region->ndr_start ||
+ (ctx->phys + ctx->cleared - 1) > ndr_end)
return 0;
sector = (ctx->phys - nd_region->ndr_start) / 512;
@@ -309,9 +300,14 @@
kfree(nvdimm_bus);
}
-static bool is_nvdimm_bus(struct device *dev)
+static const struct device_type nvdimm_bus_dev_type = {
+ .release = nvdimm_bus_release,
+ .groups = nvdimm_bus_attribute_groups,
+};
+
+bool is_nvdimm_bus(struct device *dev)
{
- return dev->release == nvdimm_bus_release;
+ return dev->type == &nvdimm_bus_dev_type;
}
struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev)
@@ -337,6 +333,12 @@
}
EXPORT_SYMBOL_GPL(to_nvdimm_bus);
+struct nvdimm_bus *nvdimm_to_bus(struct nvdimm *nvdimm)
+{
+ return to_nvdimm_bus(nvdimm->dev.parent);
+}
+EXPORT_SYMBOL_GPL(nvdimm_to_bus);
+
struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
struct nvdimm_bus_descriptor *nd_desc)
{
@@ -350,15 +352,15 @@
INIT_LIST_HEAD(&nvdimm_bus->mapping_list);
init_waitqueue_head(&nvdimm_bus->wait);
nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
- mutex_init(&nvdimm_bus->reconfig_mutex);
- badrange_init(&nvdimm_bus->badrange);
if (nvdimm_bus->id < 0) {
kfree(nvdimm_bus);
return NULL;
}
+ mutex_init(&nvdimm_bus->reconfig_mutex);
+ badrange_init(&nvdimm_bus->badrange);
nvdimm_bus->nd_desc = nd_desc;
nvdimm_bus->dev.parent = parent;
- nvdimm_bus->dev.release = nvdimm_bus_release;
+ nvdimm_bus->dev.type = &nvdimm_bus_dev_type;
nvdimm_bus->dev.groups = nd_desc->attr_groups;
nvdimm_bus->dev.bus = &nvdimm_bus_type;
nvdimm_bus->dev.of_node = nd_desc->of_node;
@@ -393,9 +395,24 @@
* i.e. remove classless children
*/
if (dev->class)
- /* pass */;
- else
- nd_device_unregister(dev, ND_SYNC);
+ return 0;
+
+ if (is_nvdimm(dev)) {
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+ bool dev_put = false;
+
+ /* We are shutting down. Make state frozen artificially. */
+ nvdimm_bus_lock(dev);
+ set_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags);
+ if (test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags))
+ dev_put = true;
+ nvdimm_bus_unlock(dev);
+ cancel_delayed_work_sync(&nvdimm->dwork);
+ if (dev_put)
+ put_device(dev);
+ }
+ nd_device_unregister(dev, ND_SYNC);
+
return 0;
}
@@ -511,12 +528,26 @@
{
if (!dev)
return;
+
+ /*
+ * Ensure that region devices always have their NUMA node set as
+ * early as possible. This way we are able to make certain that
+ * any memory associated with the creation and the creation
+ * itself of the region is associated with the correct node.
+ */
+ if (is_nd_region(dev))
+ set_dev_node(dev, to_nd_region(dev)->numa_node);
+
dev->bus = &nvdimm_bus_type;
- if (dev->parent)
+ if (dev->parent) {
get_device(dev->parent);
+ if (dev_to_node(dev) == NUMA_NO_NODE)
+ set_dev_node(dev, dev_to_node(dev->parent));
+ }
get_device(dev);
- async_schedule_domain(nd_async_device_register, dev,
- &nd_async_domain);
+
+ async_schedule_dev_domain(nd_async_device_register, dev,
+ &nd_async_domain);
}
void nd_device_register(struct device *dev)
@@ -553,9 +584,9 @@
* or otherwise let the async path handle it if the
* unregistration was already queued.
*/
- device_lock(dev);
+ nd_device_lock(dev);
killed = kill_device(dev);
- device_unlock(dev);
+ nd_device_unlock(dev);
if (!killed)
return;
@@ -579,7 +610,7 @@
struct device_driver *drv = &nd_drv->drv;
if (!nd_drv->type) {
- pr_debug("driver type bitmask not set (%pf)\n",
+ pr_debug("driver type bitmask not set (%ps)\n",
__builtin_return_address(0));
return -EINVAL;
}
@@ -597,7 +628,7 @@
}
EXPORT_SYMBOL(__nd_driver_register);
-int nvdimm_revalidate_disk(struct gendisk *disk)
+void nvdimm_check_and_set_ro(struct gendisk *disk)
{
struct device *dev = disk_to_dev(disk)->parent;
struct nd_region *nd_region = to_nd_region(dev->parent);
@@ -608,16 +639,13 @@
* read-only if the disk is already read-only.
*/
if (disk_ro || nd_region->ro == disk_ro)
- return 0;
+ return;
dev_info(dev, "%s read-only, marking %s read-only\n",
dev_name(&nd_region->dev), disk->disk_name);
set_disk_ro(disk, 1);
-
- return 0;
-
}
-EXPORT_SYMBOL(nvdimm_revalidate_disk);
+EXPORT_SYMBOL(nvdimm_check_and_set_ro);
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -643,10 +671,9 @@
/*
* nd_device_attribute_group - generic attributes for all devices on an nd bus
*/
-struct attribute_group nd_device_attribute_group = {
+const struct attribute_group nd_device_attribute_group = {
.attrs = nd_device_attributes,
};
-EXPORT_SYMBOL_GPL(nd_device_attribute_group);
static ssize_t numa_node_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -655,15 +682,44 @@
}
static DEVICE_ATTR_RO(numa_node);
+static int nvdimm_dev_to_target_node(struct device *dev)
+{
+ struct device *parent = dev->parent;
+ struct nd_region *nd_region = NULL;
+
+ if (is_nd_region(dev))
+ nd_region = to_nd_region(dev);
+ else if (parent && is_nd_region(parent))
+ nd_region = to_nd_region(parent);
+
+ if (!nd_region)
+ return NUMA_NO_NODE;
+ return nd_region->target_node;
+}
+
+static ssize_t target_node_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", nvdimm_dev_to_target_node(dev));
+}
+static DEVICE_ATTR_RO(target_node);
+
static struct attribute *nd_numa_attributes[] = {
&dev_attr_numa_node.attr,
+ &dev_attr_target_node.attr,
NULL,
};
static umode_t nd_numa_attr_visible(struct kobject *kobj, struct attribute *a,
int n)
{
+ struct device *dev = container_of(kobj, typeof(*dev), kobj);
+
if (!IS_ENABLED(CONFIG_NUMA))
+ return 0;
+
+ if (a == &dev_attr_target_node.attr &&
+ nvdimm_dev_to_target_node(dev) == NUMA_NO_NODE)
return 0;
return a->mode;
@@ -672,11 +728,10 @@
/*
* nd_numa_attribute_group - NUMA attributes for all devices on an nd bus
*/
-struct attribute_group nd_numa_attribute_group = {
+const struct attribute_group nd_numa_attribute_group = {
.attrs = nd_numa_attributes,
.is_visible = nd_numa_attr_visible,
};
-EXPORT_SYMBOL_GPL(nd_numa_attribute_group);
int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus)
{
@@ -866,10 +921,10 @@
if (nvdimm_bus->probe_active == 0)
break;
nvdimm_bus_unlock(dev);
- device_unlock(dev);
+ nd_device_unlock(dev);
wait_event(nvdimm_bus->wait,
nvdimm_bus->probe_active == 0);
- device_lock(dev);
+ nd_device_lock(dev);
nvdimm_bus_lock(dev);
} while (true);
}
@@ -928,7 +983,7 @@
/* ask the bus provider if it would like to block this request */
if (nd_desc->clear_to_send) {
- int rc = nd_desc->clear_to_send(nd_desc, nvdimm, cmd);
+ int rc = nd_desc->clear_to_send(nd_desc, nvdimm, cmd, data);
if (rc)
return rc;
@@ -979,9 +1034,25 @@
dimm_name = "bus";
}
+ /* Validate command family support against bus declared support */
if (cmd == ND_CMD_CALL) {
+ unsigned long *mask;
+
if (copy_from_user(&pkg, p, sizeof(pkg)))
return -EFAULT;
+
+ if (nvdimm) {
+ if (pkg.nd_family > NVDIMM_FAMILY_MAX)
+ return -EINVAL;
+ mask = &nd_desc->dimm_family_mask;
+ } else {
+ if (pkg.nd_family > NVDIMM_BUS_FAMILY_MAX)
+ return -EINVAL;
+ mask = &nd_desc->bus_family_mask;
+ }
+
+ if (!test_bit(pkg.nd_family, mask))
+ return -EINVAL;
}
if (!desc ||
@@ -1087,7 +1158,7 @@
goto out;
}
- device_lock(dev);
+ nd_device_lock(dev);
nvdimm_bus_lock(dev);
rc = nd_cmd_clear_to_send(nvdimm_bus, nvdimm, func, buf);
if (rc)
@@ -1109,7 +1180,7 @@
out_unlock:
nvdimm_bus_unlock(dev);
- device_unlock(dev);
+ nd_device_unlock(dev);
out:
kfree(in_env);
kfree(out_env);
@@ -1203,7 +1274,7 @@
.owner = THIS_MODULE,
.open = nd_open,
.unlocked_ioctl = bus_ioctl,
- .compat_ioctl = bus_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
.llseek = noop_llseek,
};
@@ -1211,7 +1282,7 @@
.owner = THIS_MODULE,
.open = nd_open,
.unlocked_ioctl = dimm_ioctl,
- .compat_ioctl = dimm_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
.llseek = noop_llseek,
};
--
Gitblit v1.6.2