Skip to content

Commit

Permalink
soc: aspeed: espi-slave: Avoid calling put_user in atomic context
Browse files Browse the repository at this point in the history
put_user() can sleep, which means that calling it in atomic context can
cause deadlock.
aspeed-espi-slave is calling it under spin_lock_irqsave(), resulting in
the following lockdep splat:
[   18.796723] BUG: sleeping function called from invalid context at drivers/soc/aspeed/aspeed-espi-slave.c:309
[   18.807742] in_atomic(): 1, irqs_disabled(): 128, non_block: 0, pid: 311, name: host-misc-manag
[   18.817486] INFO: lockdep is turned off.
[   18.821869] irq event stamp: 0
[   18.825289] hardirqs last  enabled at (0): [<00000000>] 0x0
[   18.831551] hardirqs last disabled at (0): [<8011ed40>] copy_process+0x7b0/0x1be8
[   18.839941] softirqs last  enabled at (0): [<8011ed40>] copy_process+0x7b0/0x1be8
[   18.848308] softirqs last disabled at (0): [<00000000>] 0x0
[   18.854538] CPU: 0 PID: 311 Comm: host-misc-manag Not tainted 5.15.0-14fcc87-dirty-7b64388 openbmc#1
[   18.864070] Hardware name: Generic DT based system
[   18.869421] Backtrace:
[   18.872155] [<80a48ec4>] (dump_backtrace) from [<80a492a8>] (show_stack+0x20/0x24)
[   18.880638]  r7:0242c06c r6:00000080 r5:80cb88f4 r4:600d0093
[   18.886969] [<80a49288>] (show_stack) from [<80a5596c>] (dump_stack_lvl+0x60/0x78)
[   18.895440] [<80a5590c>] (dump_stack_lvl) from [<80a5599c>] (dump_stack+0x18/0x1c)
[   18.903907]  r7:0242c06c r6:00000135 r5:80d0a958 r4:8ffc2000
[   18.910226] [<80a55984>] (dump_stack) from [<80160d3c>] (___might_sleep+0x1b0/0x2c0)
[   18.918901] [<80160b8c>] (___might_sleep) from [<80160ebc>] (__might_sleep+0x70/0xac)
[   18.927818]  r6:00000000 r5:00000135 r4:80d0a958
[   18.933024] [<80160e4c>] (__might_sleep) from [<802a1cf8>] (__might_fault+0x48/0xb0)
[   18.941690]  r6:8238da58 r5:00000000 r4:ffffe000
[   18.946848] [<802a1cb0>] (__might_fault) from [<8060ed78>] (aspeed_espi_pltrstn_read+0xac/0x254)
[   18.956679]  r5:8238da80 r4:ffffe000
[   18.960669] [<8060eccc>] (aspeed_espi_pltrstn_read) from [<802d6024>] (vfs_read+0xc0/0x320)
[   18.970011]  r10:00000003 r9:8ffc2000 r8:8060eccc r7:00000001 r6:00000001 r5:8ffc3f68
[   18.978754]  r4:84eb48c0
[   18.981582] [<802d5f64>] (vfs_read) from [<802d6e04>] (ksys_read+0x70/0xf4)
[   18.989378]  r10:00000003 r9:8ffc2000 r8:80100224 r7:00000000 r6:00000000 r5:84eb48c0
[   18.998122]  r4:84eb48c0
[   19.000946] [<802d6d94>] (ksys_read) from [<802d6ea0>] (sys_read+0x18/0x1c)
[   19.008735]  r7:00000003 r6:7ec07a00 r5:76fc3070 r4:0242c220
[   19.015055] [<802d6e88>] (sys_read) from [<80100060>] (ret_fast_syscall+0x0/0x1c)
[   19.023419] Exception stack(0x8ffc3fa8 to 0x8ffc3ff0)
[   19.029063] 3fa0:                   0242c220 76fc3070 00000007 0242c06c 00000001 00000000
[   19.038196] 3fc0: 0242c220 76fc3070 7ec07a00 00000003 0242c23c 0242c06c 00000001 00000000
[   19.047330] 3fe0: 00446be4 7ec079d8 00424b88 76cb536c

Rearrange the code to avoid calling *_user() function under spin_lock.
Also, use the regular *_irq() variant instead if *_irqsave(), since
it's only used for serializing process context with IRQ handler.

Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com>
Change-Id: Iaf17ddd17c020c8ee8c60c2fc98a57b97133e7a6
  • Loading branch information
iklimasz committed Dec 15, 2021
1 parent d4457cf commit c1000fe
Showing 1 changed file with 20 additions and 24 deletions.
44 changes: 20 additions & 24 deletions drivers/soc/aspeed/aspeed-espi-slave.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,24 +294,17 @@ static ssize_t aspeed_espi_pltrstn_read(struct file *filp, char __user *buf,
{
struct aspeed_espi *priv = to_aspeed_espi(filp);
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
char old_sample;
char data, old_sample;
int ret = 0;

spin_lock_irqsave(&priv->pltrstn_lock, flags);
spin_lock_irq(&priv->pltrstn_lock);

if (filp->f_flags & O_NONBLOCK) {
if (!priv->pltrstn_in_avail) {
ret = -EAGAIN;
goto out_unlock;
}
char data = priv->pltrstn;
ret = put_user(data, (unsigned long __user *)buf);
if (!ret){
ret = sizeof(data);
} else{
ret = -EAGAIN;
}
data = priv->pltrstn;
priv->pltrstn_in_avail = false;
} else {
add_wait_queue(&priv->pltrstn_waitq, &wait);
Expand All @@ -320,30 +313,33 @@ static ssize_t aspeed_espi_pltrstn_read(struct file *filp, char __user *buf,
old_sample = priv->pltrstn;

do {
char new_sample = priv->pltrstn;

if (old_sample != new_sample) {
ret = put_user(new_sample,
(unsigned long __user *)buf);
if (!ret)
ret = sizeof(new_sample);
} else if (signal_pending(current)) {
ret = -ERESTARTSYS;
if (old_sample != priv->pltrstn) {
data = priv->pltrstn;
priv->pltrstn_in_avail = false;
break;
}

if (!ret) {
spin_unlock_irqrestore(&priv->pltrstn_lock,
flags);
if (signal_pending(current)) {
ret = -ERESTARTSYS;
} else {
spin_unlock_irq(&priv->pltrstn_lock);
schedule();
spin_lock_irqsave(&priv->pltrstn_lock, flags);
spin_lock_irq(&priv->pltrstn_lock);
}
} while (!ret);

remove_wait_queue(&priv->pltrstn_waitq, &wait);
set_current_state(TASK_RUNNING);
}
out_unlock:
spin_unlock_irqrestore(&priv->pltrstn_lock, flags);
spin_unlock_irq(&priv->pltrstn_lock);

if (ret)
return ret;

ret = put_user(data, buf);
if (!ret)
ret = sizeof(data);

return ret;
}
Expand Down

0 comments on commit c1000fe

Please sign in to comment.