From: "Heiko Stübner" <heiko@sntech.de>
To: Stephen Boyd <sboyd@codeaurora.org>,
"Rafael J. Wysocki" <rjw@rjwysocki.net>,
Pavel Machek <pavel@ucw.cz>
Cc: mturquette@baylibre.com, linux-clk@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org
Subject: Re: [PATCH] clk: readd refcounting for struct clk instances [when used in pm_clk_add_clk(), genpd]
Date: Wed, 16 Sep 2015 11:18:05 +0200 [thread overview]
Message-ID: <9158634.8HmHM8CzF6@diego> (raw)
In-Reply-To: <20150916003931.GK23081@codeaurora.org>
Hi Stephen,
Am Dienstag, 15. September 2015, 17:39:31 schrieb Stephen Boyd:
> On 09/15, Heiko St=FCbner wrote:
> > With the split into struct clk and struct clk_core, clocks lost the=
> > ability for nested __clk_get clkdev calls. While it stays possible =
to
> > call __clk_get, the first call to (__)clk_put will clear the struct=
clk,
> > making subsequent clk_put calls run into a NULL pointer dereference=
.
> >=20
> > One prime example of this sits in the generic power domain code, wh=
ere it
> > is possible to add the clocks both by name and by passing in a stru=
ct clk
> > via pm_clk_add_clk(). __pm_clk_add() in turn then calls __clk_get t=
o
> > increase the refcount, so that the original code can put the clock =
again.
> >=20
> > A possible call-path looks like
> > clk =3D of_clk_get();
> > pm_clk_add_clk(dev, clk);
> > clk_put(clk);
> >=20
> > with pm_clk_add_clk() =3D> __pm_clk_add() then calling __clk_get on=
the clk
> > and later clk_put when the pm clock list gets destroyed, thus creat=
ing
> > a NULL pointer deref, as the struct clk doesn't exist anymore.
> >=20
> > So add a separate refcounting for struct clk instances and only cle=
an up
> > once the refcount reaches zero.
> >=20
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > I stumbled upon this while applying the new Rockchip power-domain d=
river,
> > but I guess the underlying issue is universal and probably present =
since
> > the original clk/clk_core split, so this probably counts as fix.
>=20
> Ok. The fix makes sense, but I wonder why we do this. Perhaps we
> should stop exporting __clk_get() and __clk_put() to everything
> that uses clkdev in the kernel. They're called per-user clks for
> a reason. There's one user. Now we have two users of the same
> struct clk instance, so we have to refcount it too? I hope the
> shared clk instance isn't being used to set rates in two pieces
> of code.
>=20
> And this only affects pm_clk_add_clk() callers right? So the only
> caller in the kernel (drivers/clk/shmobile/clk-mstp.c) doesn't
> seem to have this problem right now because it never calls
> clk_put() on the pointer it passes to pm_clk_add_clk().
As written above, I stumbled upon this with the new Rockchip power-doma=
in=20
driver [0] which calls pm_clk_add_clk in its rockchip_pd_attach_dev() f=
unction
[0] http://www.spinics.net/lists/kernel/msg2070432.html
> So what if we did the patch below? This would rely on callers not
> calling clk_put() before calling pm_clk_remove() or
> pm_clk_destroy(), and the life cycle would be clear, but the
> sharing is still there. Or we could say that after a clk is given
> to pm_clk_add_clk() that the caller shouldn't touch it anymore,
> like shmobile is doing right now. Then there's nothing to do
> besides remove the extra __clk_get() call in the pm layer.
I guess that is the call of the genpd people (Rafael and Pavel accordin=
g to=20
get_maintainers.pl). I'm very much fine with adapting the Rockchip powe=
r-
domain driver as needed to new handling paradigms.
Personally I'd prefer your solution of making the initial handler do al=
l the=20
getting and putting, as doing clk_get in the power-domain driver and re=
lying=20
on clk_put being done in the genpd core feels awkward. Although that so=
lution=20
would mean, the calling driver would also need to keep track of clocks,=
while=20
the current rockchip power-domain driver can just call clk_put after ha=
nding=20
the clock of to genpd.
>=20
> > @@ -2606,6 +2607,18 @@ static void __clk_release(struct kref *ref)
> >=20
> > =09kfree(core);
> > =20
> > }
> >=20
> > +static void __clk_release(struct kref *ref)
> > +{
> > +=09struct clk *clk =3D container_of(ref, struct clk, ref);
> > +
> > +=09hlist_del(&clk->clks_node);
> > +=09if ((clk->min_rate > clk->core->req_rate ||
> > +=09 clk->max_rate < clk->core->req_rate))
>=20
> Why did we grow a pair of parenthesis?
Remnant of me moving code around, sorry about that.
As it seems you prefer a different solution, I'll refrain from sending =
a fixed=20
version, till we decide which way to go :-).
>=20
> > +=09=09clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
> > +
> > +=09kfree(clk);
> > +}
> > +
> >=20
> > /*
> > =20
> > * Empty clk_ops for unregistered clocks. These are used temporari=
ly
> > * after clk_unregister() was called on a clock and until last clo=
ck
>=20
> diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/cloc=
k_ops.c
> index 652b5a367c1f..ef62bb3d7b26 100644
> --- a/drivers/base/power/clock_ops.c
> +++ b/drivers/base/power/clock_ops.c
> @@ -31,6 +31,7 @@ struct pm_clock_entry {
> =09char *con_id;
> =09struct clk *clk;
> =09enum pce_status status;
> +=09bool needs_clk_put;
> };
>=20
> /**
> @@ -59,8 +60,10 @@ static inline void __pm_clk_enable(struct device *=
dev,
> struct pm_clock_entry *ce */
> static void pm_clk_acquire(struct device *dev, struct pm_clock_entry=
*ce)
> {
> -=09if (!ce->clk)
> +=09if (!ce->clk) {
> =09=09ce->clk =3D clk_get(dev, ce->con_id);
> +=09=09ce->needs_clk_put =3D true;
> +=09}
> =09if (IS_ERR(ce->clk)) {
> =09=09ce->status =3D PCE_STATUS_ERROR;
> =09} else {
> @@ -93,7 +96,7 @@ static int __pm_clk_add(struct device *dev, const c=
har
> *con_id, return -ENOMEM;
> =09=09}
> =09} else {
> -=09=09if (IS_ERR(clk) || !__clk_get(clk)) {
> +=09=09if (IS_ERR(clk)) {
> =09=09=09kfree(ce);
> =09=09=09return -ENOENT;
> =09=09}
> @@ -149,7 +152,8 @@ static void __pm_clk_remove(struct pm_clock_entry=
*ce)
>=20
> =09=09if (ce->status >=3D PCE_STATUS_ACQUIRED) {
> =09=09=09clk_unprepare(ce->clk);
> -=09=09=09clk_put(ce->clk);
> +=09=09=09if (ce->needs_clk_put)
> +=09=09=09=09clk_put(ce->clk);
> =09=09}
> =09}
WARNING: multiple messages have this Message-ID (diff)
From: "Heiko Stübner" <heiko@sntech.de>
To: Stephen Boyd <sboyd@codeaurora.org>,
"Rafael J. Wysocki" <rjw@rjwysocki.net>,
Pavel Machek <pavel@ucw.cz>
Cc: mturquette@baylibre.com, linux-clk@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org
Subject: Re: [PATCH] clk: readd refcounting for struct clk instances [when used in pm_clk_add_clk(), genpd]
Date: Wed, 16 Sep 2015 11:18:05 +0200 [thread overview]
Message-ID: <9158634.8HmHM8CzF6@diego> (raw)
In-Reply-To: <20150916003931.GK23081@codeaurora.org>
Hi Stephen,
Am Dienstag, 15. September 2015, 17:39:31 schrieb Stephen Boyd:
> On 09/15, Heiko Stübner wrote:
> > With the split into struct clk and struct clk_core, clocks lost the
> > ability for nested __clk_get clkdev calls. While it stays possible to
> > call __clk_get, the first call to (__)clk_put will clear the struct clk,
> > making subsequent clk_put calls run into a NULL pointer dereference.
> >
> > One prime example of this sits in the generic power domain code, where it
> > is possible to add the clocks both by name and by passing in a struct clk
> > via pm_clk_add_clk(). __pm_clk_add() in turn then calls __clk_get to
> > increase the refcount, so that the original code can put the clock again.
> >
> > A possible call-path looks like
> > clk = of_clk_get();
> > pm_clk_add_clk(dev, clk);
> > clk_put(clk);
> >
> > with pm_clk_add_clk() => __pm_clk_add() then calling __clk_get on the clk
> > and later clk_put when the pm clock list gets destroyed, thus creating
> > a NULL pointer deref, as the struct clk doesn't exist anymore.
> >
> > So add a separate refcounting for struct clk instances and only clean up
> > once the refcount reaches zero.
> >
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > I stumbled upon this while applying the new Rockchip power-domain driver,
> > but I guess the underlying issue is universal and probably present since
> > the original clk/clk_core split, so this probably counts as fix.
>
> Ok. The fix makes sense, but I wonder why we do this. Perhaps we
> should stop exporting __clk_get() and __clk_put() to everything
> that uses clkdev in the kernel. They're called per-user clks for
> a reason. There's one user. Now we have two users of the same
> struct clk instance, so we have to refcount it too? I hope the
> shared clk instance isn't being used to set rates in two pieces
> of code.
>
> And this only affects pm_clk_add_clk() callers right? So the only
> caller in the kernel (drivers/clk/shmobile/clk-mstp.c) doesn't
> seem to have this problem right now because it never calls
> clk_put() on the pointer it passes to pm_clk_add_clk().
As written above, I stumbled upon this with the new Rockchip power-domain
driver [0] which calls pm_clk_add_clk in its rockchip_pd_attach_dev() function
[0] http://www.spinics.net/lists/kernel/msg2070432.html
> So what if we did the patch below? This would rely on callers not
> calling clk_put() before calling pm_clk_remove() or
> pm_clk_destroy(), and the life cycle would be clear, but the
> sharing is still there. Or we could say that after a clk is given
> to pm_clk_add_clk() that the caller shouldn't touch it anymore,
> like shmobile is doing right now. Then there's nothing to do
> besides remove the extra __clk_get() call in the pm layer.
I guess that is the call of the genpd people (Rafael and Pavel according to
get_maintainers.pl). I'm very much fine with adapting the Rockchip power-
domain driver as needed to new handling paradigms.
Personally I'd prefer your solution of making the initial handler do all the
getting and putting, as doing clk_get in the power-domain driver and relying
on clk_put being done in the genpd core feels awkward. Although that solution
would mean, the calling driver would also need to keep track of clocks, while
the current rockchip power-domain driver can just call clk_put after handing
the clock of to genpd.
>
> > @@ -2606,6 +2607,18 @@ static void __clk_release(struct kref *ref)
> >
> > kfree(core);
> >
> > }
> >
> > +static void __clk_release(struct kref *ref)
> > +{
> > + struct clk *clk = container_of(ref, struct clk, ref);
> > +
> > + hlist_del(&clk->clks_node);
> > + if ((clk->min_rate > clk->core->req_rate ||
> > + clk->max_rate < clk->core->req_rate))
>
> Why did we grow a pair of parenthesis?
Remnant of me moving code around, sorry about that.
As it seems you prefer a different solution, I'll refrain from sending a fixed
version, till we decide which way to go :-).
>
> > + clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
> > +
> > + kfree(clk);
> > +}
> > +
> >
> > /*
> >
> > * Empty clk_ops for unregistered clocks. These are used temporarily
> > * after clk_unregister() was called on a clock and until last clock
>
> diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
> index 652b5a367c1f..ef62bb3d7b26 100644
> --- a/drivers/base/power/clock_ops.c
> +++ b/drivers/base/power/clock_ops.c
> @@ -31,6 +31,7 @@ struct pm_clock_entry {
> char *con_id;
> struct clk *clk;
> enum pce_status status;
> + bool needs_clk_put;
> };
>
> /**
> @@ -59,8 +60,10 @@ static inline void __pm_clk_enable(struct device *dev,
> struct pm_clock_entry *ce */
> static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
> {
> - if (!ce->clk)
> + if (!ce->clk) {
> ce->clk = clk_get(dev, ce->con_id);
> + ce->needs_clk_put = true;
> + }
> if (IS_ERR(ce->clk)) {
> ce->status = PCE_STATUS_ERROR;
> } else {
> @@ -93,7 +96,7 @@ static int __pm_clk_add(struct device *dev, const char
> *con_id, return -ENOMEM;
> }
> } else {
> - if (IS_ERR(clk) || !__clk_get(clk)) {
> + if (IS_ERR(clk)) {
> kfree(ce);
> return -ENOENT;
> }
> @@ -149,7 +152,8 @@ static void __pm_clk_remove(struct pm_clock_entry *ce)
>
> if (ce->status >= PCE_STATUS_ACQUIRED) {
> clk_unprepare(ce->clk);
> - clk_put(ce->clk);
> + if (ce->needs_clk_put)
> + clk_put(ce->clk);
> }
> }
next prev parent reply other threads:[~2015-09-16 9:18 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-09-15 14:50 [PATCH] clk: readd refcounting for struct clk instances Heiko Stübner
2015-09-16 0:39 ` Stephen Boyd
2015-09-16 9:18 ` Heiko Stübner [this message]
2015-09-16 9:18 ` [PATCH] clk: readd refcounting for struct clk instances [when used in pm_clk_add_clk(), genpd] Heiko Stübner
2015-09-20 12:38 ` Heiko Stübner
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=9158634.8HmHM8CzF6@diego \
--to=heiko@sntech.de \
--cc=linux-clk@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=mturquette@baylibre.com \
--cc=pavel@ucw.cz \
--cc=rjw@rjwysocki.net \
--cc=sboyd@codeaurora.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.