[PATCH 0/5] of: overlay: Assorted fixes

STALE4156d

Revision v1 of 2 in this series.

13 messages, 3 authors, 2015-03-27 · open the first message on its own page

[PATCH 0/5] of: overlay: Assorted fixes

From: Pantelis Antoniou <hidden>
Date: 2015-03-17 20:31:08

The first patch makes sure that no overlays are being left over from
the unit tests.

The second puts the overlays as objects in the sysfs in
/sys/firmware/devicetree/overlays while the next one adds a master
overlay enable switch (that once is set to disabled can't be re-enabled)

The next updates the ABI docs and the final one adds me as the
maintainer for device tree overlays.

Pantelis Antoniou (5):
  of: unittest: overlay: Keep track of created overlays
  of: overlay: kobjectify overlay objects
  of: overlay: Master enable switch
  Documentation: ABI: /sys/firmware/devicetree/overlays
  MAINTAINERS: Pantelis Antoniou device tree overlay maintainer

 .../ABI/testing/sysfs-firmware-devicetree-overlays |   9 ++
 MAINTAINERS                                        |   9 ++
 drivers/of/base.c                                  |   5 +
 drivers/of/of_private.h                            |   9 ++
 drivers/of/overlay.c                               | 116 ++++++++++++++++++++-
 drivers/of/unittest.c                              |  62 +++++++++++
 6 files changed, 208 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-firmware-devicetree-overlays

-- 
1.7.12

[PATCH 2/5] of: overlay: kobjectify overlay objects

From: Pantelis Antoniou <hidden>
Date: 2015-03-17 20:31:14

We are going to need the overlays to appear on sysfs with runtime
global properties (like master enable) so turn them into kobjects.

Signed-off-by: Pantelis Antoniou <redacted>
---
 drivers/of/base.c       |  5 +++++
 drivers/of/of_private.h |  9 +++++++++
 drivers/of/overlay.c    | 52 +++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 64 insertions(+), 2 deletions(-)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index adb8764..9b4d6f9 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -192,6 +192,7 @@ int __of_attach_node_sysfs(struct device_node *np)
 static int __init of_init(void)
 {
 	struct device_node *np;
+	int ret;
 
 	/* Create the kset, and register existing nodes */
 	mutex_lock(&of_mutex);
@@ -208,6 +209,10 @@ static int __init of_init(void)
 	if (of_root)
 		proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
 
+	ret = of_overlay_init();
+	if (ret != 0)
+		pr_warn("of_init: of_overlay_init failed!\n");
+
 	return 0;
 }
 core_initcall(of_init);
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 8e882e7..120eb44 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -90,4 +90,13 @@ extern void __of_detach_node_sysfs(struct device_node *np);
 #define for_each_transaction_entry_reverse(_oft, _te) \
 	list_for_each_entry_reverse(_te, &(_oft)->te_list, node)
 
+#if defined(CONFIG_OF_OVERLAY)
+extern int of_overlay_init(void);
+#else
+static inline int of_overlay_init(void)
+{
+	return 0;
+}
+#endif
+
 #endif /* _LINUX_OF_PRIVATE_H */
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index dee9270..f17f5ef 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/idr.h>
+#include <linux/sysfs.h>
 
 #include "of_private.h"
 
@@ -51,6 +52,7 @@ struct of_overlay {
 	int count;
 	struct of_overlay_info *ovinfo_tab;
 	struct of_changeset cset;
+	struct kobject kobj;
 };
 
 static int of_overlay_apply_one(struct of_overlay *ov,
@@ -325,6 +327,24 @@ static int of_free_overlay_info(struct of_overlay *ov)
 static LIST_HEAD(ov_list);
 static DEFINE_IDR(ov_idr);
 
+static inline struct of_overlay *kobj_to_overlay(struct kobject *kobj)
+{
+	return container_of(kobj, struct of_overlay, kobj);
+}
+
+void of_overlay_release(struct kobject *kobj)
+{
+	struct of_overlay *ov = kobj_to_overlay(kobj);
+
+	kfree(ov);
+}
+
+static struct kobj_type of_overlay_ktype = {
+	.release = of_overlay_release,
+};
+
+static struct kset *ov_kset;
+
 /**
  * of_overlay_create() - Create and apply an overlay
  * @tree:	Device node containing all the overlays
@@ -350,6 +370,9 @@ int of_overlay_create(struct device_node *tree)
 
 	of_changeset_init(&ov->cset);
 
+	/* initialize kobject */
+	kobject_init(&ov->kobj, &of_overlay_ktype);
+
 	mutex_lock(&of_mutex);
 
 	id = idr_alloc(&ov_idr, ov, 0, 0, GFP_KERNEL);
@@ -385,6 +408,14 @@ int of_overlay_create(struct device_node *tree)
 		goto err_revert_overlay;
 	}
 
+	ov->kobj.kset = ov_kset;
+	err = kobject_add(&ov->kobj, NULL, "%d", id);
+	if (err != 0) {
+		pr_err("%s: kobject_add() failed for tree@%s\n",
+				__func__, tree->full_name);
+		goto err_cancel_overlay;
+	}
+
 	/* add to the tail of the overlay list */
 	list_add_tail(&ov->node, &ov_list);
 
@@ -392,6 +423,8 @@ int of_overlay_create(struct device_node *tree)
 
 	return id;
 
+err_cancel_overlay:
+	of_changeset_revert(&ov->cset);
 err_revert_overlay:
 err_abort_trans:
 	of_free_overlay_info(ov);
@@ -512,7 +545,9 @@ int of_overlay_destroy(int id)
 	of_free_overlay_info(ov);
 	idr_remove(&ov_idr, id);
 	of_changeset_destroy(&ov->cset);
-	kfree(ov);
+
+	kobject_del(&ov->kobj);
+	kobject_put(&ov->kobj);
 
 	err = 0;
 
@@ -542,7 +577,8 @@ int of_overlay_destroy_all(void)
 		of_changeset_revert(&ov->cset);
 		of_free_overlay_info(ov);
 		idr_remove(&ov_idr, ov->id);
-		kfree(ov);
+		kobject_del(&ov->kobj);
+		kobject_put(&ov->kobj);
 	}
 
 	mutex_unlock(&of_mutex);
