Commit 523634db authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'libnvdimm-fixes-5.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm

Pull libnvdimm fixes from Dan Williams:
 "A collection of locking and async operations fixes for v5.3-rc2. These
  had been soaking in a branch targeting the merge window, but missed
  due to a regression hunt. This fixed up version has otherwise been in
  -next this past week with no reported issues.

  In order to gain confidence in the locking changes the pull also
  includes a debug / instrumentation patch to enable lockdep coverage
  for libnvdimm subsystem operations that depend on the device_lock for
  exclusion. As mentioned in the changelog it is a hack, but it works
  and documents the locking expectations of the sub-system in a way that
  others can use lockdep to verify. The driver core touches got an ack
  from Greg.

  Summary:

   - Fix duplicate device_unregister() calls (multiple threads competing
     to do unregister work when scheduling device removal from a sysfs
     attribute of the self-same device).

   - Fix badblocks registration order bug. Ensure region badblocks are
     initialized in advance of namespace registration.

   - Fix a deadlock between the bus lock and probe operations.

   - Export device-core infrastructure to coordinate async operations
     via the device ->dead state.

   - Add device-core infrastructure to validate device_lock() usage with
     lockdep"

* tag 'libnvdimm-fixes-5.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm:
  driver-core, libnvdimm: Let device subsystems add local lockdep coverage
  libnvdimm/bus: Fix wait_nvdimm_bus_probe_idle() ABBA deadlock
  libnvdimm/bus: Stop holding nvdimm_bus_list_mutex over __nd_ioctl()
  libnvdimm/bus: Prepare the nd_ioctl() path to be re-entrant
  libnvdimm/region: Register badblocks before namespaces
  libnvdimm/bus: Prevent duplicate device_unregister() calls
  drivers/base: Introduce kill_device()
