mirror of
https://github.com/torvalds/linux.git
synced 2024-12-26 21:02:19 +00:00
c42adf87e4
We do check for a bad block during namespace init and that use region bad block list. We need to initialize the bad block for volatile regions for this to work. We also observe a lockdep warning as below because the lock is not initialized correctly since we skip bad block init for volatile regions. INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 2 PID: 1 Comm: swapper/0 Not tainted 5.3.0-rc1-15699-g3dee241c937e #149 Call Trace: [c0000000f95cb250] [c00000000147dd84] dump_stack+0xe8/0x164 (unreliable) [c0000000f95cb2a0] [c00000000022ccd8] register_lock_class+0x308/0xa60 [c0000000f95cb3a0] [c000000000229cc0] __lock_acquire+0x170/0x1ff0 [c0000000f95cb4c0] [c00000000022c740] lock_acquire+0x220/0x270 [c0000000f95cb580] [c000000000a93230] badblocks_check+0xc0/0x290 [c0000000f95cb5f0] [c000000000d97540] nd_pfn_validate+0x5c0/0x7f0 [c0000000f95cb6d0] [c000000000d98300] nd_dax_probe+0xd0/0x1f0 [c0000000f95cb760] [c000000000d9b66c] nd_pmem_probe+0x10c/0x160 [c0000000f95cb790] [c000000000d7f5ec] nvdimm_bus_probe+0x10c/0x240 [c0000000f95cb820] [c000000000d0f844] really_probe+0x254/0x4e0 [c0000000f95cb8b0] [c000000000d0fdfc] driver_probe_device+0x16c/0x1e0 [c0000000f95cb930] [c000000000d10238] device_driver_attach+0x68/0xa0 [c0000000f95cb970] [c000000000d1040c] __driver_attach+0x19c/0x1c0 [c0000000f95cb9f0] [c000000000d0c4c4] bus_for_each_dev+0x94/0x130 [c0000000f95cba50] [c000000000d0f014] driver_attach+0x34/0x50 [c0000000f95cba70] [c000000000d0e208] bus_add_driver+0x178/0x2f0 [c0000000f95cbb00] [c000000000d117c8] driver_register+0x108/0x170 [c0000000f95cbb70] [c000000000d7edb0] __nd_driver_register+0xe0/0x100 [c0000000f95cbbd0] [c000000001a6baa4] nd_pmem_driver_init+0x34/0x48 [c0000000f95cbbf0] [c0000000000106f4] do_one_initcall+0x1d4/0x4b0 [c0000000f95cbcd0] [c0000000019f499c] kernel_init_freeable+0x544/0x65c [c0000000f95cbdb0] [c000000000010d6c] kernel_init+0x2c/0x180 [c0000000f95cbe20] [c00000000000b954] ret_from_kernel_thread+0x5c/0x68 Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com> Link: https://lore.kernel.org/r/20190919083355.26340-1-aneesh.kumar@linux.ibm.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
161 lines
4.1 KiB
C
161 lines
4.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
|
|
*/
|
|
#include <linux/cpumask.h>
|
|
#include <linux/module.h>
|
|
#include <linux/device.h>
|
|
#include <linux/nd.h>
|
|
#include "nd-core.h"
|
|
#include "nd.h"
|
|
|
|
static int nd_region_probe(struct device *dev)
|
|
{
|
|
int err, rc;
|
|
static unsigned long once;
|
|
struct nd_region_data *ndrd;
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
if (nd_region->num_lanes > num_online_cpus()
|
|
&& nd_region->num_lanes < num_possible_cpus()
|
|
&& !test_and_set_bit(0, &once)) {
|
|
dev_dbg(dev, "online cpus (%d) < concurrent i/o lanes (%d) < possible cpus (%d)\n",
|
|
num_online_cpus(), nd_region->num_lanes,
|
|
num_possible_cpus());
|
|
dev_dbg(dev, "setting nr_cpus=%d may yield better libnvdimm device performance\n",
|
|
nd_region->num_lanes);
|
|
}
|
|
|
|
rc = nd_region_activate(nd_region);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = nd_blk_region_init(nd_region);
|
|
if (rc)
|
|
return rc;
|
|
|
|
if (is_memory(&nd_region->dev)) {
|
|
struct resource ndr_res;
|
|
|
|
if (devm_init_badblocks(dev, &nd_region->bb))
|
|
return -ENODEV;
|
|
nd_region->bb_state = sysfs_get_dirent(nd_region->dev.kobj.sd,
|
|
"badblocks");
|
|
if (!nd_region->bb_state)
|
|
dev_warn(&nd_region->dev,
|
|
"'badblocks' notification disabled\n");
|
|
ndr_res.start = nd_region->ndr_start;
|
|
ndr_res.end = nd_region->ndr_start + nd_region->ndr_size - 1;
|
|
nvdimm_badblocks_populate(nd_region, &nd_region->bb, &ndr_res);
|
|
}
|
|
|
|
rc = nd_region_register_namespaces(nd_region, &err);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
ndrd = dev_get_drvdata(dev);
|
|
ndrd->ns_active = rc;
|
|
ndrd->ns_count = rc + err;
|
|
|
|
if (rc && err && rc == err)
|
|
return -ENODEV;
|
|
|
|
nd_region->btt_seed = nd_btt_create(nd_region);
|
|
nd_region->pfn_seed = nd_pfn_create(nd_region);
|
|
nd_region->dax_seed = nd_dax_create(nd_region);
|
|
if (err == 0)
|
|
return 0;
|
|
|
|
/*
|
|
* Given multiple namespaces per region, we do not want to
|
|
* disable all the successfully registered peer namespaces upon
|
|
* a single registration failure. If userspace is missing a
|
|
* namespace that it expects it can disable/re-enable the region
|
|
* to retry discovery after correcting the failure.
|
|
* <regionX>/namespaces returns the current
|
|
* "<async-registered>/<total>" namespace count.
|
|
*/
|
|
dev_err(dev, "failed to register %d namespace%s, continuing...\n",
|
|
err, err == 1 ? "" : "s");
|
|
return 0;
|
|
}
|
|
|
|
static int child_unregister(struct device *dev, void *data)
|
|
{
|
|
nd_device_unregister(dev, ND_SYNC);
|
|
return 0;
|
|
}
|
|
|
|
static int nd_region_remove(struct device *dev)
|
|
{
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
device_for_each_child(dev, NULL, child_unregister);
|
|
|
|
/* flush attribute readers and disable */
|
|
nvdimm_bus_lock(dev);
|
|
nd_region->ns_seed = NULL;
|
|
nd_region->btt_seed = NULL;
|
|
nd_region->pfn_seed = NULL;
|
|
nd_region->dax_seed = NULL;
|
|
dev_set_drvdata(dev, NULL);
|
|
nvdimm_bus_unlock(dev);
|
|
|
|
/*
|
|
* Note, this assumes nd_device_lock() context to not race
|
|
* nd_region_notify()
|
|
*/
|
|
sysfs_put(nd_region->bb_state);
|
|
nd_region->bb_state = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int child_notify(struct device *dev, void *data)
|
|
{
|
|
nd_device_notify(dev, *(enum nvdimm_event *) data);
|
|
return 0;
|
|
}
|
|
|
|
static void nd_region_notify(struct device *dev, enum nvdimm_event event)
|
|
{
|
|
if (event == NVDIMM_REVALIDATE_POISON) {
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
struct resource res;
|
|
|
|
if (is_memory(&nd_region->dev)) {
|
|
res.start = nd_region->ndr_start;
|
|
res.end = nd_region->ndr_start +
|
|
nd_region->ndr_size - 1;
|
|
nvdimm_badblocks_populate(nd_region,
|
|
&nd_region->bb, &res);
|
|
if (nd_region->bb_state)
|
|
sysfs_notify_dirent(nd_region->bb_state);
|
|
}
|
|
}
|
|
device_for_each_child(dev, &event, child_notify);
|
|
}
|
|
|
|
static struct nd_device_driver nd_region_driver = {
|
|
.probe = nd_region_probe,
|
|
.remove = nd_region_remove,
|
|
.notify = nd_region_notify,
|
|
.drv = {
|
|
.name = "nd_region",
|
|
},
|
|
.type = ND_DRIVER_REGION_BLK | ND_DRIVER_REGION_PMEM,
|
|
};
|
|
|
|
int __init nd_region_init(void)
|
|
{
|
|
return nd_driver_register(&nd_region_driver);
|
|
}
|
|
|
|
void nd_region_exit(void)
|
|
{
|
|
driver_unregister(&nd_region_driver.drv);
|
|
}
|
|
|
|
MODULE_ALIAS_ND_DEVICE(ND_DEVICE_REGION_PMEM);
|
|
MODULE_ALIAS_ND_DEVICE(ND_DEVICE_REGION_BLK);
|