diff mbox

opp: convert dev_warn() to dev_dbg() for duplicate OPPs

Message ID CAKohpoknu=V_wscVPWLdZO8xEGY6CVMNXuP4F76GNABnm9K4dQ@mail.gmail.com
State New
Headers show

Commit Message

Viresh Kumar Nov. 19, 2014, 7:46 a.m. UTC
On 19 November 2014 02:21, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> On Tuesday, November 18, 2014 08:38:14 AM Viresh Kumar wrote:

>> We are allowing addition of duplicate OPPs as a standard thing right now
>> as cpufreq drivers don't get rid of the OPPs they create with DT. So, that
>> shouldn't complain, isn't it ?
>
> Is cpufreq the only user of OPP?  I thought there were other users, so what
> about them?

Probably of CPU OPPs, but I am not sure. Obviously dev OPPs can be used
by others.

> I'm not sure about that.  If they aren't useful for anything after
> that, what's the benefit of keeping them around?

I don't think they are of any use once the driver is gone, unless the driver is
inserted again.

So, this is what we can do to distinguish DT OPPs with other dynamic ones:



Does this look fine? I can then write of_free_opp_table(), opposite of
of_init_opp_table().
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Rafael J. Wysocki Nov. 21, 2014, 3:58 p.m. UTC | #1
On Wednesday, November 19, 2014 01:16:24 PM Viresh Kumar wrote:
> On 19 November 2014 02:21, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> > On Tuesday, November 18, 2014 08:38:14 AM Viresh Kumar wrote:
> 
> >> We are allowing addition of duplicate OPPs as a standard thing right now
> >> as cpufreq drivers don't get rid of the OPPs they create with DT. So, that
> >> shouldn't complain, isn't it ?
> >
> > Is cpufreq the only user of OPP?  I thought there were other users, so what
> > about them?
> 
> Probably of CPU OPPs, but I am not sure. Obviously dev OPPs can be used
> by others.
> 
> > I'm not sure about that.  If they aren't useful for anything after
> > that, what's the benefit of keeping them around?
> 
> I don't think they are of any use once the driver is gone, unless the driver is
> inserted again.
> 
> So, this is what we can do to distinguish DT OPPs with other dynamic ones:
> 
> diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
> index 490e9db..7e25f01 100644
> --- a/drivers/base/power/opp.c
> +++ b/drivers/base/power/opp.c
> @@ -49,6 +49,7 @@
>   *             are protected by the dev_opp_list_lock for integrity.
>   *             IMPORTANT: the opp nodes should be maintained in increasing
>   *             order.
> + * @from_dt:   created from static DT entries.

What about @dynamic instead of @from_dt?  That may apply to more use cases if
need be.

>   * @available: true/false - marks if this OPP as available or not
>   * @rate:      Frequency in hertz
>   * @u_volt:    Nominal voltage in microvolts corresponding to this OPP
> @@ -61,6 +62,7 @@ struct dev_pm_opp {
>         struct list_head node;
> 
>         bool available;
> +       bool from_dt;
>         unsigned long rate;
>         unsigned long u_volt;
> 
> 
> 
> Does this look fine? I can then write of_free_opp_table(), opposite of
> of_init_opp_table().
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Viresh Kumar Nov. 24, 2014, 10:40 a.m. UTC | #2
On 21 November 2014 at 21:28, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> What about @dynamic instead of @from_dt?  That may apply to more use cases if
> need be.

@Paul: I am stuck at a point and need help on RCUs :)

File: drivers/base/power/opp.c

We are trying to remove OPPs created from static data present in DT on
cpufreq driver's removal (when configured as module).

opp core uses RCUs internally and it looks like I need to implement:
list_for_each_entry_safe_rcu()

But, I am not sure because of these:
http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-10/6280.html
http://patchwork.ozlabs.org/patch/48989/

So, wanted to ask you if I really need that or the OPP code is
buggy somewhere.

The code removing OPPs is:

        list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) {
                srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_REMOVE, opp);
                list_del_rcu(&opp->node);

                kfree(opp);
        }

Because we are freeing opp at the end, list_for_each_entry_rcu()
is trying to read the already freed opp to find opp->node.next
and that results in a crash.

What am I doing wrong ?

--
viresh
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Viresh Kumar Nov. 25, 2014, 6:32 a.m. UTC | #3
On 24 November 2014 at 20:39, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> I hope that doesn't happen under rcu_read_lock()?

No. Should it?

> The modification needs to be done under dev_opp_list_lock in the first place

Yeah, its there to protect against other updaters.

> in which case you don't need the _rcu version of list walking, so you simply
> can use list_for_each_entry_safe() here. The mutex is sufficient for the
> synchronization with other writers (if any).  The freeing, though, has to be

Correct.

> deferred until all readers drop their references to the old entry.  You can
> use kfree_rcu() for that.

Cool. I understood the concept atleast. And yes I followed the srcu mail from
paul as well.. Will reply there.
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Viresh Kumar Nov. 25, 2014, 10:37 a.m. UTC | #4
On 24 November 2014 at 21:44, Paul E. McKenney
<paulmck@linux.vnet.ibm.com> wrote:
> As Rafael says, if opp is reachable by RCU readers, you cannot just
> immediately kfree() it.  Immediately kfree()ing it like this -will-
> cause your RCU readers to see freed memory, which, as you noted, can
> cause crashes.

In order to reply you at some level, I tried going through RCU documentation
today before replying anymore. And yes I understood this part.

> Except that srcu_notifier_call_chain() involves SRCU readers.  So,
> unless I am confused, you instead need something like this:
>
> static void kfree_opp_rcu(struct rcu_head *rhp)
> {
>         struct device_opp *opp = container_of(rhp, struct device_opp, opp_list);
>
>         kfree(opp);
> }
>
> Then replace the above kfree() by:
>
>         call_srcu(&opp->rcu, kfree_opp_rcu);

Correct. But you missed the srcu which should be the first argument here :)

> This will require adding the following to struct device_opp:
>
>         struct rcu_head rcu;

We were freeing struct dev_pm_opp, and so I believe you
wanted me to add it there? Its already there.

> All that said, I do not claim to understand the OPP code, so please take
> the above suggested changes with a grain of salt.  And if you let me know
> where I am confused, I should be able to offer better suggestions.

Thanks for your suggestions. I have sent the patch to list and cc'd you on
the relevant ones. Would be great if you can review the rcu part there.

--
viresh
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index 490e9db..7e25f01 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -49,6 +49,7 @@ 
  *             are protected by the dev_opp_list_lock for integrity.
  *             IMPORTANT: the opp nodes should be maintained in increasing
  *             order.
+ * @from_dt:   created from static DT entries.
  * @available: true/false - marks if this OPP as available or not
  * @rate:      Frequency in hertz
  * @u_volt:    Nominal voltage in microvolts corresponding to this OPP
@@ -61,6 +62,7 @@  struct dev_pm_opp {
        struct list_head node;

        bool available;
+       bool from_dt;
        unsigned long rate;
        unsigned long u_volt;