| From geert@linux-m68k.org Tue Dec 8 09:38:00 2015 |
| From: Geert Uytterhoeven <geert+renesas@glider.be> |
| Date: Tue, 8 Dec 2015 18:37:38 +0100 |
| Subject: [PATCH 2/5] clkdev: use clk_hw internally |
| To: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Cc: Simon Horman <horms@verge.net.au>, Magnus Damm <magnus.damm@gmail.com>, ltsi-dev@lists.linuxfoundation.org, Russell King <rmk+kernel@arm.linux.org.uk>, Geert Uytterhoeven <geert+renesas@glider.be> |
| Message-ID: <1449596261-31005-3-git-send-email-geert+renesas@glider.be> |
| |
| |
| From: Russell King <rmk+kernel@arm.linux.org.uk> |
| |
| clk_add_alias() calls clk_get() followed by clk_put() but in between |
| those two calls it saves away the struct clk pointer to a clk_lookup |
| structure. This leaves the 'clk' member of the clk_lookup pointing at |
| freed memory on configurations where CONFIG_COMMON_CLK=y. This is a |
| problem because clk_get_sys() will eventually try to dereference the |
| freed pointer by calling __clk_get_hw() on it. Fix this by saving away |
| the struct clk_hw pointer instead of the struct clk pointer so that when |
| we try to create a per-user struct clk in clk_get_sys() we don't |
| dereference a junk pointer. |
| |
| Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> |
| (cherry picked from commit d5622a9c13752be46e6fcde9d31391ce0bb0598b) |
| Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> |
| --- |
| drivers/clk/clkdev.c | 24 ++++++++++++++++-------- |
| include/linux/clkdev.h | 1 + |
| 2 files changed, 17 insertions(+), 8 deletions(-) |
| |
| --- a/drivers/clk/clkdev.c |
| +++ b/drivers/clk/clkdev.c |
| @@ -177,7 +177,7 @@ struct clk *clk_get_sys(const char *dev_ |
| if (!cl) |
| goto out; |
| |
| - clk = __clk_create_clk(__clk_get_hw(cl->clk), dev_id, con_id); |
| + clk = __clk_create_clk(cl->clk_hw, dev_id, con_id); |
| if (IS_ERR(clk)) |
| goto out; |
| |
| @@ -215,18 +215,26 @@ void clk_put(struct clk *clk) |
| } |
| EXPORT_SYMBOL(clk_put); |
| |
| -void clkdev_add(struct clk_lookup *cl) |
| +static void __clkdev_add(struct clk_lookup *cl) |
| { |
| mutex_lock(&clocks_mutex); |
| list_add_tail(&cl->node, &clocks); |
| mutex_unlock(&clocks_mutex); |
| } |
| + |
| +void clkdev_add(struct clk_lookup *cl) |
| +{ |
| + if (!cl->clk_hw) |
| + cl->clk_hw = __clk_get_hw(cl->clk); |
| + __clkdev_add(cl); |
| +} |
| EXPORT_SYMBOL(clkdev_add); |
| |
| void __init clkdev_add_table(struct clk_lookup *cl, size_t num) |
| { |
| mutex_lock(&clocks_mutex); |
| while (num--) { |
| + cl->clk_hw = __clk_get_hw(cl->clk); |
| list_add_tail(&cl->node, &clocks); |
| cl++; |
| } |
| @@ -243,7 +251,7 @@ struct clk_lookup_alloc { |
| }; |
| |
| static struct clk_lookup * __init_refok |
| -vclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, |
| +vclkdev_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt, |
| va_list ap) |
| { |
| struct clk_lookup_alloc *cla; |
| @@ -252,7 +260,7 @@ vclkdev_alloc(struct clk *clk, const cha |
| if (!cla) |
| return NULL; |
| |
| - cla->cl.clk = clk; |
| + cla->cl.clk_hw = hw; |
| if (con_id) { |
| strlcpy(cla->con_id, con_id, sizeof(cla->con_id)); |
| cla->cl.con_id = cla->con_id; |
| @@ -273,7 +281,7 @@ clkdev_alloc(struct clk *clk, const char |
| va_list ap; |
| |
| va_start(ap, dev_fmt); |
| - cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); |
| + cl = vclkdev_alloc(__clk_get_hw(clk), con_id, dev_fmt, ap); |
| va_end(ap); |
| |
| return cl; |
| @@ -334,7 +342,7 @@ int clk_register_clkdev(struct clk *clk, |
| return PTR_ERR(clk); |
| |
| va_start(ap, dev_fmt); |
| - cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); |
| + cl = vclkdev_alloc(__clk_get_hw(clk), con_id, dev_fmt, ap); |
| va_end(ap); |
| |
| if (!cl) |
| @@ -365,8 +373,8 @@ int clk_register_clkdevs(struct clk *clk |
| return PTR_ERR(clk); |
| |
| for (i = 0; i < num; i++, cl++) { |
| - cl->clk = clk; |
| - clkdev_add(cl); |
| + cl->clk_hw = __clk_get_hw(clk); |
| + __clkdev_add(cl); |
| } |
| |
| return 0; |
| --- a/include/linux/clkdev.h |
| +++ b/include/linux/clkdev.h |
| @@ -22,6 +22,7 @@ struct clk_lookup { |
| const char *dev_id; |
| const char *con_id; |
| struct clk *clk; |
| + struct clk_hw *clk_hw; |
| }; |
| |
| #define CLKDEV_INIT(d, n, c) \ |