All of lore.kernel.org
 help / color / mirror / Atom feed
From: tixy@linaro.org (Jon Medhurst (Tixy))
To: linux-arm-kernel@lists.infradead.org
Subject: Problem with component helpers and probe deferral in 4.5-rc1
Date: Tue, 26 Jan 2016 17:59:13 +0000	[thread overview]
Message-ID: <1453831153.2850.107.camel@linaro.org> (raw)

I believe I've found a problem with the component helpers and/or how
drivers use them. I discovered this whilst trying to get ARM's HDLCD
driver [1] working on 4.5-rc1, however I believe that code is following
a pattern used by drivers already in 4.5 and the problem isn't specific
to it. This is what I have observed...

The master device's probe function uses component_match_add to create a
match list then it passes this to component_master_add_with_match.

That creates a struct master and then calls try_to_bring_up_master
which:
- Calls find_components to attach all components to the master.
- Calls master->ops->bind()

If this bind call fails (with -EPROBE_DEFER due to missing clock in my
case) then this error is returned to component_master_add_with_match
which proceeds to delete the master struct. However, find_components has
already attached components to that deleted master, so I think we also
need something to detach components as well. I've added a patch at the
end of this email which does that directly, but I wonder if instead it's
the responsibility of the driver for the master to call
component_master_del on error?

Finally, with my scenario which has probe deferring, some time later the
original master device will be probed again, repeating all the above.
Except that now find_components doesn't find the components because they
are already attached to a different master (the old master struct which
was deleted) this results in a permanent error. Which is what lead me to
investigate.

[1] https://lkml.org/lkml/2015/12/22/451

The patch to detach components when master is deleted...

-------------------------------------------------------------------------

From: Jon Medhurst <tixy@linaro.org>
Subject: [PATCH] component: Detach components when deleting master struct

component_master_add_with_match calls find_components which, if any
components already exist, it attaches to the master struct. However, if
we later encounter an error the master struct is deleted, leaving
components with a dangling pointer to it.

If the error was a temporary one, e.g. for probe deferral, then when
the master device is re-probed, it will fail to find the required
components as they appear to already be attached to a master.

Fix this by nulling components pointers to the master struct when it is
deleted. This code is factored out into a separate function so it can be
shared with component_master_del.

Signed-off-by: Jon Medhurst <tixy@linaro.org>
---
 drivers/base/component.c | 41 ++++++++++++++++++++++-------------------
 1 file changed, 22 insertions(+), 19 deletions(-)

diff --git a/drivers/base/component.c b/drivers/base/component.c
index 89f5cf68..a3a1394 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -283,6 +283,24 @@ void component_match_add_release(struct device *master,
 }
 EXPORT_SYMBOL(component_match_add_release);
 
+static void free_master(struct master *master)
+{
+	struct component_match *match = master->match;
+	int i;
+
+	list_del(&master->node);
+
+	if (match) {
+		for (i = 0; i < match->num; i++) {
+			struct component *c = match->compare[i].component;
+			if (c)
+				c->master = NULL;
+		}
+	}
+
+	kfree(master);
+}
+
 int component_master_add_with_match(struct device *dev,
 	const struct component_master_ops *ops,
 	struct component_match *match)
