nvme-hwmon: rework to avoid devm allocation

The original design to use device-managed resource allocation
doesn't really work as the NVMe controller has a vastly different
lifetime than the hwmon sysfs attributes, causing warning about
duplicate sysfs entries upon reconnection.
This patch reworks the hwmon allocation to avoid device-managed
resource allocation, and uses the NVMe controller as parent for
the sysfs attributes.

Cc: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Hannes Reinecke <hare@suse.de>
Tested-by: Enzo Matsumiya <ematsumiya@suse.de>
Tested-by: Daniel Wagner <dwagner@suse.de>
Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Hannes Reinecke 2021-01-19 07:43:18 +01:00 committed by Christoph Hellwig
parent 295a39f5a5
commit ed7770f662
3 changed files with 30 additions and 10 deletions

View file

@ -4471,6 +4471,7 @@ EXPORT_SYMBOL_GPL(nvme_start_ctrl);
void nvme_uninit_ctrl(struct nvme_ctrl *ctrl) void nvme_uninit_ctrl(struct nvme_ctrl *ctrl)
{ {
nvme_hwmon_exit(ctrl);
nvme_fault_inject_fini(&ctrl->fault_inject); nvme_fault_inject_fini(&ctrl->fault_inject);
dev_pm_qos_hide_latency_tolerance(ctrl->device); dev_pm_qos_hide_latency_tolerance(ctrl->device);
cdev_device_del(&ctrl->cdev, ctrl->device); cdev_device_del(&ctrl->cdev, ctrl->device);

View file

@ -223,12 +223,12 @@ static const struct hwmon_chip_info nvme_hwmon_chip_info = {
int nvme_hwmon_init(struct nvme_ctrl *ctrl) int nvme_hwmon_init(struct nvme_ctrl *ctrl)
{ {
struct device *dev = ctrl->dev; struct device *dev = ctrl->device;
struct nvme_hwmon_data *data; struct nvme_hwmon_data *data;
struct device *hwmon; struct device *hwmon;
int err; int err;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return 0; return 0;
@ -237,19 +237,30 @@ int nvme_hwmon_init(struct nvme_ctrl *ctrl)
err = nvme_hwmon_get_smart_log(data); err = nvme_hwmon_get_smart_log(data);
if (err) { if (err) {
dev_warn(ctrl->device, dev_warn(dev, "Failed to read smart log (error %d)\n", err);
"Failed to read smart log (error %d)\n", err); kfree(data);
devm_kfree(dev, data);
return err; return err;
} }
hwmon = devm_hwmon_device_register_with_info(dev, "nvme", data, hwmon = hwmon_device_register_with_info(dev, "nvme",
&nvme_hwmon_chip_info, data, &nvme_hwmon_chip_info,
NULL); NULL);
if (IS_ERR(hwmon)) { if (IS_ERR(hwmon)) {
dev_warn(dev, "Failed to instantiate hwmon device\n"); dev_warn(dev, "Failed to instantiate hwmon device\n");
devm_kfree(dev, data); kfree(data);
} }
ctrl->hwmon_device = hwmon;
return 0; return 0;
} }
void nvme_hwmon_exit(struct nvme_ctrl *ctrl)
{
if (ctrl->hwmon_device) {
struct nvme_hwmon_data *data =
dev_get_drvdata(ctrl->hwmon_device);
hwmon_device_unregister(ctrl->hwmon_device);
ctrl->hwmon_device = NULL;
kfree(data);
}
}

View file

@ -246,6 +246,9 @@ struct nvme_ctrl {
struct rw_semaphore namespaces_rwsem; struct rw_semaphore namespaces_rwsem;
struct device ctrl_device; struct device ctrl_device;
struct device *device; /* char device */ struct device *device; /* char device */
#ifdef CONFIG_NVME_HWMON
struct device *hwmon_device;
#endif
struct cdev cdev; struct cdev cdev;
struct work_struct reset_work; struct work_struct reset_work;
struct work_struct delete_work; struct work_struct delete_work;
@ -812,11 +815,16 @@ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
#ifdef CONFIG_NVME_HWMON #ifdef CONFIG_NVME_HWMON
int nvme_hwmon_init(struct nvme_ctrl *ctrl); int nvme_hwmon_init(struct nvme_ctrl *ctrl);
void nvme_hwmon_exit(struct nvme_ctrl *ctrl);
#else #else
static inline int nvme_hwmon_init(struct nvme_ctrl *ctrl) static inline int nvme_hwmon_init(struct nvme_ctrl *ctrl)
{ {
return 0; return 0;
} }
static inline void nvme_hwmon_exit(struct nvme_ctrl *ctrl)
{
}
#endif #endif
u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,