[PATCH] clk: remove the clk_notifier from clk_notifier_list beforefree it (was: Re: [BUG] zynq | CCF | SRCU)

From: Lai Jiangshan
Date: Mon Jun 03 2013 - 05:14:41 EST


On 06/01/2013 03:12 AM, SÃren Brinkmann wrote:
> Hi,
>
> we recently encountered some kernel panics when we compiled one of our
> drivers as module and tested inserting/removing the module.
> Trying to debug this issue, I could reproduce it on the mainline kernel
> with a dummy module.
>
> What happens is, that when on driver remove clk_notifier_unregister() is
> called and no other notifier for that clock is registered, the kernel
> panics.
> I'm not sure what is going wrong here. If there is a bug (and if where)
> or I'm just using the infrastructure the wrong way,... So, any hint is
> appreciated.
>
> I attach the output from the crashing system. The stacktrace indicates a
> crash in 'srcu_readers_seq_idx()'.
> I also attach the module I used to trigger the issue and a patch on top
> of mainline commit a93cb29acaa8f75618c3f202d1cf43c231984644 which has
> the DT modifications I need to make the module find its clock and boot
> with my initramfs.
>
>
> Thanks,
> SÃren
>



Hi, SÃren Brinkmann

I guess:

modprobe clk_notif_dbg
modprobe clk_notif_dbg -r # memory corrupt here
modprobe clk_notif_dbg # access corrupted memroy, but no visiable bug
modprobe clk_notif_dbg -r # access corrupted memroy, BUG


How the first "modprobe clk_notif_dbg -r" corrupt memroy:

=========

int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
{
struct clk_notifier *cn = NULL;
int ret = -EINVAL;

if (!clk || !nb)
return -EINVAL;

clk_prepare_lock();

list_for_each_entry(cn, &clk_notifier_list, node)
if (cn->clk == clk)
break;

if (cn->clk == clk) {
ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);

clk->notifier_count--;

/* XXX the notifier code should handle this better */
if (!cn->notifier_head.head) {
srcu_cleanup_notifier_head(&cn->notifier_head);

===========> the code forgot to remove @cn from the clk_notifier_list
===========> the second "modprobe clk_notif_dbg" will the same @clk and use the same corrupt @cn

kfree(cn);
}

} else {
ret = -ENOENT;
}

clk_prepare_unlock();

return ret;
}

===========

Could you retry with the following patch?

Thanks,
Lai