@@ -309,11 +327,9 @@ int component_master_add_with_match(struct device *dev,
 
 	ret = try_to_bring_up_master(master, NULL);
 
-	if (ret < 0) {
-		/* Delete off the list if we weren't successful */
-		list_del(&master->node);
-		kfree(master);
-	}
+	if (ret < 0)
+		free_master(master);
+
 	mutex_unlock(&component_mutex);
 
 	return ret < 0 ? ret : 0;
@@ -324,25 +340,12 @@ void component_master_del(struct device *dev,
 	const struct component_master_ops *ops)
 {
 	struct master *master;
-	int i;
 
 	mutex_lock(&component_mutex);
 	master = __master_find(dev, ops);
 	if (master) {
-		struct component_match *match = master->match;
-
 		take_down_master(master);
-
-		list_del(&master->node);
-
-		if (match) {
-			for (i = 0; i < match->num; i++) {
-				struct component *c = match->compare[i].component;
-				if (c)
-					c->master = NULL;
-			}
-		}
-		kfree(master);
+		free_master(master);
 	}
 	mutex_unlock(&component_mutex);
 }
-- 
2.1.4

WARNING: multiple messages have this Message-ID (diff)
From: "Jon Medhurst (Tixy)" <tixy@linaro.org>
To: Russell King - ARM Linux <linux@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Liviu Dudau <liviu.dudau@arm.com>,
	linux-arm-kernel@lists.infradead.org,
	dri-devel@lists.freedesktop.org
Subject: Problem with component helpers and probe deferral in 4.5-rc1
Date: Tue, 26 Jan 2016 17:59:13 +0000	[thread overview]
Message-ID: <1453831153.2850.107.camel@linaro.org> (raw)

I believe I've found a problem with the component helpers and/or how
drivers use them. I discovered this whilst trying to get ARM's HDLCD
driver [1] working on 4.5-rc1, however I believe that code is following
a pattern used by drivers already in 4.5 and the problem isn't specific
to it. This is what I have observed...

The master device's probe function uses component_match_add to create a
match list then it passes this to component_master_add_with_match.

That creates a struct master and then calls try_to_bring_up_master
which:
- Calls find_components to attach all components to the master.
- Calls master->ops->bind()

If this bind call fails (with -EPROBE_DEFER due to missing clock in my
case) then this error is returned to component_master_add_with_match
which proceeds to delete the master struct. However, find_components has
already attached components to that deleted master, so I think we also
need something to detach components as well. I've added a patch at the
end of this email which does that directly, but I wonder if instead it's
the responsibility of the driver for the master to call
component_master_del on error?

Finally, with my scenario which has probe deferring, some time later the
original master device will be probed again, repeating all the above.
Except that now find_components doesn't find the components because they
are already attached to a different master (the old master struct which
was deleted) this results in a permanent error. Which is what lead me to
investigate.

[1] https://lkml.org/lkml/2015/12/22/451

The patch to detach components when master is deleted...

-------------------------------------------------------------------------

From: Jon Medhurst <tixy@linaro.org>
Subject: [PATCH] component: Detach components when deleting master struct

component_master_add_with_match calls find_components which, if any
components already exist, it attaches to the master struct. However, if
we later encounter an error the master struct is deleted, leaving
components with a dangling pointer to it.

If the error was a temporary one, e.g. for probe deferral, then when
the master device is re-probed, it will fail to find the required
components as they appear to already be attached to a master.

Fix this by nulling components pointers to the master struct when it is
deleted. This code is factored out into a separate function so it can be
shared with component_master_del.

Signed-off-by: Jon Medhurst <tixy@linaro.org>
---
 drivers/base/component.c | 41 ++++++++++++++++++++++-------------------
 1 file changed, 22 insertions(+), 19 deletions(-)

diff --git a/drivers/base/component.c b/drivers/base/component.c
index 89f5cf68..a3a1394 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -283,6 +283,24 @@ void component_match_add_release(struct device *master,
 }
 EXPORT_SYMBOL(component_match_add_release);
 
+static void free_master(struct master *master)
+{
+	struct component_match *match = master->match;
+	int i;
+
+	list_del(&master->node);
+
+	if (match) {
+		for (i = 0; i < match->num; i++) {
+			struct component *c = match->compare[i].component;
+			if (c)
+				c->master = NULL;
+		}
+	}
+
+	kfree(master);
+}
+
 int component_master_add_with_match(struct device *dev,
 	const struct component_master_ops *ops,
 	struct component_match *match)
@@ -309,11 +327,9 @@ int component_master_add_with_match(struct device *dev,
 
 	ret = try_to_bring_up_master(master, NULL);
 
-	if (ret < 0) {
-		/* Delete off the list if we weren't successful */
-		list_del(&master->node);
-		kfree(master);
-	}
+	if (ret < 0)
+		free_master(master);
+
 	mutex_unlock(&component_mutex);
 
 	return ret < 0 ? ret : 0;
@@ -324,25 +340,12 @@ void component_master_del(struct device *dev,
 	const struct component_master_ops *ops)
 {
 	struct master *master;
-	int i;
 
 	mutex_lock(&component_mutex);
 	master = __master_find(dev, ops);
 	if (master) {
-		struct component_match *match = master->match;
-
 		take_down_master(master);
-
-		list_del(&master->node);
-
-		if (match) {
-			for (i = 0; i < match->num; i++) {
-				struct component *c = match->compare[i].component;
-				if (c)
-					c->master = NULL;
-			}
-		}
-		kfree(master);
+		free_master(master);
 	}
 	mutex_unlock(&component_mutex);
 }
-- 
2.1.4

             reply	other threads:[~2016-01-26 17:59 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-26 17:59 Jon Medhurst (Tixy) [this message]
2016-01-26 17:59 ` Problem with component helpers and probe deferral in 4.5-rc1 Jon Medhurst (Tixy)
2016-01-26 22:35 ` Russell King - ARM Linux
2016-01-26 22:35   ` Russell King - ARM Linux
2016-01-27  9:18   ` Jon Medhurst (Tixy)
2016-01-27  9:18     ` Jon Medhurst (Tixy)
2016-01-27  9:50     ` Jon Medhurst (Tixy)
2016-01-27  9:50       ` Jon Medhurst (Tixy)

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=1453831153.2850.107.camel@linaro.org \
    --to=tixy@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.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.