@@ -550,3 +586,15 @@ int of_overlay_destroy_all(void)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(of_overlay_destroy_all);
+
+/* called from of_init() */
+int of_overlay_init(void)
+{
+	int rc;
+
+	ov_kset = kset_create_and_add("overlays", NULL, &of_kset->kobj);
+	if (!ov_kset)
+		return -ENOMEM;
+
+	return 0;
+}
-- 
1.7.12

[PATCH 3/5] of: overlay: Master enable switch

From: Pantelis Antoniou <hidden>
Date: 2015-03-17 20:31:18

Implement a throw once master enable switch to protect against any
further overlay applications if the administrator desires so.

Signed-off-by: Pantelis Antoniou <redacted>
---
 drivers/of/overlay.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 65 insertions(+), 1 deletion(-)
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index f17f5ef..6688797 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -21,6 +21,7 @@
 #include <linux/err.h>
 #include <linux/idr.h>
 #include <linux/sysfs.h>
+#include <linux/atomic.h>
 
 #include "of_private.h"
 
@@ -55,6 +56,9 @@ struct of_overlay {
 	struct kobject kobj;
 };
 
+/* master enable switch; once set to 0 can't be re-enabled */
+static atomic_t ov_enable = ATOMIC_INIT(1);
+
 static int of_overlay_apply_one(struct of_overlay *ov,
 		struct device_node *target, const struct device_node *overlay);
 
@@ -345,6 +349,60 @@ static struct kobj_type of_overlay_ktype = {
 
 static struct kset *ov_kset;
 
+static ssize_t enable_read(struct file *filp, struct kobject *kobj,
+		struct bin_attribute *bin_attr, char *buf,
+		loff_t offset, size_t count)
+{
+	char tbuf[3];
+
+	if (offset < 0)
+		return -EINVAL;
+
+	if (offset >= sizeof(tbuf))
+		return 0;
+
+	if (count > sizeof(tbuf) - offset)
+		count = sizeof(tbuf) - offset;
+
+	/* fill in temp */
+	tbuf[0] = '0' + atomic_read(&ov_enable);
+	tbuf[1] = '\n';
+	tbuf[2] = '\0';
+
+	/* copy to buffer */
+	memcpy(buf, tbuf + offset, count);
+
+	return count;
+}
+
+static ssize_t enable_write(struct file *filp, struct kobject *kobj,
+		struct bin_attribute *bin_attr, char *buf,
+		loff_t off, size_t count)
+{
+	int new_enable;
+
+	if (off != 0 || (buf[0] != '0' && buf[1] != '1'))
+		return -EINVAL;
+
+	new_enable = buf[0] - '0';
+	if (new_enable != 0 && new_enable != 1)
+		return -EINVAL;
+
+	/* NOP for same value */
+	if (new_enable == atomic_read(&ov_enable))
+		return count;
+
+	/* if we've disabled it, no going back */
+	if (atomic_read(&ov_enable) == 0)
+		return -EPERM;
+
+	atomic_set(&ov_enable, new_enable);
+	return count;
+}
+
+/* just a single char + '\n' + '\0' */
+static BIN_ATTR_RW(enable, 3);
+
 /**
  * of_overlay_create() - Create and apply an overlay
  * @tree:	Device node containing all the overlays
@@ -360,6 +418,10 @@ int of_overlay_create(struct device_node *tree)
 	struct of_overlay *ov;
 	int err, id;
 
+	/* administratively disabled */
+	if (!atomic_read(&ov_enable))
+		return -EPERM;
+
 	/* allocate the overlay structure */
 	ov = kzalloc(sizeof(*ov), GFP_KERNEL);
 	if (ov == NULL)
@@ -596,5 +658,7 @@ int of_overlay_init(void)
 	if (!ov_kset)
 		return -ENOMEM;
 
-	return 0;
+	rc = sysfs_create_bin_file(&ov_kset->kobj, &bin_attr_enable);
+	WARN(rc, "%s: error adding enable attribute\n", __func__);
+	return rc;
 }
