linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] clk: Evict unregistered clks from parent caches
@ 2019-08-26 23:43 Stephen Boyd
  2019-08-27  0:40 ` Bjorn Andersson
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Stephen Boyd @ 2019-08-26 23:43 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: linux-kernel, linux-clk, Bjorn Andersson, Sai Prakash Ranjan

We leave a dangling pointer in each clk_core::parents array that has an
unregistered clk as a potential parent when that clk_core pointer is
freed by clk{_hw}_unregister(). It is impossible for the true parent of
a clk to be set with clk_set_parent() once the dangling pointer is left
in the cache because we compare parent pointers in
clk_fetch_parent_index() instead of checking for a matching clk name or
clk_hw pointer.

Before commit ede77858473a ("clk: Remove global clk traversal on fetch
parent index"), we would check clk_hw pointers, which has a higher
chance of being the same between registration and unregistration, but it
can still be allocated and freed by the clk provider. In fact, this has
been a long standing problem since commit da0f0b2c3ad2 ("clk: Correct
lookup logic in clk_fetch_parent_index()") where we stopped trying to
compare clk names and skipped over entries in the cache that weren't
NULL.

There are good (performance) reasons to not do the global tree lookup in
cases where the cache holds dangling pointers to parents that have been
unregistered. Let's take the performance hit on the uncommon
registration path instead. Loop through all the clk_core::parents arrays
when a clk is unregistered and set the entry to NULL when the parent
cache entry and clk being unregistered are the same pointer. This will
fix this problem and avoid the overhead for the "normal" case.

Based on a patch by Bjorn Andersson.

Fixes: da0f0b2c3ad2 ("clk: Correct lookup logic in clk_fetch_parent_index()")
Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
Cc: Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
 drivers/clk/clk.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index c0990703ce54..f3982bfa39d6 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -3737,6 +3737,34 @@ static const struct clk_ops clk_nodrv_ops = {
 	.set_parent	= clk_nodrv_set_parent,
 };
 
+static void clk_core_evict_parent_cache_subtree(struct clk_core *root,
+						struct clk_core *target)
+{
+	int i;
+	struct clk_core *child;
+
+	for (i = 0; i < root->num_parents; i++)
+		if (root->parents[i].core == target)
+			root->parents[i].core = NULL;
+
+	hlist_for_each_entry(child, &root->children, child_node)
+		clk_core_evict_parent_cache_subtree(child, target);
+}
+
+/* Remove this clk from all parent caches */
+static void clk_core_evict_parent_cache(struct clk_core *core)
+{
+	struct hlist_head **lists;
+	struct clk_core *root;
+
+	lockdep_assert_held(&prepare_lock);
+
+	for (lists = all_lists; *lists; lists++)
+		hlist_for_each_entry(root, *lists, child_node)
+			clk_core_evict_parent_cache_subtree(root, core);
+
+}
+
 /**
  * clk_unregister - unregister a currently registered clock
  * @clk: clock to unregister
@@ -3775,6 +3803,8 @@ void clk_unregister(struct clk *clk)
 			clk_core_set_parent_nolock(child, NULL);
 	}
 
+	clk_core_evict_parent_cache(clk->core);
+
 	hlist_del_init(&clk->core->child_node);
 
 	if (clk->core->prepare_count)
-- 
Sent by a computer through tubes


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] clk: Evict unregistered clks from parent caches
  2019-08-26 23:43 [PATCH] clk: Evict unregistered clks from parent caches Stephen Boyd
@ 2019-08-27  0:40 ` Bjorn Andersson
  2019-08-27  3:33 ` Sai Prakash Ranjan
  2019-08-27 10:28 ` kbuild test robot
  2 siblings, 0 replies; 5+ messages in thread
From: Bjorn Andersson @ 2019-08-27  0:40 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Michael Turquette, linux-kernel, linux-clk, Sai Prakash Ranjan

On Mon 26 Aug 16:43 PDT 2019, Stephen Boyd wrote:

> We leave a dangling pointer in each clk_core::parents array that has an
> unregistered clk as a potential parent when that clk_core pointer is
> freed by clk{_hw}_unregister(). It is impossible for the true parent of
> a clk to be set with clk_set_parent() once the dangling pointer is left
> in the cache because we compare parent pointers in
> clk_fetch_parent_index() instead of checking for a matching clk name or
> clk_hw pointer.
> 
> Before commit ede77858473a ("clk: Remove global clk traversal on fetch
> parent index"), we would check clk_hw pointers, which has a higher
> chance of being the same between registration and unregistration, but it
> can still be allocated and freed by the clk provider. In fact, this has
> been a long standing problem since commit da0f0b2c3ad2 ("clk: Correct
> lookup logic in clk_fetch_parent_index()") where we stopped trying to
> compare clk names and skipped over entries in the cache that weren't
> NULL.
> 
> There are good (performance) reasons to not do the global tree lookup in
> cases where the cache holds dangling pointers to parents that have been
> unregistered. Let's take the performance hit on the uncommon
> registration path instead. Loop through all the clk_core::parents arrays
> when a clk is unregistered and set the entry to NULL when the parent
> cache entry and clk being unregistered are the same pointer. This will
> fix this problem and avoid the overhead for the "normal" case.
> 
> Based on a patch by Bjorn Andersson.
> 
> Fixes: da0f0b2c3ad2 ("clk: Correct lookup logic in clk_fetch_parent_index()")
> Cc: Bjorn Andersson <bjorn.andersson@linaro.org>

Thanks for writing this up.

Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>

> Cc: Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
> ---
>  drivers/clk/clk.c | 30 ++++++++++++++++++++++++++++++
>  1 file changed, 30 insertions(+)
> 
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index c0990703ce54..f3982bfa39d6 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -3737,6 +3737,34 @@ static const struct clk_ops clk_nodrv_ops = {
>  	.set_parent	= clk_nodrv_set_parent,
>  };
>  
> +static void clk_core_evict_parent_cache_subtree(struct clk_core *root,
> +						struct clk_core *target)
> +{
> +	int i;
> +	struct clk_core *child;
> +
> +	for (i = 0; i < root->num_parents; i++)
> +		if (root->parents[i].core == target)
> +			root->parents[i].core = NULL;
> +
> +	hlist_for_each_entry(child, &root->children, child_node)
> +		clk_core_evict_parent_cache_subtree(child, target);
> +}
> +
> +/* Remove this clk from all parent caches */
> +static void clk_core_evict_parent_cache(struct clk_core *core)
> +{
> +	struct hlist_head **lists;
> +	struct clk_core *root;
> +
> +	lockdep_assert_held(&prepare_lock);
> +
> +	for (lists = all_lists; *lists; lists++)
> +		hlist_for_each_entry(root, *lists, child_node)
> +			clk_core_evict_parent_cache_subtree(root, core);
> +
> +}
> +
>  /**
>   * clk_unregister - unregister a currently registered clock
>   * @clk: clock to unregister
> @@ -3775,6 +3803,8 @@ void clk_unregister(struct clk *clk)
>  			clk_core_set_parent_nolock(child, NULL);
>  	}
>  
> +	clk_core_evict_parent_cache(clk->core);
> +
>  	hlist_del_init(&clk->core->child_node);
>  
>  	if (clk->core->prepare_count)
> -- 
> Sent by a computer through tubes
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] clk: Evict unregistered clks from parent caches
  2019-08-26 23:43 [PATCH] clk: Evict unregistered clks from parent caches Stephen Boyd
  2019-08-27  0:40 ` Bjorn Andersson
@ 2019-08-27  3:33 ` Sai Prakash Ranjan
  2019-08-27 10:28 ` kbuild test robot
  2 siblings, 0 replies; 5+ messages in thread
From: Sai Prakash Ranjan @ 2019-08-27  3:33 UTC (permalink / raw)
  To: Stephen Boyd; +Cc: Michael Turquette, linux-kernel, linux-clk, Bjorn Andersson

On 2019-08-27 05:13, Stephen Boyd wrote:
> We leave a dangling pointer in each clk_core::parents array that has an
> unregistered clk as a potential parent when that clk_core pointer is
> freed by clk{_hw}_unregister(). It is impossible for the true parent of
> a clk to be set with clk_set_parent() once the dangling pointer is left
> in the cache because we compare parent pointers in
> clk_fetch_parent_index() instead of checking for a matching clk name or
> clk_hw pointer.
> 
> Before commit ede77858473a ("clk: Remove global clk traversal on fetch
> parent index"), we would check clk_hw pointers, which has a higher
> chance of being the same between registration and unregistration, but 
> it
> can still be allocated and freed by the clk provider. In fact, this has
> been a long standing problem since commit da0f0b2c3ad2 ("clk: Correct
> lookup logic in clk_fetch_parent_index()") where we stopped trying to
> compare clk names and skipped over entries in the cache that weren't
> NULL.
> 
> There are good (performance) reasons to not do the global tree lookup 
> in
> cases where the cache holds dangling pointers to parents that have been
> unregistered. Let's take the performance hit on the uncommon
> registration path instead. Loop through all the clk_core::parents 
> arrays
> when a clk is unregistered and set the entry to NULL when the parent
> cache entry and clk being unregistered are the same pointer. This will
> fix this problem and avoid the overhead for the "normal" case.
> 
> Based on a patch by Bjorn Andersson.
> 
> Fixes: da0f0b2c3ad2 ("clk: Correct lookup logic in 
> clk_fetch_parent_index()")
> Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
> Cc: Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
> ---
>  drivers/clk/clk.c | 30 ++++++++++++++++++++++++++++++
>  1 file changed, 30 insertions(+)
> 
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index c0990703ce54..f3982bfa39d6 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -3737,6 +3737,34 @@ static const struct clk_ops clk_nodrv_ops = {
>  	.set_parent	= clk_nodrv_set_parent,
>  };
> 
> +static void clk_core_evict_parent_cache_subtree(struct clk_core *root,
> +						struct clk_core *target)
> +{
> +	int i;
> +	struct clk_core *child;
> +
> +	for (i = 0; i < root->num_parents; i++)
> +		if (root->parents[i].core == target)
> +			root->parents[i].core = NULL;
> +
> +	hlist_for_each_entry(child, &root->children, child_node)
> +		clk_core_evict_parent_cache_subtree(child, target);
> +}
> +
> +/* Remove this clk from all parent caches */
> +static void clk_core_evict_parent_cache(struct clk_core *core)
> +{
> +	struct hlist_head **lists;
> +	struct clk_core *root;
> +
> +	lockdep_assert_held(&prepare_lock);
> +
> +	for (lists = all_lists; *lists; lists++)
> +		hlist_for_each_entry(root, *lists, child_node)
> +			clk_core_evict_parent_cache_subtree(root, core);
> +
> +}
> +
>  /**
>   * clk_unregister - unregister a currently registered clock
>   * @clk: clock to unregister
> @@ -3775,6 +3803,8 @@ void clk_unregister(struct clk *clk)
>  			clk_core_set_parent_nolock(child, NULL);
>  	}
> 
> +	clk_core_evict_parent_cache(clk->core);
> +
>  	hlist_del_init(&clk->core->child_node);
> 
>  	if (clk->core->prepare_count)


Thanks Stephen. Tested this on cheza now and the issue is not seen 
anymore.

Tested-by: Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a 
member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] clk: Evict unregistered clks from parent caches
  2019-08-26 23:43 [PATCH] clk: Evict unregistered clks from parent caches Stephen Boyd
  2019-08-27  0:40 ` Bjorn Andersson
  2019-08-27  3:33 ` Sai Prakash Ranjan
@ 2019-08-27 10:28 ` kbuild test robot
  2019-08-28 18:10   ` Stephen Boyd
  2 siblings, 1 reply; 5+ messages in thread
From: kbuild test robot @ 2019-08-27 10:28 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: kbuild-all, Michael Turquette, Stephen Boyd, linux-kernel,
	linux-clk, Bjorn Andersson, Sai Prakash Ranjan

[-- Attachment #1: Type: text/plain, Size: 1859 bytes --]

Hi Stephen,

I love your patch! Yet something to improve:

[auto build test ERROR on linus/master]
[cannot apply to v5.3-rc6 next-20190827]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Stephen-Boyd/clk-Evict-unregistered-clks-from-parent-caches/20190827-165138
config: mips-allnoconfig (attached as .config)
compiler: mips-linux-gcc (GCC) 7.4.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.4.0 make.cross ARCH=mips 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/clk/clk.c: In function 'clk_core_evict_parent_cache':
>> drivers/clk/clk.c:3785:15: error: 'all_lists' undeclared (first use in this function); did you mean 'lists'?
     for (lists = all_lists; *lists; lists++)
                  ^~~~~~~~~
                  lists
   drivers/clk/clk.c:3785:15: note: each undeclared identifier is reported only once for each function it appears in

vim +3785 drivers/clk/clk.c

  3776	
  3777	/* Remove this clk from all parent caches */
  3778	static void clk_core_evict_parent_cache(struct clk_core *core)
  3779	{
  3780		struct hlist_head **lists;
  3781		struct clk_core *root;
  3782	
  3783		lockdep_assert_held(&prepare_lock);
  3784	
> 3785		for (lists = all_lists; *lists; lists++)
  3786			hlist_for_each_entry(root, *lists, child_node)
  3787				clk_core_evict_parent_cache_subtree(root, core);
  3788	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 6909 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] clk: Evict unregistered clks from parent caches
  2019-08-27 10:28 ` kbuild test robot
@ 2019-08-28 18:10   ` Stephen Boyd
  0 siblings, 0 replies; 5+ messages in thread
From: Stephen Boyd @ 2019-08-28 18:10 UTC (permalink / raw)
  To: kbuild test robot
  Cc: kbuild-all, Michael Turquette, linux-kernel, linux-clk,
	Bjorn Andersson, Sai Prakash Ranjan

Quoting kbuild test robot (2019-08-27 03:28:35)
> Hi Stephen,
> 
> I love your patch! Yet something to improve:
> 
> [auto build test ERROR on linus/master]
> [cannot apply to v5.3-rc6 next-20190827]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> 
> url:    https://github.com/0day-ci/linux/commits/Stephen-Boyd/clk-Evict-unregistered-clks-from-parent-caches/20190827-165138
> config: mips-allnoconfig (attached as .config)
> compiler: mips-linux-gcc (GCC) 7.4.0
> reproduce:
>         wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # save the attached .config to linux build tree
>         GCC_VERSION=7.4.0 make.cross ARCH=mips 
> 
> If you fix the issue, kindly add following tag
> Reported-by: kbuild test robot <lkp@intel.com>
> 
> All errors (new ones prefixed by >>):
> 
>    drivers/clk/clk.c: In function 'clk_core_evict_parent_cache':
> >> drivers/clk/clk.c:3785:15: error: 'all_lists' undeclared (first use in this function); did you mean 'lists'?
>      for (lists = all_lists; *lists; lists++)
>                   ^~~~~~~~~
>                   lists
>    drivers/clk/clk.c:3785:15: note: each undeclared identifier is reported only once for each function it appears in

Aha, thanks. all_lists is for debugfs it seems.


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2019-08-28 18:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-26 23:43 [PATCH] clk: Evict unregistered clks from parent caches Stephen Boyd
2019-08-27  0:40 ` Bjorn Andersson
2019-08-27  3:33 ` Sai Prakash Ranjan
2019-08-27 10:28 ` kbuild test robot
2019-08-28 18:10   ` Stephen Boyd

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).