All of lore.kernel.org
 help / color / mirror / Atom feed
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))

  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: link
Be 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.