-- 
1.7.12

[PATCH 5/5] MAINTAINERS: Pantelis Antoniou device tree overlay maintainer

From: Pantelis Antoniou <hidden>
Date: 2015-03-17 20:31:25

Add me as the device tree overlays maintainer.

Signed-off-by: Pantelis Antoniou <redacted>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 0e1abe8..24aa339 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7187,6 +7187,15 @@ F:	Documentation/devicetree/
 F:	arch/*/boot/dts/
 F:	include/dt-bindings/
 
+OPEN FIRMWARE AND DEVICE TREE OVERLAYS
+M:	Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+L:	devicetree@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/dynamic-resolution-notes.txt
+F:	Documentation/devicetree/overlay-notes.txt
+F:	drivers/of/overlay.c
+F:	drivers/of/resolver.c
+
 OPENRISC ARCHITECTURE
 M:	Jonas Bonn <jonas@southpole.se>
 W:	http://openrisc.net
-- 
1.7.12

[PATCH 4/5] Documentation: ABI: /sys/firmware/devicetree/overlays

From: Pantelis Antoniou <hidden>
Date: 2015-03-17 20:31:54

Documentation ABI entry for overlays sysfs entries.

Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
---
 Documentation/ABI/testing/sysfs-firmware-devicetree-overlays | 9 +++++++++
 1 file changed, 9 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
diff --git a/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
new file mode 100644
index 0000000..5a07499
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
@@ -0,0 +1,9 @@
+What:		/sys/firmware/devicetree/overlays/
+Date:		March 2015
+Contact:	Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
+Description:
+		This directory contains the applied device tree overlays of
+		the running system, as directories of the overlay id.
+
+		enable: The master enable switch, by default is 1, and when
+		        set to 0 it cannot be re-enabled for security reasons.
-- 
1.7.12

[PATCH 1/5] of: unittest: overlay: Keep track of created overlays

From: Pantelis Antoniou <hidden>
Date: 2015-03-17 20:32:23

During the course of the overlay selftests some of them remain
applied. While this does not pose a real problem, make sure you track
them and destroy them at the end of the test.

Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
---
 drivers/of/unittest.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 4e60682..c711534 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -23,6 +23,8 @@
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
 
+#include <linux/bitops.h>
+
 #include "of_private.h"
 
 static struct selftest_results {
@@ -1115,6 +1117,59 @@ static const char *overlay_path(int nr)
 
 static const char *bus_path = "/testcase-data/overlay-node/test-bus";
 
+/* it is guaranteed that overlay ids are assigned in sequence */
+#define MAX_SELFTEST_OVERLAYS	256
+static unsigned long overlay_id_bits[BITS_TO_LONGS(MAX_SELFTEST_OVERLAYS)];
+static int overlay_first_id = -1;
+
+static void of_selftest_track_overlay(int id)
+{
+	if (overlay_first_id < 0)
+		overlay_first_id = id;
+	id -= overlay_first_id;
+
+	/* we shouldn't need that many */
+	BUG_ON(id >= MAX_SELFTEST_OVERLAYS);
+	overlay_id_bits[BIT_WORD(id)] |= BIT_MASK(id);
+}
+
+static void of_selftest_untrack_overlay(int id)
+{
+	if (overlay_first_id < 0)
+		return;
+	id -= overlay_first_id;
+	BUG_ON(id >= MAX_SELFTEST_OVERLAYS);
+	overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id);
+}
+
+static void of_selftest_destroy_tracked_overlays(void)
+{
+	int id, ret, defers;
+
+	if (overlay_first_id < 0)
+		return;
+
+	/* try until no defers */
+	do {
+		defers = 0;
+		/* remove in reverse order */
+		for (id = MAX_SELFTEST_OVERLAYS - 1; id >= 0; id--) {
+			if (!(overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id)))
+				continue;
+
+			ret = of_overlay_destroy(id + overlay_first_id);
+			if (ret != 0) {
+				defers++;
+				pr_warn("%s: overlay destroy failed for #%d\n",
+					__func__, id + overlay_first_id);
+				continue;
+			}
+
+			overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id);
+		}
+	} while (defers > 0);
+}
+
 static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
 		int *overlay_id)
 {
@@ -1136,6 +1191,7 @@ static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
 		goto out;
 	}
 	id = ret;
+	of_selftest_track_overlay(id);
 
 	ret = 0;
 
@@ -1349,6 +1405,7 @@ static void of_selftest_overlay_6(void)
 			return;
 		}
 		ov_id[i] = ret;
+		of_selftest_track_overlay(ov_id[i]);
 	}
 
 	for (i = 0; i < 2; i++) {
@@ -1373,6 +1430,7 @@ static void of_selftest_overlay_6(void)
 						PDEV_OVERLAY));
 			return;
 		}
+		of_selftest_untrack_overlay(ov_id[i]);
 	}
 
 	for (i = 0; i < 2; i++) {
@@ -1417,6 +1475,7 @@ static void of_selftest_overlay_8(void)
 			return;
 		}
 		ov_id[i] = ret;
+		of_selftest_track_overlay(ov_id[i]);
 	}
 
 	/* now try to remove first overlay (it should fail) */
@@ -1439,6 +1498,7 @@ static void of_selftest_overlay_8(void)
 						PDEV_OVERLAY));
 			return;
 		}
+		of_selftest_untrack_overlay(ov_id[i]);
 	}
 
 	selftest(1, "overlay test %d passed\n", 8);
@@ -1861,6 +1921,8 @@ static void __init of_selftest_overlay(void)
 	of_selftest_overlay_i2c_cleanup();
 #endif
 
+	of_selftest_destroy_tracked_overlays();
+
 out:
 	of_node_put(bus_np);
 }
-- 
1.7.12

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Re: [PATCH 0/5] of: overlay: Assorted fixes

From: Rob Herring <hidden>
Date: 2015-03-17 20:38:08

On Tue, Mar 17, 2015 at 3:30 PM, Pantelis Antoniou
[off-list ref] wrote:
The first patch makes sure that no overlays are being left over from
the unit tests.

