From: Dan Williams <dan.j.williams@intel.com> To: linux-nvdimm@lists.01.org Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>, david@fromorbit.com, linux-kernel@vger.kernel.org, hch@lst.de Subject: [PATCH 01/13] driver core, libnvdimm: disable manual unbind of dimms while region active Date: Sat, 04 Jun 2016 13:52:38 -0700 [thread overview] Message-ID: <146507355828.8347.11600179233094511139.stgit@dwillia2-desk3.amr.corp.intel.com> (raw) In-Reply-To: <146507355220.8347.12117020810872172684.stgit@dwillia2-desk3.amr.corp.intel.com> There are scenarios where we need a middle ground between disabling all manual bind/unbind attempts (via driver->suppress_bind_attrs) and allowing unbind at any userspace-determined time. Pinning modules takes away one vector for unwanted out-of-sequence device_release_driver() invocations, this new mechanism (via device->suppress_unbind_attr) takes away another. The first user of this mechanism is the libnvdimm sub-system where manual dimm disabling should be prevented while the dimm is active in any region. Note that there is a 1:N dimm-to-region relationship which is why this is implemented as a disable count rather than a flag. This forces userspace to disable regions before dimms when manually shutting down a bus topology. This does not affect any of the kernel-internal initiated invocations of device_release_driver(). Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- drivers/base/base.h | 1 + drivers/base/bus.c | 12 ++++++++++-- drivers/base/core.c | 1 + drivers/base/dd.c | 2 +- drivers/nvdimm/namespace_devs.c | 1 + drivers/nvdimm/region_devs.c | 4 +++- include/linux/device.h | 20 ++++++++++++++++++++ 7 files changed, 37 insertions(+), 4 deletions(-) diff --git a/drivers/base/base.h b/drivers/base/base.h index e05db388bd1c..129814b17ca6 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -109,6 +109,7 @@ extern int bus_add_driver(struct device_driver *drv); extern void bus_remove_driver(struct device_driver *drv); extern void driver_detach(struct device_driver *drv); +extern void __device_release_driver(struct device *dev); extern int driver_probe_device(struct device_driver *drv, struct device *dev); extern void driver_deferred_probe_del(struct device *dev); static inline int driver_match_device(struct device_driver *drv, diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 6470eb8088f4..b48a903f2d28 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -188,10 +188,18 @@ static ssize_t unbind_store(struct device_driver *drv, const char *buf, if (dev && dev->driver == drv) { if (dev->parent) /* Needed for USB */ device_lock(dev->parent); - device_release_driver(dev); + + device_lock(dev); + if (atomic_read(&dev->suppress_unbind_attr) > 0) + err = -EBUSY; + else { + __device_release_driver(dev); + err = count; + } + device_unlock(dev); + if (dev->parent) device_unlock(dev->parent); - err = count; } put_device(dev); bus_put(bus); diff --git a/drivers/base/core.c b/drivers/base/core.c index 0a8bdade53f2..0ea0e8560e1d 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -708,6 +708,7 @@ void device_initialize(struct device *dev) INIT_LIST_HEAD(&dev->devres_head); device_pm_init(dev); set_dev_node(dev, -1); + atomic_set(&dev->suppress_unbind_attr, 0); #ifdef CONFIG_GENERIC_MSI_IRQ INIT_LIST_HEAD(&dev->msi_list); #endif diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 16688f50729c..9e21817ca2d6 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -756,7 +756,7 @@ EXPORT_SYMBOL_GPL(driver_attach); * __device_release_driver() must be called with @dev lock held. * When called for a USB interface, @dev->parent lock must be held as well. */ -static void __device_release_driver(struct device *dev) +void __device_release_driver(struct device *dev) { struct device_driver *drv; diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index c5e3196c45b0..e65572b6092c 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1950,6 +1950,7 @@ static int init_active_labels(struct nd_region *nd_region) } nd_mapping->ndd = ndd; atomic_inc(&nvdimm->busy); + device_disable_unbind_attr(&nvdimm->dev); get_ndd(ndd); count = nd_label_active_count(ndd); diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 40fcfea26fbb..320f0f3ea367 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -427,8 +427,10 @@ static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus, nd_mapping->labels = NULL; put_ndd(ndd); nd_mapping->ndd = NULL; - if (ndd) + if (ndd) { atomic_dec(&nvdimm->busy); + device_enable_unbind_attr(&nvdimm->dev); + } } if (is_nd_pmem(dev)) diff --git a/include/linux/device.h b/include/linux/device.h index 38f02814d53a..d9eaa85bb9cf 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -849,6 +849,7 @@ struct device { void (*release)(struct device *dev); struct iommu_group *iommu_group; + atomic_t suppress_unbind_attr; /* disable manual unbind */ bool offline_disabled:1; bool offline:1; @@ -988,6 +989,25 @@ static inline void device_lock_assert(struct device *dev) lockdep_assert_held(&dev->mutex); } +static inline bool device_disable_unbind_attr(struct device *dev) +{ + bool suppressed = false; + + device_lock(dev); + if (dev->driver) { + atomic_inc(&dev->suppress_unbind_attr); + suppressed = true; + } + device_unlock(dev); + + return suppressed; +} + +static inline bool device_enable_unbind_attr(struct device *dev) +{ + return atomic_dec_and_test(&dev->suppress_unbind_attr); +} + static inline struct device_node *dev_of_node(struct device *dev) { if (!IS_ENABLED(CONFIG_OF)) _______________________________________________ Linux-nvdimm mailing list Linux-nvdimm@lists.01.org https://lists.01.org/mailman/listinfo/linux-nvdimm
WARNING: multiple messages have this Message-ID (diff)
From: Dan Williams <dan.j.williams@intel.com> To: linux-nvdimm@ml01.01.org Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>, david@fromorbit.com, linux-kernel@vger.kernel.org, hch@lst.de Subject: [PATCH 01/13] driver core, libnvdimm: disable manual unbind of dimms while region active Date: Sat, 04 Jun 2016 13:52:38 -0700 [thread overview] Message-ID: <146507355828.8347.11600179233094511139.stgit@dwillia2-desk3.amr.corp.intel.com> (raw) In-Reply-To: <146507355220.8347.12117020810872172684.stgit@dwillia2-desk3.amr.corp.intel.com> There are scenarios where we need a middle ground between disabling all manual bind/unbind attempts (via driver->suppress_bind_attrs) and allowing unbind at any userspace-determined time. Pinning modules takes away one vector for unwanted out-of-sequence device_release_driver() invocations, this new mechanism (via device->suppress_unbind_attr) takes away another. The first user of this mechanism is the libnvdimm sub-system where manual dimm disabling should be prevented while the dimm is active in any region. Note that there is a 1:N dimm-to-region relationship which is why this is implemented as a disable count rather than a flag. This forces userspace to disable regions before dimms when manually shutting down a bus topology. This does not affect any of the kernel-internal initiated invocations of device_release_driver(). Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- drivers/base/base.h | 1 + drivers/base/bus.c | 12 ++++++++++-- drivers/base/core.c | 1 + drivers/base/dd.c | 2 +- drivers/nvdimm/namespace_devs.c | 1 + drivers/nvdimm/region_devs.c | 4 +++- include/linux/device.h | 20 ++++++++++++++++++++ 7 files changed, 37 insertions(+), 4 deletions(-) diff --git a/drivers/base/base.h b/drivers/base/base.h index e05db388bd1c..129814b17ca6 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -109,6 +109,7 @@ extern int bus_add_driver(struct device_driver *drv); extern void bus_remove_driver(struct device_driver *drv); extern void driver_detach(struct device_driver *drv); +extern void __device_release_driver(struct device *dev); extern int driver_probe_device(struct device_driver *drv, struct device *dev); extern void driver_deferred_probe_del(struct device *dev); static inline int driver_match_device(struct device_driver *drv, diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 6470eb8088f4..b48a903f2d28 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -188,10 +188,18 @@ static ssize_t unbind_store(struct device_driver *drv, const char *buf, if (dev && dev->driver == drv) { if (dev->parent) /* Needed for USB */ device_lock(dev->parent); - device_release_driver(dev); + + device_lock(dev); + if (atomic_read(&dev->suppress_unbind_attr) > 0) + err = -EBUSY; + else { + __device_release_driver(dev); + err = count; + } + device_unlock(dev); + if (dev->parent) device_unlock(dev->parent); - err = count; } put_device(dev); bus_put(bus); diff --git a/drivers/base/core.c b/drivers/base/core.c index 0a8bdade53f2..0ea0e8560e1d 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -708,6 +708,7 @@ void device_initialize(struct device *dev) INIT_LIST_HEAD(&dev->devres_head); device_pm_init(dev); set_dev_node(dev, -1); + atomic_set(&dev->suppress_unbind_attr, 0); #ifdef CONFIG_GENERIC_MSI_IRQ INIT_LIST_HEAD(&dev->msi_list); #endif diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 16688f50729c..9e21817ca2d6 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -756,7 +756,7 @@ EXPORT_SYMBOL_GPL(driver_attach); * __device_release_driver() must be called with @dev lock held. * When called for a USB interface, @dev->parent lock must be held as well. */ -static void __device_release_driver(struct device *dev) +void __device_release_driver(struct device *dev) { struct device_driver *drv; diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index c5e3196c45b0..e65572b6092c 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1950,6 +1950,7 @@ static int init_active_labels(struct nd_region *nd_region) } nd_mapping->ndd = ndd; atomic_inc(&nvdimm->busy); + device_disable_unbind_attr(&nvdimm->dev); get_ndd(ndd); count = nd_label_active_count(ndd); diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 40fcfea26fbb..320f0f3ea367 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -427,8 +427,10 @@ static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus, nd_mapping->labels = NULL; put_ndd(ndd); nd_mapping->ndd = NULL; - if (ndd) + if (ndd) { atomic_dec(&nvdimm->busy); + device_enable_unbind_attr(&nvdimm->dev); + } } if (is_nd_pmem(dev)) diff --git a/include/linux/device.h b/include/linux/device.h index 38f02814d53a..d9eaa85bb9cf 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -849,6 +849,7 @@ struct device { void (*release)(struct device *dev); struct iommu_group *iommu_group; + atomic_t suppress_unbind_attr; /* disable manual unbind */ bool offline_disabled:1; bool offline:1; @@ -988,6 +989,25 @@ static inline void device_lock_assert(struct device *dev) lockdep_assert_held(&dev->mutex); } +static inline bool device_disable_unbind_attr(struct device *dev) +{ + bool suppressed = false; + + device_lock(dev); + if (dev->driver) { + atomic_inc(&dev->suppress_unbind_attr); + suppressed = true; + } + device_unlock(dev); + + return suppressed; +} + +static inline bool device_enable_unbind_attr(struct device *dev) +{ + return atomic_dec_and_test(&dev->suppress_unbind_attr); +} + static inline struct device_node *dev_of_node(struct device *dev) { if (!IS_ENABLED(CONFIG_OF))
next prev parent reply other threads:[~2016-06-04 20:53 UTC|newest] Thread overview: 73+ messages / expand[flat|nested] mbox.gz Atom feed top 2016-06-04 20:52 [PATCH 00/13] deprecate pcommit Dan Williams 2016-06-04 20:52 ` Dan Williams 2016-06-04 20:52 ` Dan Williams [this message] 2016-06-04 20:52 ` [PATCH 01/13] driver core, libnvdimm: disable manual unbind of dimms while region active Dan Williams 2016-06-04 21:10 ` Greg Kroah-Hartman 2016-06-04 21:10 ` Greg Kroah-Hartman 2016-06-04 21:39 ` Dan Williams 2016-06-04 21:39 ` Dan Williams 2016-06-04 21:45 ` Greg Kroah-Hartman 2016-06-04 21:45 ` Greg Kroah-Hartman 2016-06-04 21:48 ` Dan Williams 2016-06-04 21:48 ` Dan Williams 2016-06-04 21:50 ` kbuild test robot 2016-06-04 21:50 ` kbuild test robot 2016-06-06 19:25 ` Linda Knippers 2016-06-06 19:25 ` Linda Knippers 2016-06-06 19:31 ` Dan Williams 2016-06-06 19:31 ` Dan Williams 2016-06-06 19:36 ` Dan Williams 2016-06-06 19:36 ` Dan Williams 2016-06-06 19:36 ` Linda Knippers 2016-06-06 19:36 ` Linda Knippers 2016-06-06 19:46 ` Dan Williams 2016-06-06 19:46 ` Dan Williams 2016-06-06 20:20 ` Linda Knippers 2016-06-06 20:20 ` Linda Knippers 2016-06-06 20:36 ` Dan Williams 2016-06-06 20:36 ` Dan Williams 2016-06-06 21:15 ` Linda Knippers 2016-06-06 21:15 ` Linda Knippers 2016-06-04 20:52 ` [PATCH 02/13] nfit: always associate flush hints Dan Williams 2016-06-04 20:52 ` Dan Williams 2016-06-04 20:52 ` [PATCH 03/13] libnvdimm: introduce nvdimm_flush() Dan Williams 2016-06-04 20:52 ` Dan Williams 2016-06-06 17:45 ` Jeff Moyer 2016-06-04 20:52 ` [PATCH 04/13] libnvdimm, nfit: move flush hint mapping to dimm driver Dan Williams 2016-06-04 20:52 ` Dan Williams 2016-06-04 21:29 ` kbuild test robot 2016-06-04 21:29 ` kbuild test robot 2016-06-04 21:40 ` kbuild test robot 2016-06-04 21:40 ` kbuild test robot 2016-06-04 21:49 ` kbuild test robot 2016-06-04 21:49 ` kbuild test robot 2016-06-07 18:11 ` Kani, Toshimitsu 2016-06-07 18:11 ` Kani, Toshimitsu 2016-06-07 18:15 ` Dan Williams 2016-06-07 18:15 ` Dan Williams 2016-06-04 20:52 ` [PATCH 05/13] tools/testing/nvdimm: simulate multiple flush hints per-dimm Dan Williams 2016-06-04 20:52 ` Dan Williams 2016-06-04 20:53 ` [PATCH 06/13] libnvdimm: cycle flush hints per-cpu Dan Williams 2016-06-04 20:53 ` Dan Williams 2016-06-04 20:53 ` [PATCH 07/13] libnvdimm, pmem: use REQ_FUA, REQ_FLUSH for nvdimm_flush() Dan Williams 2016-06-04 20:53 ` Dan Williams 2016-06-04 20:53 ` [PATCH 08/13] fs/dax: remove wmb_pmem() Dan Williams 2016-06-04 20:53 ` Dan Williams 2016-06-04 20:53 ` [PATCH 09/13] libnvdimm, pmem: use nvdimm_flush() for namespace I/O writes Dan Williams 2016-06-04 20:53 ` Dan Williams 2016-06-04 20:53 ` [PATCH 10/13] pmem: kill wmb_pmem() Dan Williams 2016-06-04 20:53 ` Dan Williams 2016-06-04 20:53 ` [PATCH 11/13] Revert "KVM: x86: add pcommit support" Dan Williams 2016-06-04 20:53 ` Dan Williams 2016-06-06 15:14 ` Paolo Bonzini 2016-06-06 16:14 ` Dan Williams 2016-06-04 20:53 ` [PATCH 12/13] x86/insn: remove pcommit Dan Williams 2016-06-04 20:53 ` Dan Williams 2016-06-04 20:53 ` [PATCH 13/13] pmem: kill __pmem address space Dan Williams 2016-06-04 20:53 ` Dan Williams 2016-06-04 22:18 ` kbuild test robot 2016-06-04 22:18 ` kbuild test robot 2016-06-05 17:41 ` [PATCH 00/13] deprecate pcommit Andy Lutomirski 2016-06-05 17:41 ` Andy Lutomirski 2016-06-05 18:48 ` Rudoff, Andy 2016-06-05 18:48 ` Rudoff, Andy
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=146507355828.8347.11600179233094511139.stgit@dwillia2-desk3.amr.corp.intel.com \ --to=dan.j.williams@intel.com \ --cc=david@fromorbit.com \ --cc=gregkh@linuxfoundation.org \ --cc=hch@lst.de \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-nvdimm@lists.01.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.