On 7/15/20 10:08 PM, Saravana Kannan wrote: > Marek and Guenter reported that commit 287905e68dd2 ("driver core: > Expose device link details in sysfs") caused sleeping/scheduling while > atomic warnings. > > BUG: sleeping function called from invalid context at > kernel/locking/mutex.c:935 > in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 12, name: kworker/0:1 > 2 locks held by kworker/0:1/12: > #0: ee8074a8 ((wq_completion)rcu_gp){+.+.}-{0:0}, at: > process_one_work+0x174/0x7dc > #1: ee921f20 ((work_completion)(&sdp->work)){+.+.}-{0:0}, at: > process_one_work+0x174/0x7dc > Preemption disabled at: > [<c01b10f0>] srcu_invoke_callbacks+0xc0/0x154 > ----- 8< ----- SNIP > [<c064590c>] (device_del) from [<c0645c9c>] (device_unregister+0x24/0x64) > [<c0645c9c>] (device_unregister) from [<c01b10fc>] > (srcu_invoke_callbacks+0xcc/0x154) > [<c01b10fc>] (srcu_invoke_callbacks) from [<c01493c4>] > (process_one_work+0x234/0x7dc) > [<c01493c4>] (process_one_work) from [<c01499b0>] (worker_thread+0x44/0x51c) > [<c01499b0>] (worker_thread) from [<c0150bf4>] (kthread+0x158/0x1a0) > [<c0150bf4>] (kthread) from [<c0100114>] (ret_from_fork+0x14/0x20) > Exception stack(0xee921fb0 to 0xee921ff8) > > This was caused by the device link device being released in the context > of srcu_invoke_callbacks(). There is no need to wait till the RCU > callback to release the device link device. So release the device > earlier and revert the RCU callback code to what it was before > commit 287905e68dd2 ("driver core: Expose device link details in sysfs") > > Fixes: 287905e68dd2 ("driver core: Expose device link details in sysfs") > Reported-by: Marek Szyprowski <m.szyprow...@samsung.com> > Reported-by: Guenter Roeck <li...@roeck-us.net> > Signed-off-by: Saravana Kannan <sarava...@google.com> > --- > Marek and Guenter, > > It haven't had a chance to test this yet. Can one of you please test it > and confirm it fixes the issue? >
With this patch applied, the original warning is gone, but I get lots of other warnings. WARNING: CPU: 0 PID: 1 at drivers/base/core.c:1790 device_release+0x94/0xa4^M Device 'regulators:regulator@0:50038000.ethernet' does not have a release() function, it is broken and must be fixed. WARNING: CPU: 0 PID: 1 at drivers/base/core.c:1790 device_release+0x94/0xa4 Device '53f9c000.gpio:50038000.ethernet' does not have a release() function, it is broken and must be fixed. WARNING: CPU: 0 PID: 1 at drivers/base/core.c:1790 device_release+0x94/0xa4^M Device '50030000.tscadc:50030400.tcq' does not have a release() function, it is broken and must be fixed. and so on. I don't know if this is caused by this patch or by some other patch in -next. Guenter > Thanks, > Saravana > > drivers/base/core.c | 10 +++------- > 1 file changed, 3 insertions(+), 7 deletions(-) > > diff --git a/drivers/base/core.c b/drivers/base/core.c > index 5373ddd029f6..ccb2ce11f5b5 100644 > --- a/drivers/base/core.c > +++ b/drivers/base/core.c > @@ -306,16 +306,10 @@ static struct attribute *devlink_attrs[] = { > }; > ATTRIBUTE_GROUPS(devlink); > > -static void devlink_dev_release(struct device *dev) > -{ > - kfree(to_devlink(dev)); > -} > - > static struct class devlink_class = { > .name = "devlink", > .owner = THIS_MODULE, > .dev_groups = devlink_groups, > - .dev_release = devlink_dev_release, > }; > > static int devlink_add_symlinks(struct device *dev, > @@ -737,7 +731,7 @@ static void device_link_free(struct device_link *link) > > put_device(link->consumer); > put_device(link->supplier); > - device_unregister(&link->link_dev); > + kfree(link); > } > > #ifdef CONFIG_SRCU > @@ -756,6 +750,7 @@ static void __device_link_del(struct kref *kref) > if (link->flags & DL_FLAG_PM_RUNTIME) > pm_runtime_drop_link(link->consumer); > > + device_unregister(&link->link_dev); > list_del_rcu(&link->s_node); > list_del_rcu(&link->c_node); > call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu); > @@ -771,6 +766,7 @@ static void __device_link_del(struct kref *kref) > if (link->flags & DL_FLAG_PM_RUNTIME) > pm_runtime_drop_link(link->consumer); > > + device_unregister(&link->link_dev); > list_del(&link->s_node); > list_del(&link->c_node); > device_link_free(link); >