The second puts the overlays as objects in the sysfs in
/sys/firmware/devicetree/overlays while the next one adds a master
overlay enable switch (that once is set to disabled can't be re-enabled)

The next updates the ABI docs and the final one adds me as the
maintainer for device tree overlays.
You call this fixes, but it looks like new functionality to me. So
this looks like 4.1 material.

Rob
Pantelis Antoniou (5):
  of: unittest: overlay: Keep track of created overlays
  of: overlay: kobjectify overlay objects
  of: overlay: Master enable switch
  Documentation: ABI: /sys/firmware/devicetree/overlays
  MAINTAINERS: Pantelis Antoniou device tree overlay maintainer

 .../ABI/testing/sysfs-firmware-devicetree-overlays |   9 ++
 MAINTAINERS                                        |   9 ++
 drivers/of/base.c                                  |   5 +
 drivers/of/of_private.h                            |   9 ++
 drivers/of/overlay.c                               | 116 ++++++++++++++++++++-
 drivers/of/unittest.c                              |  62 +++++++++++
 6 files changed, 208 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-firmware-devicetree-overlays

--
1.7.12

Re: [PATCH 0/5] of: overlay: Assorted fixes

From: Pantelis Antoniou <hidden>
Date: 2015-03-17 20:39:57

On Mar 17, 2015, at 22:37 , Rob Herring [off-list ref] wrote:

On Tue, Mar 17, 2015 at 3:30 PM, Pantelis Antoniou
[off-list ref] wrote:
quoted
The first patch makes sure that no overlays are being left over from
the unit tests.

The second puts the overlays as objects in the sysfs in
/sys/firmware/devicetree/overlays while the next one adds a master
overlay enable switch (that once is set to disabled can't be re-enabled)

The next updates the ABI docs and the final one adds me as the
maintainer for device tree overlays.
You call this fixes, but it looks like new functionality to me. So
this looks like 4.1 material.
Yep, they are not 4.0 material. They are not major functional changes though.
Rob
Regards

— Pantelis
quoted
Pantelis Antoniou (5):
 of: unittest: overlay: Keep track of created overlays
 of: overlay: kobjectify overlay objects
 of: overlay: Master enable switch
 Documentation: ABI: /sys/firmware/devicetree/overlays
 MAINTAINERS: Pantelis Antoniou device tree overlay maintainer

.../ABI/testing/sysfs-firmware-devicetree-overlays |   9 ++
MAINTAINERS                                        |   9 ++
drivers/of/base.c                                  |   5 +
drivers/of/of_private.h                            |   9 ++
drivers/of/overlay.c                               | 116 ++++++++++++++++++++-
drivers/of/unittest.c                              |  62 +++++++++++
6 files changed, 208 insertions(+), 2 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-firmware-devicetree-overlays

--
1.7.12

Re: [PATCH 1/5] of: unittest: overlay: Keep track of created overlays

From: Rob Herring <hidden>
Date: 2015-03-25 04:53:29

On Tue, Mar 17, 2015 at 3:30 PM, Pantelis Antoniou
[off-list ref] wrote:
During the course of the overlay selftests some of them remain
applied. While this does not pose a real problem, make sure you track
them and destroy them at the end of the test.
This is going to need to be rebased on my tree as there has been some
selftest->unitest renaming.

Rob
quoted hunk
Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
---
 drivers/of/unittest.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 4e60682..c711534 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -23,6 +23,8 @@
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>

+#include <linux/bitops.h>
+
 #include "of_private.h"

 static struct selftest_results {
@@ -1115,6 +1117,59 @@ static const char *overlay_path(int nr)

 static const char *bus_path = "/testcase-data/overlay-node/test-bus";

+/* it is guaranteed that overlay ids are assigned in sequence */
+#define MAX_SELFTEST_OVERLAYS  256
+static unsigned long overlay_id_bits[BITS_TO_LONGS(MAX_SELFTEST_OVERLAYS)];
+static int overlay_first_id = -1;
+
+static void of_selftest_track_overlay(int id)
+{
+       if (overlay_first_id < 0)
+               overlay_first_id = id;
+       id -= overlay_first_id;
+
+       /* we shouldn't need that many */
+       BUG_ON(id >= MAX_SELFTEST_OVERLAYS);
+       overlay_id_bits[BIT_WORD(id)] |= BIT_MASK(id);
+}
+
+static void of_selftest_untrack_overlay(int id)
+{
+       if (overlay_first_id < 0)
+               return;
+       id -= overlay_first_id;
+       BUG_ON(id >= MAX_SELFTEST_OVERLAYS);
+       overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id);
+}
+
+static void of_selftest_destroy_tracked_overlays(void)
+{
+       int id, ret, defers;
+
+       if (overlay_first_id < 0)
+               return;
+
+       /* try until no defers */
+       do {
+               defers = 0;
+               /* remove in reverse order */
+               for (id = MAX_SELFTEST_OVERLAYS - 1; id >= 0; id--) {
+                       if (!(overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id)))
+                               continue;
+
+                       ret = of_overlay_destroy(id + overlay_first_id);
+                       if (ret != 0) {
+                               defers++;
+                               pr_warn("%s: overlay destroy failed for #%d\n",
+                                       __func__, id + overlay_first_id);
+                               continue;
+                       }
+
+                       overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id);
+               }
+       } while (defers > 0);
+}
+
 static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
                int *overlay_id)
 {
@@ -1136,6 +1191,7 @@ static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
                goto out;
        }
        id = ret;
+       of_selftest_track_overlay(id);

        ret = 0;
@@ -1349,6 +1405,7 @@ static void of_selftest_overlay_6(void)
                        return;
                }
                ov_id[i] = ret;
+               of_selftest_track_overlay(ov_id[i]);
        }

        for (i = 0; i < 2; i++) {
@@ -1373,6 +1430,7 @@ static void of_selftest_overlay_6(void)
                                                PDEV_OVERLAY));
                        return;
                }
+               of_selftest_untrack_overlay(ov_id[i]);
        }

        for (i = 0; i < 2; i++) {
@@ -1417,6 +1475,7 @@ static void of_selftest_overlay_8(void)
                        return;
                }
                ov_id[i] = ret;
+               of_selftest_track_overlay(ov_id[i]);
        }

        /* now try to remove first overlay (it should fail) */
@@ -1439,6 +1498,7 @@ static void of_selftest_overlay_8(void)
                                                PDEV_OVERLAY));
                        return;
                }
+               of_selftest_untrack_overlay(ov_id[i]);
        }

        selftest(1, "overlay test %d passed\n", 8);
@@ -1861,6 +1921,8 @@ static void __init of_selftest_overlay(void)
        of_selftest_overlay_i2c_cleanup();
 #endif

+       of_selftest_destroy_tracked_overlays();
+
 out:
        of_node_put(bus_np);
 }
--
1.7.12

Re: [PATCH 3/5] of: overlay: Master enable switch

From: Rob Herring <hidden>
Date: 2015-03-25 05:25:52

On Tue, Mar 17, 2015 at 3:30 PM, Pantelis Antoniou
[off-list ref] wrote:
Implement a throw once master enable switch to protect against any
further overlay applications if the administrator desires so.
sysfs documentation?
quoted hunk
Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
---
 drivers/of/overlay.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 65 insertions(+), 1 deletion(-)
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index f17f5ef..6688797 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -21,6 +21,7 @@
 #include <linux/err.h>
 #include <linux/idr.h>
 #include <linux/sysfs.h>
+#include <linux/atomic.h>

 #include "of_private.h"
@@ -55,6 +56,9 @@ struct of_overlay {
        struct kobject kobj;
 };

+/* master enable switch; once set to 0 can't be re-enabled */
+static atomic_t ov_enable = ATOMIC_INIT(1);
+
 static int of_overlay_apply_one(struct of_overlay *ov,
                struct device_node *target, const struct device_node *overlay);
@@ -345,6 +349,60 @@ static struct kobj_type of_overlay_ktype = {

 static struct kset *ov_kset;

+static ssize_t enable_read(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *bin_attr, char *buf,
+               loff_t offset, size_t count)
+{
+       char tbuf[3];
+
+       if (offset < 0)
+               return -EINVAL;
+
+       if (offset >= sizeof(tbuf))
+               return 0;
+
+       if (count > sizeof(tbuf) - offset)
+               count = sizeof(tbuf) - offset;
+
+       /* fill in temp */
+       tbuf[0] = '0' + atomic_read(&ov_enable);
+       tbuf[1] = '\n';
+       tbuf[2] = '\0';
+
+       /* copy to buffer */
+       memcpy(buf, tbuf + offset, count);
+
+       return count;
+}
+
+static ssize_t enable_write(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *bin_attr, char *buf,
+               loff_t off, size_t count)
+{
+       int new_enable;
+
+       if (off != 0 || (buf[0] != '0' && buf[1] != '1'))
Is buf[1] correct here?
+               return -EINVAL;
+
+       new_enable = buf[0] - '0';
+       if (new_enable != 0 && new_enable != 1)
Make unsigned just "if (new_enable > 1)".
quoted hunk
+               return -EINVAL;
+
+       /* NOP for same value */
+       if (new_enable == atomic_read(&ov_enable))
+               return count;
+
+       /* if we've disabled it, no going back */
+       if (atomic_read(&ov_enable) == 0)
+               return -EPERM;
+
+       atomic_set(&ov_enable, new_enable);
+       return count;
+}
+
+/* just a single char + '\n' + '\0' */
+static BIN_ATTR_RW(enable, 3);
+
 /**
  * of_overlay_create() - Create and apply an overlay
  * @tree:      Device node containing all the overlays
@@ -360,6 +418,10 @@ int of_overlay_create(struct device_node *tree)
        struct of_overlay *ov;
        int err, id;

+       /* administratively disabled */
+       if (!atomic_read(&ov_enable))
+               return -EPERM;
+
        /* allocate the overlay structure */
        ov = kzalloc(sizeof(*ov), GFP_KERNEL);
        if (ov == NULL)
@@ -596,5 +658,7 @@ int of_overlay_init(void)
        if (!ov_kset)
                return -ENOMEM;

-       return 0;
+       rc = sysfs_create_bin_file(&ov_kset->kobj, &bin_attr_enable);
+       WARN(rc, "%s: error adding enable attribute\n", __func__);
+       return rc;
 }
--
1.7.12
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Re: [PATCH 5/5] MAINTAINERS: Pantelis Antoniou device tree overlay maintainer

From: Rob Herring <hidden>
Date: 2015-03-25 05:31:52

On Tue, Mar 17, 2015 at 3:30 PM, Pantelis Antoniou
[off-list ref] wrote:
Add me as the device tree overlays maintainer.

Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
Applied. Thanks.

Rob
quoted hunk
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 0e1abe8..24aa339 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7187,6 +7187,15 @@ F:       Documentation/devicetree/
 F:     arch/*/boot/dts/
 F:     include/dt-bindings/

+OPEN FIRMWARE AND DEVICE TREE OVERLAYS
+M:     Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
+L:     devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+S:     Maintained
+F:     Documentation/devicetree/dynamic-resolution-notes.txt
+F:     Documentation/devicetree/overlay-notes.txt
+F:     drivers/of/overlay.c
+F:     drivers/of/resolver.c
+
 OPENRISC ARCHITECTURE
 M:     Jonas Bonn <jonas-A9uVI2HLR7kOP4wsBPIw7w@public.gmane.org>
 W:     http://openrisc.net
--
1.7.12

Re: [PATCH 1/5] of: unittest: overlay: Keep track of created overlays

From: Pantelis Antoniou <hidden>
Date: 2015-03-27 18:24:47

Hi Rob,
On Mar 24, 2015, at 21:53 , Rob Herring [off-list ref] wrote:

On Tue, Mar 17, 2015 at 3:30 PM, Pantelis Antoniou
[off-list ref] wrote:
quoted
During the course of the overlay selftests some of them remain
applied. While this does not pose a real problem, make sure you track
them and destroy them at the end of the test.
This is going to need to be rebased on my tree as there has been some
selftest->unitest renaming.
Ok, will do so first thing next week.
Rob
Regards

— Pantelis
quoted
Signed-off-by: Pantelis Antoniou <redacted>
---
drivers/of/unittest.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 62 insertions(+)
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 4e60682..c711534 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -23,6 +23,8 @@
#include <linux/i2c.h>
#include <linux/i2c-mux.h>

+#include <linux/bitops.h>
+
#include "of_private.h"

static struct selftest_results {
@@ -1115,6 +1117,59 @@ static const char *overlay_path(int nr)
static const char *bus_path = "/testcase-data/overlay-node/test-bus";

+/* it is guaranteed that overlay ids are assigned in sequence */
+#define MAX_SELFTEST_OVERLAYS  256
+static unsigned long overlay_id_bits[BITS_TO_LONGS(MAX_SELFTEST_OVERLAYS)];
+static int overlay_first_id = -1;
+
+static void of_selftest_track_overlay(int id)
+{
+       if (overlay_first_id < 0)
+               overlay_first_id = id;
+       id -= overlay_first_id;
+
+       /* we shouldn't need that many */
+       BUG_ON(id >= MAX_SELFTEST_OVERLAYS);
+       overlay_id_bits[BIT_WORD(id)] |= BIT_MASK(id);
+}
+
+static void of_selftest_untrack_overlay(int id)
+{
+       if (overlay_first_id < 0)
+               return;
+       id -= overlay_first_id;
+       BUG_ON(id >= MAX_SELFTEST_OVERLAYS);
+       overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id);
+}
+
+static void of_selftest_destroy_tracked_overlays(void)
+{
+       int id, ret, defers;
+
+       if (overlay_first_id < 0)
+               return;
+
+       /* try until no defers */
+       do {
+               defers = 0;
+               /* remove in reverse order */
+               for (id = MAX_SELFTEST_OVERLAYS - 1; id >= 0; id--) {
+                       if (!(overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id)))
+                               continue;
+
+                       ret = of_overlay_destroy(id + overlay_first_id);
+                       if (ret != 0) {
+                               defers++;
+                               pr_warn("%s: overlay destroy failed for #%d\n",
+                                       __func__, id + overlay_first_id);
+                               continue;
+                       }
+
+                       overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id);
+               }
+       } while (defers > 0);
+}
+
static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
               int *overlay_id)
{
@@ -1136,6 +1191,7 @@ static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
               goto out;
       }
       id = ret;
+       of_selftest_track_overlay(id);

       ret = 0;
@@ -1349,6 +1405,7 @@ static void of_selftest_overlay_6(void)
                       return;
               }
               ov_id[i] = ret;
+               of_selftest_track_overlay(ov_id[i]);
       }

       for (i = 0; i < 2; i++) {
@@ -1373,6 +1430,7 @@ static void of_selftest_overlay_6(void)
                                               PDEV_OVERLAY));
                       return;
               }
+               of_selftest_untrack_overlay(ov_id[i]);
       }

       for (i = 0; i < 2; i++) {
@@ -1417,6 +1475,7 @@ static void of_selftest_overlay_8(void)
                       return;
               }
               ov_id[i] = ret;
+               of_selftest_track_overlay(ov_id[i]);
       }

       /* now try to remove first overlay (it should fail) */
@@ -1439,6 +1498,7 @@ static void of_selftest_overlay_8(void)
                                               PDEV_OVERLAY));
                       return;
               }
+               of_selftest_untrack_overlay(ov_id[i]);
       }

       selftest(1, "overlay test %d passed\n", 8);
@@ -1861,6 +1921,8 @@ static void __init of_selftest_overlay(void)
       of_selftest_overlay_i2c_cleanup();
#endif

+       of_selftest_destroy_tracked_overlays();
+
out:
       of_node_put(bus_np);
}
--
1.7.12

Re: [PATCH 3/5] of: overlay: Master enable switch

From: Pantelis Antoniou <hidden>
Date: 2015-03-27 18:25:56

Hi Rob,
On Mar 24, 2015, at 22:25 , Rob Herring [off-list ref] wrote:

On Tue, Mar 17, 2015 at 3:30 PM, Pantelis Antoniou
[off-list ref] wrote:
quoted
Implement a throw once master enable switch to protect against any
further overlay applications if the administrator desires so.
sysfs documentation?
OK, coming up.
quoted
Signed-off-by: Pantelis Antoniou <redacted>
---
drivers/of/overlay.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 65 insertions(+), 1 deletion(-)
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index f17f5ef..6688797 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -21,6 +21,7 @@
#include <linux/err.h>
#include <linux/idr.h>
#include <linux/sysfs.h>
+#include <linux/atomic.h>

#include "of_private.h"
@@ -55,6 +56,9 @@ struct of_overlay {
       struct kobject kobj;
};

+/* master enable switch; once set to 0 can't be re-enabled */
+static atomic_t ov_enable = ATOMIC_INIT(1);
+
static int of_overlay_apply_one(struct of_overlay *ov,
               struct device_node *target, const struct device_node *overlay);
@@ -345,6 +349,60 @@ static struct kobj_type of_overlay_ktype = {
static struct kset *ov_kset;

+static ssize_t enable_read(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *bin_attr, char *buf,
+               loff_t offset, size_t count)
+{
+       char tbuf[3];
+
+       if (offset < 0)
+               return -EINVAL;
+
+       if (offset >= sizeof(tbuf))
+               return 0;
+
+       if (count > sizeof(tbuf) - offset)
+               count = sizeof(tbuf) - offset;
+
+       /* fill in temp */
+       tbuf[0] = '0' + atomic_read(&ov_enable);
+       tbuf[1] = '\n';
+       tbuf[2] = '\0';
+
+       /* copy to buffer */
+       memcpy(buf, tbuf + offset, count);
+
+       return count;
+}
+
+static ssize_t enable_write(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *bin_attr, char *buf,
+               loff_t off, size_t count)
+{
+       int new_enable;
+
+       if (off != 0 || (buf[0] != '0' && buf[1] != '1'))
Is buf[1] correct here?
Nope.
quoted
+               return -EINVAL;
+
+       new_enable = buf[0] - '0';
+       if (new_enable != 0 && new_enable != 1)
Make unsigned just "if (new_enable > 1)”.
OK.
quoted
+               return -EINVAL;
+
+       /* NOP for same value */
+       if (new_enable == atomic_read(&ov_enable))
+               return count;
+
+       /* if we've disabled it, no going back */
+       if (atomic_read(&ov_enable) == 0)
+               return -EPERM;
+
+       atomic_set(&ov_enable, new_enable);
+       return count;
+}
+
+/* just a single char + '\n' + '\0' */
+static BIN_ATTR_RW(enable, 3);
+
/**
 * of_overlay_create() - Create and apply an overlay
 * @tree:      Device node containing all the overlays
@@ -360,6 +418,10 @@ int of_overlay_create(struct device_node *tree)
       struct of_overlay *ov;
       int err, id;

+       /* administratively disabled */
+       if (!atomic_read(&ov_enable))
+               return -EPERM;
+
       /* allocate the overlay structure */
       ov = kzalloc(sizeof(*ov), GFP_KERNEL);
       if (ov == NULL)
@@ -596,5 +658,7 @@ int of_overlay_init(void)
       if (!ov_kset)
               return -ENOMEM;

-       return 0;
+       rc = sysfs_create_bin_file(&ov_kset->kobj, &bin_attr_enable);
+       WARN(rc, "%s: error adding enable attribute\n", __func__);
+       return rc;
}
--
1.7.12
Regards

— Pantelis
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help