parents 5168afe6 87a30e1f
...@@ -1282,7 +1282,7 @@ static ssize_t hw_error_scrub_store(struct device *dev, ...@@ -1282,7 +1282,7 @@ static ssize_t hw_error_scrub_store(struct device *dev,
if (rc) if (rc)
return rc; return rc;
device_lock(dev); nfit_device_lock(dev);
nd_desc = dev_get_drvdata(dev); nd_desc = dev_get_drvdata(dev);
if (nd_desc) { if (nd_desc) {
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
...@@ -1299,7 +1299,7 @@ static ssize_t hw_error_scrub_store(struct device *dev, ...@@ -1299,7 +1299,7 @@ static ssize_t hw_error_scrub_store(struct device *dev,
break; break;
} }
} }
device_unlock(dev); nfit_device_unlock(dev);
if (rc) if (rc)
return rc; return rc;
return size; return size;
...@@ -1319,7 +1319,7 @@ static ssize_t scrub_show(struct device *dev, ...@@ -1319,7 +1319,7 @@ static ssize_t scrub_show(struct device *dev,
ssize_t rc = -ENXIO; ssize_t rc = -ENXIO;
bool busy; bool busy;
device_lock(dev); nfit_device_lock(dev);
nd_desc = dev_get_drvdata(dev); nd_desc = dev_get_drvdata(dev);
if (!nd_desc) { if (!nd_desc) {
device_unlock(dev); device_unlock(dev);
...@@ -1339,7 +1339,7 @@ static ssize_t scrub_show(struct device *dev, ...@@ -1339,7 +1339,7 @@ static ssize_t scrub_show(struct device *dev,
} }
mutex_unlock(&acpi_desc->init_mutex); mutex_unlock(&acpi_desc->init_mutex);
device_unlock(dev); nfit_device_unlock(dev);
return rc; return rc;
} }
...@@ -1356,14 +1356,14 @@ static ssize_t scrub_store(struct device *dev, ...@@ -1356,14 +1356,14 @@ static ssize_t scrub_store(struct device *dev,
if (val != 1) if (val != 1)
return -EINVAL; return -EINVAL;
device_lock(dev); nfit_device_lock(dev);
nd_desc = dev_get_drvdata(dev); nd_desc = dev_get_drvdata(dev);
if (nd_desc) { if (nd_desc) {
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
rc = acpi_nfit_ars_rescan(acpi_desc, ARS_REQ_LONG); rc = acpi_nfit_ars_rescan(acpi_desc, ARS_REQ_LONG);
} }
device_unlock(dev); nfit_device_unlock(dev);
if (rc) if (rc)
return rc; return rc;
return size; return size;
...@@ -1749,9 +1749,9 @@ static void acpi_nvdimm_notify(acpi_handle handle, u32 event, void *data) ...@@ -1749,9 +1749,9 @@ static void acpi_nvdimm_notify(acpi_handle handle, u32 event, void *data)
struct acpi_device *adev = data; struct acpi_device *adev = data;
struct device *dev = &adev->dev; struct device *dev = &adev->dev;
device_lock(dev->parent); nfit_device_lock(dev->parent);
__acpi_nvdimm_notify(dev, event); __acpi_nvdimm_notify(dev, event);
device_unlock(dev->parent); nfit_device_unlock(dev->parent);
} }
static bool acpi_nvdimm_has_method(struct acpi_device *adev, char *method) static bool acpi_nvdimm_has_method(struct acpi_device *adev, char *method)
...@@ -3457,8 +3457,8 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) ...@@ -3457,8 +3457,8 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc)
struct device *dev = acpi_desc->dev; struct device *dev = acpi_desc->dev;
/* Bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */ /* Bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */
device_lock(dev); nfit_device_lock(dev);
device_unlock(dev); nfit_device_unlock(dev);
/* Bounce the init_mutex to complete initial registration */ /* Bounce the init_mutex to complete initial registration */
mutex_lock(&acpi_desc->init_mutex); mutex_lock(&acpi_desc->init_mutex);
...@@ -3602,8 +3602,8 @@ void acpi_nfit_shutdown(void *data) ...@@ -3602,8 +3602,8 @@ void acpi_nfit_shutdown(void *data)
* acpi_nfit_ars_rescan() submissions have had a chance to * acpi_nfit_ars_rescan() submissions have had a chance to
* either submit or see ->cancel set. * either submit or see ->cancel set.
*/ */
device_lock(bus_dev); nfit_device_lock(bus_dev);
device_unlock(bus_dev); nfit_device_unlock(bus_dev);
flush_workqueue(nfit_wq); flush_workqueue(nfit_wq);
} }
...@@ -3746,9 +3746,9 @@ EXPORT_SYMBOL_GPL(__acpi_nfit_notify); ...@@ -3746,9 +3746,9 @@ EXPORT_SYMBOL_GPL(__acpi_nfit_notify);
static void acpi_nfit_notify(struct acpi_device *adev, u32 event) static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
{ {
device_lock(&adev->dev); nfit_device_lock(&adev->dev);
__acpi_nfit_notify(&adev->dev, adev->handle, event); __acpi_nfit_notify(&adev->dev, adev->handle, event);
device_unlock(&adev->dev); nfit_device_unlock(&adev->dev);
} }
static const struct acpi_device_id acpi_nfit_ids[] = { static const struct acpi_device_id acpi_nfit_ids[] = {
......
...@@ -312,6 +312,30 @@ static inline struct acpi_nfit_desc *to_acpi_desc( ...@@ -312,6 +312,30 @@ static inline struct acpi_nfit_desc *to_acpi_desc(
return container_of(nd_desc, struct acpi_nfit_desc, nd_desc); return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
} }
#ifdef CONFIG_PROVE_LOCKING
static inline void nfit_device_lock(struct device *dev)
{
device_lock(dev);
mutex_lock(&dev->lockdep_mutex);
}
static inline void nfit_device_unlock(struct device *dev)
{
mutex_unlock(&dev->lockdep_mutex);
device_unlock(dev);
}
#else
static inline void nfit_device_lock(struct device *dev)
{
device_lock(dev);
}
static inline void nfit_device_unlock(struct device *dev)
{
device_unlock(dev);
}
#endif
const guid_t *to_nfit_uuid(enum nfit_uuids id); const guid_t *to_nfit_uuid(enum nfit_uuids id);
int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *nfit, acpi_size sz); int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *nfit, acpi_size sz);
void acpi_nfit_shutdown(void *data); void acpi_nfit_shutdown(void *data);
......
...@@ -1663,6 +1663,9 @@ void device_initialize(struct device *dev) ...@@ -1663,6 +1663,9 @@ void device_initialize(struct device *dev)
kobject_init(&dev->kobj, &device_ktype); kobject_init(&dev->kobj, &device_ktype);
INIT_LIST_HEAD(&dev->dma_pools); INIT_LIST_HEAD(&dev->dma_pools);
mutex_init(&dev->mutex); mutex_init(&dev->mutex);
#ifdef CONFIG_PROVE_LOCKING
mutex_init(&dev->lockdep_mutex);
#endif
lockdep_set_novalidate_class(&dev->mutex); lockdep_set_novalidate_class(&dev->mutex);
spin_lock_init(&dev->devres_lock); spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head); INIT_LIST_HEAD(&dev->devres_head);
...@@ -2211,6 +2214,24 @@ void put_device(struct device *dev) ...@@ -2211,6 +2214,24 @@ void put_device(struct device *dev)
} }
EXPORT_SYMBOL_GPL(put_device); EXPORT_SYMBOL_GPL(put_device);
bool kill_device(struct device *dev)
{
/*
* Require the device lock and set the "dead" flag to guarantee that
* the update behavior is consistent with the other bitfields near
* it and that we cannot have an asynchronous probe routine trying
* to run while we are tearing out the bus/class/sysfs from
* underneath the device.
*/
lockdep_assert_held(&dev->mutex);
if (dev->p->dead)
return false;
dev->p->dead = true;
return true;
}
EXPORT_SYMBOL_GPL(kill_device);
/** /**
* device_del - delete device from system. * device_del - delete device from system.
* @dev: device. * @dev: device.
...@@ -2230,15 +2251,8 @@ void device_del(struct device *dev) ...@@ -2230,15 +2251,8 @@ void device_del(struct device *dev)
struct kobject *glue_dir = NULL; struct kobject *glue_dir = NULL;
struct class_interface *class_intf; struct class_interface *class_intf;
/*
* Hold the device lock and set the "dead" flag to guarantee that
* the update behavior is consistent with the other bitfields near
* it and that we cannot have an asynchronous probe routine trying
* to run while we are tearing out the bus/class/sysfs from
* underneath the device.
*/
device_lock(dev); device_lock(dev);
dev->p->dead = true; kill_device(dev);
device_unlock(dev); device_unlock(dev);
/* Notify clients of device removal. This call must come /* Notify clients of device removal. This call must come
......
...@@ -62,14 +62,14 @@ static ssize_t sector_size_store(struct device *dev, ...@@ -62,14 +62,14 @@ static ssize_t sector_size_store(struct device *dev,
struct nd_btt *nd_btt = to_nd_btt(dev); struct nd_btt *nd_btt = to_nd_btt(dev);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
rc = nd_size_select_store(dev, buf, &nd_btt->lbasize, rc = nd_size_select_store(dev, buf, &nd_btt->lbasize,
btt_lbasize_supported); btt_lbasize_supported);
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
buf[len - 1] == '\n' ? "" : "\n"); buf[len - 1] == '\n' ? "" : "\n");
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
device_unlock(dev); nd_device_unlock(dev);
return rc ? rc : len; return rc ? rc : len;
} }
...@@ -91,11 +91,11 @@ static ssize_t uuid_store(struct device *dev, ...@@ -91,11 +91,11 @@ static ssize_t uuid_store(struct device *dev,
struct nd_btt *nd_btt = to_nd_btt(dev); struct nd_btt *nd_btt = to_nd_btt(dev);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
rc = nd_uuid_store(dev, &nd_btt->uuid, buf, len); rc = nd_uuid_store(dev, &nd_btt->uuid, buf, len);
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
buf[len - 1] == '\n' ? "" : "\n"); buf[len - 1] == '\n' ? "" : "\n");
device_unlock(dev); nd_device_unlock(dev);
return rc ? rc : len; return rc ? rc : len;
} }
...@@ -120,13 +120,13 @@ static ssize_t namespace_store(struct device *dev, ...@@ -120,13 +120,13 @@ static ssize_t namespace_store(struct device *dev,
struct nd_btt *nd_btt = to_nd_btt(dev); struct nd_btt *nd_btt = to_nd_btt(dev);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
rc = nd_namespace_store(dev, &nd_btt->ndns, buf, len); rc = nd_namespace_store(dev, &nd_btt->ndns, buf, len);
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
buf[len - 1] == '\n' ? "" : "\n"); buf[len - 1] == '\n' ? "" : "\n");
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
device_unlock(dev); nd_device_unlock(dev);
return rc; return rc;
} }
...@@ -138,14 +138,14 @@ static ssize_t size_show(struct device *dev, ...@@ -138,14 +138,14 @@ static ssize_t size_show(struct device *dev,
struct nd_btt *nd_btt = to_nd_btt(dev); struct nd_btt *nd_btt = to_nd_btt(dev);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
if (dev->driver) if (dev->driver)
rc = sprintf(buf, "%llu\n", nd_btt->size); rc = sprintf(buf, "%llu\n", nd_btt->size);
else { else {
/* no size to convey if the btt instance is disabled */ /* no size to convey if the btt instance is disabled */
rc = -ENXIO; rc = -ENXIO;
} }
device_unlock(dev); nd_device_unlock(dev);
return rc; return rc;
} }
......
This diff is collapsed.
...@@ -246,7 +246,7 @@ static int nd_uuid_parse(struct device *dev, u8 *uuid_out, const char *buf, ...@@ -246,7 +246,7 @@ static int nd_uuid_parse(struct device *dev, u8 *uuid_out, const char *buf,
* *
* Enforce that uuids can only be changed while the device is disabled * Enforce that uuids can only be changed while the device is disabled
* (driver detached) * (driver detached)
* LOCKING: expects device_lock() is held on entry * LOCKING: expects nd_device_lock() is held on entry
*/ */
int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf, int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf,
size_t len) size_t len)
...@@ -347,15 +347,15 @@ static DEVICE_ATTR_RO(provider); ...@@ -347,15 +347,15 @@ static DEVICE_ATTR_RO(provider);
static int flush_namespaces(struct device *dev, void *data) static int flush_namespaces(struct device *dev, void *data)
{ {
device_lock(dev); nd_device_lock(dev);
device_unlock(dev); nd_device_unlock(dev);
return 0; return 0;
} }
static int flush_regions_dimms(struct device *dev, void *data) static int flush_regions_dimms(struct device *dev, void *data)
{ {
device_lock(dev); nd_device_lock(dev);
device_unlock(dev); nd_device_unlock(dev);
device_for_each_child(dev, NULL, flush_namespaces); device_for_each_child(dev, NULL, flush_namespaces);
return 0; return 0;
} }
......
...@@ -484,12 +484,12 @@ static ssize_t security_store(struct device *dev, ...@@ -484,12 +484,12 @@ static ssize_t security_store(struct device *dev,
* done while probing is idle and the DIMM is not in active use * done while probing is idle and the DIMM is not in active use
* in any region. * in any region.
*/ */
device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev); wait_nvdimm_bus_probe_idle(dev);
rc = __security_store(dev, buf, len); rc = __security_store(dev, buf, len);
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
device_unlock(dev); nd_device_unlock(dev);
return rc; return rc;
} }
......
...@@ -410,7 +410,7 @@ static ssize_t alt_name_store(struct device *dev, ...@@ -410,7 +410,7 @@ static ssize_t alt_name_store(struct device *dev,
struct nd_region *nd_region = to_nd_region(dev->parent); struct nd_region *nd_region = to_nd_region(dev->parent);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev); wait_nvdimm_bus_probe_idle(dev);
rc = __alt_name_store(dev, buf, len); rc = __alt_name_store(dev, buf, len);
...@@ -418,7 +418,7 @@ static ssize_t alt_name_store(struct device *dev, ...@@ -418,7 +418,7 @@ static ssize_t alt_name_store(struct device *dev,
rc = nd_namespace_label_update(nd_region, dev); rc = nd_namespace_label_update(nd_region, dev);
dev_dbg(dev, "%s(%zd)\n", rc < 0 ? "fail " : "", rc); dev_dbg(dev, "%s(%zd)\n", rc < 0 ? "fail " : "", rc);
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
device_unlock(dev); nd_device_unlock(dev);
return rc < 0 ? rc : len; return rc < 0 ? rc : len;
} }
...@@ -1077,7 +1077,7 @@ static ssize_t size_store(struct device *dev, ...@@ -1077,7 +1077,7 @@ static ssize_t size_store(struct device *dev,
if (rc) if (rc)
return rc; return rc;
device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev); wait_nvdimm_bus_probe_idle(dev);
rc = __size_store(dev, val); rc = __size_store(dev, val);
...@@ -1103,7 +1103,7 @@ static ssize_t size_store(struct device *dev, ...@@ -1103,7 +1103,7 @@ static ssize_t size_store(struct device *dev,
dev_dbg(dev, "%llx %s (%d)\n", val, rc < 0 ? "fail" : "success", rc); dev_dbg(dev, "%llx %s (%d)\n", val, rc < 0 ? "fail" : "success", rc);
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
device_unlock(dev); nd_device_unlock(dev);
return rc < 0 ? rc : len; return rc < 0 ? rc : len;
} }
...@@ -1286,7 +1286,7 @@ static ssize_t uuid_store(struct device *dev, ...@@ -1286,7 +1286,7 @@ static ssize_t uuid_store(struct device *dev,
} else } else
return -ENXIO; return -ENXIO;
device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev); wait_nvdimm_bus_probe_idle(dev);
if (to_ndns(dev)->claim) if (to_ndns(dev)->claim)
...@@ -1302,7 +1302,7 @@ static ssize_t uuid_store(struct device *dev, ...@@ -1302,7 +1302,7 @@ static ssize_t uuid_store(struct device *dev,
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
buf[len - 1] == '\n' ? "" : "\n"); buf[len - 1] == '\n' ? "" : "\n");
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
device_unlock(dev); nd_device_unlock(dev);
return rc < 0 ? rc : len; return rc < 0 ? rc : len;
} }
...@@ -1376,7 +1376,7 @@ static ssize_t sector_size_store(struct device *dev, ...@@ -1376,7 +1376,7 @@ static ssize_t sector_size_store(struct device *dev,
} else } else
return -ENXIO; return -ENXIO;
device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
if (to_ndns(dev)->claim) if (to_ndns(dev)->claim)
rc = -EBUSY; rc = -EBUSY;
...@@ -1387,7 +1387,7 @@ static ssize_t sector_size_store(struct device *dev, ...@@ -1387,7 +1387,7 @@ static ssize_t sector_size_store(struct device *dev,
dev_dbg(dev, "result: %zd %s: %s%s", rc, rc < 0 ? "tried" : "wrote", dev_dbg(dev, "result: %zd %s: %s%s", rc, rc < 0 ? "tried" : "wrote",
buf, buf[len - 1] == '\n' ? "" : "\n"); buf, buf[len - 1] == '\n' ? "" : "\n");
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
device_unlock(dev); nd_device_unlock(dev);
return rc ? rc : len; return rc ? rc : len;
} }
...@@ -1502,9 +1502,9 @@ static ssize_t holder_show(struct device *dev, ...@@ -1502,9 +1502,9 @@ static ssize_t holder_show(struct device *dev,
struct nd_namespace_common *ndns = to_ndns(dev); struct nd_namespace_common *ndns = to_ndns(dev);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
rc = sprintf(buf, "%s\n", ndns->claim ? dev_name(ndns->claim) : ""); rc = sprintf(buf, "%s\n", ndns->claim ? dev_name(ndns->claim) : "");
device_unlock(dev); nd_device_unlock(dev);
return rc; return rc;
} }
...@@ -1541,7 +1541,7 @@ static ssize_t holder_class_store(struct device *dev, ...@@ -1541,7 +1541,7 @@ static ssize_t holder_class_store(struct device *dev,
struct nd_region *nd_region = to_nd_region(dev->parent); struct nd_region *nd_region = to_nd_region(dev->parent);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev); wait_nvdimm_bus_probe_idle(dev);
rc = __holder_class_store(dev, buf); rc = __holder_class_store(dev, buf);
...@@ -1549,7 +1549,7 @@ static ssize_t holder_class_store(struct device *dev, ...@@ -1549,7 +1549,7 @@ static ssize_t holder_class_store(struct device *dev,
rc = nd_namespace_label_update(nd_region, dev); rc = nd_namespace_label_update(nd_region, dev);
dev_dbg(dev, "%s(%zd)\n", rc < 0 ? "fail " : "", rc); dev_dbg(dev, "%s(%zd)\n", rc < 0 ? "fail " : "", rc);
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
device_unlock(dev); nd_device_unlock(dev);
return rc < 0 ? rc : len; return rc < 0 ? rc : len;
} }
...@@ -1560,7 +1560,7 @@ static ssize_t holder_class_show(struct device *dev, ...@@ -1560,7 +1560,7 @@ static ssize_t holder_class_show(struct device *dev,
struct nd_namespace_common *ndns = to_ndns(dev); struct nd_namespace_common *ndns = to_ndns(dev);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
if (ndns->claim_class == NVDIMM_CCLASS_NONE) if (ndns->claim_class == NVDIMM_CCLASS_NONE)
rc = sprintf(buf, "\n"); rc = sprintf(buf, "\n");
else if ((ndns->claim_class == NVDIMM_CCLASS_BTT) || else if ((ndns->claim_class == NVDIMM_CCLASS_BTT) ||
...@@ -1572,7 +1572,7 @@ static ssize_t holder_class_show(struct device *dev, ...@@ -1572,7 +1572,7 @@ static ssize_t holder_class_show(struct device *dev,
rc = sprintf(buf, "dax\n"); rc = sprintf(buf, "dax\n");
else else
rc = sprintf(buf, "<unknown>\n"); rc = sprintf(buf, "<unknown>\n");
device_unlock(dev); nd_device_unlock(dev);
return rc; return rc;
} }
...@@ -1586,7 +1586,7 @@ static ssize_t mode_show(struct device *dev, ...@@ -1586,7 +1586,7 @@ static ssize_t mode_show(struct device *dev,
char *mode; char *mode;
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
claim = ndns->claim; claim = ndns->claim;
if (claim && is_nd_btt(claim)) if (claim && is_nd_btt(claim))
mode = "safe"; mode = "safe";
...@@ -1599,7 +1599,7 @@ static ssize_t mode_show(struct device *dev, ...@@ -1599,7 +1599,7 @@ static ssize_t mode_show(struct device *dev,
else else
mode = "raw"; mode = "raw";
rc = sprintf(buf, "%s\n", mode); rc = sprintf(buf, "%s\n", mode);
device_unlock(dev); nd_device_unlock(dev);
return rc; return rc;
} }
...@@ -1703,8 +1703,8 @@ struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev) ...@@ -1703,8 +1703,8 @@ struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev)
* Flush any in-progess probes / removals in the driver * Flush any in-progess probes / removals in the driver
* for the raw personality of this namespace. * for the raw personality of this namespace.
*/ */
device_lock(&ndns->dev); nd_device_lock(&ndns->dev);
device_unlock(&ndns->dev); nd_device_unlock(&ndns->dev);
if (ndns->dev.driver) { if (ndns->dev.driver) {
dev_dbg(&ndns->dev, "is active, can't bind %s\n", dev_dbg(&ndns->dev, "is active, can't bind %s\n",
dev_name(dev)); dev_name(dev));
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/nd.h> #include <linux/nd.h>
#include "nd.h"
extern struct list_head nvdimm_bus_list; extern struct list_head nvdimm_bus_list;
extern struct mutex nvdimm_bus_list_mutex; extern struct mutex nvdimm_bus_list_mutex;
...@@ -17,10 +18,11 @@ extern struct workqueue_struct *nvdimm_wq; ...@@ -17,10 +18,11 @@ extern struct workqueue_struct *nvdimm_wq;
struct nvdimm_bus { struct nvdimm_bus {
struct nvdimm_bus_descriptor *nd_desc; struct nvdimm_bus_descriptor *nd_desc;
wait_queue_head_t probe_wait; wait_queue_head_t wait;
struct list_head list; struct list_head list;
struct device dev; struct device dev;
int id, probe_active; int id, probe_active;
atomic_t ioctl_active;
struct list_head mapping_list; struct list_head mapping_list;
struct mutex reconfig_mutex; struct mutex reconfig_mutex;
struct badrange badrange; struct badrange badrange;
...@@ -181,4 +183,71 @@ ssize_t nd_namespace_store(struct device *dev, ...@@ -181,4 +183,71 @@ ssize_t nd_namespace_store(struct device *dev,
struct nd_namespace_common **_ndns, const char *buf, struct nd_namespace_common **_ndns, const char *buf,
size_t len); size_t len);
struct nd_pfn *to_nd_pfn_safe(struct device *dev); struct nd_pfn *to_nd_pfn_safe(struct device *dev);
bool is_nvdimm_bus(struct device *dev);
#ifdef CONFIG_PROVE_LOCKING
extern struct class *nd_class;
enum {
LOCK_BUS,
LOCK_NDCTL,
LOCK_REGION,
LOCK_DIMM = LOCK_REGION,
LOCK_NAMESPACE,
LOCK_CLAIM,
};
static inline void debug_nvdimm_lock(struct device *dev)
{
if (is_nd_region(dev))
mutex_lock_nested(&dev->lockdep_mutex, LOCK_REGION);
else if (is_nvdimm(dev))
mutex_lock_nested(&dev->lockdep_mutex, LOCK_DIMM);
else if (is_nd_btt(dev) || is_nd_pfn(dev) || is_nd_dax(dev))
mutex_lock_nested(&dev->lockdep_mutex, LOCK_CLAIM);
else if (dev->parent && (is_nd_region(dev->parent)))
mutex_lock_nested(&dev->lockdep_mutex, LOCK_NAMESPACE);
else if (is_nvdimm_bus(dev))
mutex_lock_nested(&dev->lockdep_mutex, LOCK_BUS);
else if (dev->class && dev->class == nd_class)
mutex_lock_nested(&dev->lockdep_mutex, LOCK_NDCTL);
else
dev_WARN(dev, "unknown lock level\n");
}
static inline void debug_nvdimm_unlock(struct device *dev)
{
mutex_unlock(&dev->lockdep_mutex);
}
static inline void nd_device_lock(struct device *dev)
{
device_lock(dev);
debug_nvdimm_lock(dev);
}
static inline void nd_device_unlock(struct device *dev)
{
debug_nvdimm_unlock(dev);
device_unlock(dev);
}
#else
static inline void nd_device_lock(struct device *dev)
{
device_lock(dev);
}
static inline void nd_device_unlock(struct device *dev)
{
device_unlock(dev);
}
static inline void debug_nvdimm_lock(struct device *dev)
{
}
static inline void debug_nvdimm_unlock(struct device *dev)
{
}
#endif
#endif /* __ND_CORE_H__ */ #endif /* __ND_CORE_H__ */
...@@ -67,7 +67,7 @@ static ssize_t mode_store(struct device *dev, ...@@ -67,7 +67,7 @@ static ssize_t mode_store(struct device *dev,
struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev); struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
ssize_t rc = 0; ssize_t rc = 0;
device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
if (dev->driver) if (dev->driver)
rc = -EBUSY; rc = -EBUSY;
...@@ -89,7 +89,7 @@ static ssize_t mode_store(struct device *dev, ...@@ -89,7 +89,7 @@ static ssize_t mode_store(struct device *dev,
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
buf[len - 1] == '\n' ? "" : "\n"); buf[len - 1] == '\n' ? "" : "\n");
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
device_unlock(dev); nd_device_unlock(dev);
return rc ? rc : len; return rc ? rc : len;
} }
...@@ -132,14 +132,14 @@ static ssize_t align_store(struct device *dev, ...@@ -132,14 +132,14 @@ static ssize_t align_store(struct device *dev,
struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev); struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
rc = nd_size_select_store(dev, buf, &nd_pfn->align, rc = nd_size_select_store(dev, buf, &nd_pfn->align,
nd_pfn_supported_alignments()); nd_pfn_supported_alignments());
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
buf[len - 1] == '\n' ? "" : "\n"); buf[len - 1] == '\n' ? "" : "\n");
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
device_unlock(dev); nd_device_unlock(dev);
return rc ? rc : len; return rc ? rc : len;
} }
...@@ -161,11 +161,11 @@ static ssize_t uuid_store(struct device *dev, ...@@ -161,11 +161,11 @@ static ssize_t uuid_store(struct device *dev,
struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev); struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
rc = nd_uuid_store(dev, &nd_pfn->uuid, buf, len); rc = nd_uuid_store(dev, &nd_pfn->uuid, buf, len);
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
buf[len - 1] == '\n' ? "" : "\n"); buf[len - 1] == '\n' ? "" : "\n");
device_unlock(dev); nd_device_unlock(dev);
return rc ? rc : len; return rc ? rc : len;
} }
...@@ -190,13 +190,13 @@ static ssize_t namespace_store(struct device *dev, ...@@ -190,13 +190,13 @@ static ssize_t namespace_store(struct device *dev,
struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev); struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
rc = nd_namespace_store(dev, &nd_pfn->ndns, buf, len); rc = nd_namespace_store(dev, &nd_pfn->ndns, buf, len);
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
buf[len - 1] == '\n' ? "" : "\n"); buf[len - 1] == '\n' ? "" : "\n");
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
device_unlock(dev); nd_device_unlock(dev);
return rc; return rc;
} }
...@@ -208,7 +208,7 @@ static ssize_t resource_show(struct device *dev, ...@@ -208,7 +208,7 @@ static ssize_t resource_show(struct device *dev,
struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev); struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
if (dev->driver) { if (dev->driver) {
struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
u64 offset = __le64_to_cpu(pfn_sb->dataoff); u64 offset = __le64_to_cpu(pfn_sb->dataoff);
...@@ -222,7 +222,7 @@ static ssize_t resource_show(struct device *dev, ...@@ -222,7 +222,7 @@ static ssize_t resource_show(struct device *dev,
/* no address to convey if the pfn instance is disabled */ /* no address to convey if the pfn instance is disabled */
rc = -ENXIO; rc = -ENXIO;
} }
device_unlock(dev); nd_device_unlock(dev);
return rc; return rc;
} }
...@@ -234,7 +234,7 @@ static ssize_t size_show(struct device *dev, ...@@ -234,7 +234,7 @@ static ssize_t size_show(struct device *dev,
struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev); struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
if (dev->driver) { if (dev->driver) {
struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
u64 offset = __le64_to_cpu(pfn_sb->dataoff); u64 offset = __le64_to_cpu(pfn_sb->dataoff);
...@@ -250,7 +250,7 @@ static ssize_t size_show(struct device *dev, ...@@ -250,7 +250,7 @@ static ssize_t size_show(struct device *dev,
/* no size to convey if the pfn instance is disabled */ /* no size to convey if the pfn instance is disabled */
rc = -ENXIO; rc = -ENXIO;
} }
device_unlock(dev); nd_device_unlock(dev);
return rc; return rc;
} }
......
...@@ -522,8 +522,8 @@ static int nd_pmem_remove(struct device *dev) ...@@ -522,8 +522,8 @@ static int nd_pmem_remove(struct device *dev)
nvdimm_namespace_detach_btt(to_nd_btt(dev)); nvdimm_namespace_detach_btt(to_nd_btt(dev));
else { else {
/* /*
* Note, this assumes device_lock() context to not race * Note, this assumes nd_device_lock() context to not
* nd_pmem_notify() * race nd_pmem_notify()
*/ */
sysfs_put(pmem->bb_state); sysfs_put(pmem->bb_state);
pmem->bb_state = NULL; pmem->bb_state = NULL;
......
...@@ -34,17 +34,6 @@ static int nd_region_probe(struct device *dev) ...@@ -34,17 +34,6 @@ static int nd_region_probe(struct device *dev)
if (rc) if (rc)
return rc; return rc;
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;
if (is_nd_pmem(&nd_region->dev)) { if (is_nd_pmem(&nd_region->dev)) {
struct resource ndr_res; struct resource ndr_res;
...@@ -60,6 +49,17 @@ static int nd_region_probe(struct device *dev) ...@@ -60,6 +49,17 @@ static int nd_region_probe(struct device *dev)
nvdimm_badblocks_populate(nd_region, &nd_region->bb, &ndr_res); 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->btt_seed = nd_btt_create(nd_region);
nd_region->pfn_seed = nd_pfn_create(nd_region); nd_region->pfn_seed = nd_pfn_create(nd_region);
nd_region->dax_seed = nd_dax_create(nd_region); nd_region->dax_seed = nd_dax_create(nd_region);
...@@ -102,7 +102,7 @@ static int nd_region_remove(struct device *dev) ...@@ -102,7 +102,7 @@ static int nd_region_remove(struct device *dev)
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
/* /*
* Note, this assumes device_lock() context to not race * Note, this assumes nd_device_lock() context to not race
* nd_region_notify() * nd_region_notify()
*/ */
sysfs_put(nd_region->bb_state); sysfs_put(nd_region->bb_state);
......
...@@ -331,7 +331,7 @@ static ssize_t set_cookie_show(struct device *dev, ...@@ -331,7 +331,7 @@ static ssize_t set_cookie_show(struct device *dev,
* the v1.1 namespace label cookie definition. To read all this * the v1.1 namespace label cookie definition. To read all this
* data we need to wait for probing to settle. * data we need to wait for probing to settle.
*/ */
device_lock(dev); nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev); wait_nvdimm_bus_probe_idle(dev);
if (nd_region->ndr_mappings) { if (nd_region->ndr_mappings) {
...@@ -348,7 +348,7 @@ static ssize_t set_cookie_show(struct device *dev, ...@@ -348,7 +348,7 @@ static ssize_t set_cookie_show(struct device *dev,
} }
} }
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
device_unlock(dev); nd_device_unlock(dev);
if (rc) if (rc)
return rc; return rc;
...@@ -424,10 +424,12 @@ static ssize_t available_size_show(struct device *dev, ...@@ -424,10 +424,12 @@ static ssize_t available_size_show(struct device *dev,
* memory nvdimm_bus_lock() is dropped, but that's userspace's * memory nvdimm_bus_lock() is dropped, but that's userspace's
* problem to not race itself. * problem to not race itself.
*/ */
nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev); wait_nvdimm_bus_probe_idle(dev);
available = nd_region_available_dpa(nd_region); available = nd_region_available_dpa(nd_region);
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
nd_device_unlock(dev);
return sprintf(buf, "%llu\n", available); return sprintf(buf, "%llu\n", available);
} }
...@@ -439,10 +441,12 @@ static ssize_t max_available_extent_show(struct device *dev, ...@@ -439,10 +441,12 @@ static ssize_t max_available_extent_show(struct device *dev,
struct nd_region *nd_region = to_nd_region(dev); struct nd_region *nd_region = to_nd_region(dev);
unsigned long long available = 0; unsigned long long available = 0;
nd_device_lock(dev);
nvdimm_bus_lock(dev); nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev); wait_nvdimm_bus_probe_idle(dev);
available = nd_region_allocatable_dpa(nd_region); available = nd_region_allocatable_dpa(nd_region);
nvdimm_bus_unlock(dev); nvdimm_bus_unlock(dev);
nd_device_unlock(dev);
return sprintf(buf, "%llu\n", available); return sprintf(buf, "%llu\n", available);
} }
...@@ -561,12 +565,12 @@ static ssize_t region_badblocks_show(struct device *dev, ...@@ -561,12 +565,12 @@ static ssize_t region_badblocks_show(struct device *dev,
struct nd_region *nd_region = to_nd_region(dev); struct nd_region *nd_region = to_nd_region(dev);
ssize_t rc; ssize_t rc;
device_lock(dev); nd_device_lock(dev);
if (dev->driver) if (dev->driver)
rc = badblocks_show(&nd_region->bb, buf, 0); rc = badblocks_show(&nd_region->bb, buf, 0);
else else
rc = -ENXIO; rc = -ENXIO;
device_unlock(dev); nd_device_unlock(dev);
return rc; return rc;
} }
......
...@@ -915,6 +915,8 @@ struct dev_links_info { ...@@ -915,6 +915,8 @@ struct dev_links_info {
* This identifies the device type and carries type-specific * This identifies the device type and carries type-specific
* information. * information.
* @mutex: Mutex to synchronize calls to its driver. * @mutex: Mutex to synchronize calls to its driver.
* @lockdep_mutex: An optional debug lock that a subsystem can use as a
* peer lock to gain localized lockdep coverage of the device_lock.
* @bus: Type of bus device is on. * @bus: Type of bus device is on.
* @driver: Which driver has allocated this * @driver: Which driver has allocated this
* @platform_data: Platform data specific to the device. * @platform_data: Platform data specific to the device.
...@@ -998,6 +1000,9 @@ struct device { ...@@ -998,6 +1000,9 @@ struct device {
core doesn't touch it */ core doesn't touch it */
void *driver_data; /* Driver data, set and get with void *driver_data; /* Driver data, set and get with
dev_set_drvdata/dev_get_drvdata */ dev_set_drvdata/dev_get_drvdata */
#ifdef CONFIG_PROVE_LOCKING
struct mutex lockdep_mutex;
#endif
struct mutex mutex; /* mutex to synchronize calls to struct mutex mutex; /* mutex to synchronize calls to
* its driver. * its driver.
*/ */
...@@ -1383,6 +1388,7 @@ extern int (*platform_notify_remove)(struct device *dev); ...@@ -1383,6 +1388,7 @@ extern int (*platform_notify_remove)(struct device *dev);
*/ */
extern struct device *get_device(struct device *dev); extern struct device *get_device(struct device *dev);
extern void put_device(struct device *dev); extern void put_device(struct device *dev);
extern bool kill_device(struct device *dev);
#ifdef CONFIG_DEVTMPFS #ifdef CONFIG_DEVTMPFS
extern int devtmpfs_create_node(struct device *dev); extern int devtmpfs_create_node(struct device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment