Skip to content

Commit 53c0441

Browse files
Jiri Pirkokuba-moo
authored andcommitted
dpll: fix possible deadlock during netlink dump operation
Recently, I've been hitting following deadlock warning during dpll pin dump: [52804.637962] ====================================================== [52804.638536] WARNING: possible circular locking dependency detected [52804.639111] 6.8.0-rc2jiri+ #1 Not tainted [52804.639529] ------------------------------------------------------ [52804.640104] python3/2984 is trying to acquire lock: [52804.640581] ffff88810e642678 (nlk_cb_mutex-GENERIC){+.+.}-{3:3}, at: netlink_dump+0xb3/0x780 [52804.641417] but task is already holding lock: [52804.642010] ffffffff83bde4c8 (dpll_lock){+.+.}-{3:3}, at: dpll_lock_dumpit+0x13/0x20 [52804.642747] which lock already depends on the new lock. [52804.643551] the existing dependency chain (in reverse order) is: [52804.644259] -> #1 (dpll_lock){+.+.}-{3:3}: [52804.644836] lock_acquire+0x174/0x3e0 [52804.645271] __mutex_lock+0x119/0x1150 [52804.645723] dpll_lock_dumpit+0x13/0x20 [52804.646169] genl_start+0x266/0x320 [52804.646578] __netlink_dump_start+0x321/0x450 [52804.647056] genl_family_rcv_msg_dumpit+0x155/0x1e0 [52804.647575] genl_rcv_msg+0x1ed/0x3b0 [52804.648001] netlink_rcv_skb+0xdc/0x210 [52804.648440] genl_rcv+0x24/0x40 [52804.648831] netlink_unicast+0x2f1/0x490 [52804.649290] netlink_sendmsg+0x36d/0x660 [52804.649742] __sock_sendmsg+0x73/0xc0 [52804.650165] __sys_sendto+0x184/0x210 [52804.650597] __x64_sys_sendto+0x72/0x80 [52804.651045] do_syscall_64+0x6f/0x140 [52804.651474] entry_SYSCALL_64_after_hwframe+0x46/0x4e [52804.652001] -> #0 (nlk_cb_mutex-GENERIC){+.+.}-{3:3}: [52804.652650] check_prev_add+0x1ae/0x1280 [52804.653107] __lock_acquire+0x1ed3/0x29a0 [52804.653559] lock_acquire+0x174/0x3e0 [52804.653984] __mutex_lock+0x119/0x1150 [52804.654423] netlink_dump+0xb3/0x780 [52804.654845] __netlink_dump_start+0x389/0x450 [52804.655321] genl_family_rcv_msg_dumpit+0x155/0x1e0 [52804.655842] genl_rcv_msg+0x1ed/0x3b0 [52804.656272] netlink_rcv_skb+0xdc/0x210 [52804.656721] genl_rcv+0x24/0x40 [52804.657119] netlink_unicast+0x2f1/0x490 [52804.657570] netlink_sendmsg+0x36d/0x660 [52804.658022] __sock_sendmsg+0x73/0xc0 [52804.658450] __sys_sendto+0x184/0x210 [52804.658877] __x64_sys_sendto+0x72/0x80 [52804.659322] do_syscall_64+0x6f/0x140 [52804.659752] entry_SYSCALL_64_after_hwframe+0x46/0x4e [52804.660281] other info that might help us debug this: [52804.661077] Possible unsafe locking scenario: [52804.661671] CPU0 CPU1 [52804.662129] ---- ---- [52804.662577] lock(dpll_lock); [52804.662924] lock(nlk_cb_mutex-GENERIC); [52804.663538] lock(dpll_lock); [52804.664073] lock(nlk_cb_mutex-GENERIC); [52804.664490] The issue as follows: __netlink_dump_start() calls control->start(cb) with nlk->cb_mutex held. In control->start(cb) the dpll_lock is taken. Then nlk->cb_mutex is released and taken again in netlink_dump(), while dpll_lock still being held. That leads to ABBA deadlock when another CPU races with the same operation. Fix this by moving dpll_lock taking into dumpit() callback which ensures correct lock taking order. Fixes: 9d71b54 ("dpll: netlink: Add DPLL framework base functions") Signed-off-by: Jiri Pirko <[email protected]> Reviewed-by: Arkadiusz Kubalewski <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 1f719a2 commit 53c0441

File tree

4 files changed

+6
-24
lines changed

4 files changed

+6
-24
lines changed

Documentation/netlink/specs/dpll.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,6 @@ operations:
384384
- type
385385

386386
dump:
387-
pre: dpll-lock-dumpit
388-
post: dpll-unlock-dumpit
389387
reply: *dev-attrs
390388

391389
-
@@ -473,8 +471,6 @@ operations:
473471
- fractional-frequency-offset
474472

475473
dump:
476-
pre: dpll-lock-dumpit
477-
post: dpll-unlock-dumpit
478474
request:
479475
attributes:
480476
- id

drivers/dpll/dpll_netlink.c

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,7 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
11991199
unsigned long i;
12001200
int ret = 0;
12011201

1202+
mutex_lock(&dpll_lock);
12021203
xa_for_each_marked_start(&dpll_pin_xa, i, pin, DPLL_REGISTERED,
12031204
ctx->idx) {
12041205
if (!dpll_pin_available(pin))
@@ -1218,6 +1219,8 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
12181219
}
12191220
genlmsg_end(skb, hdr);
12201221
}
1222+
mutex_unlock(&dpll_lock);
1223+
12211224
if (ret == -EMSGSIZE) {
12221225
ctx->idx = i;
12231226
return skb->len;
@@ -1373,6 +1376,7 @@ int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
13731376
unsigned long i;
13741377
int ret = 0;
13751378

1379+
mutex_lock(&dpll_lock);
13761380
xa_for_each_marked_start(&dpll_device_xa, i, dpll, DPLL_REGISTERED,
13771381
ctx->idx) {
13781382
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
@@ -1389,6 +1393,8 @@ int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
13891393
}
13901394
genlmsg_end(skb, hdr);
13911395
}
1396+
mutex_unlock(&dpll_lock);
1397+
13921398
if (ret == -EMSGSIZE) {
13931399
ctx->idx = i;
13941400
return skb->len;
@@ -1439,20 +1445,6 @@ dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
14391445
mutex_unlock(&dpll_lock);
14401446
}
14411447

1442-
int dpll_lock_dumpit(struct netlink_callback *cb)
1443-
{
1444-
mutex_lock(&dpll_lock);
1445-
1446-
return 0;
1447-
}
1448-
1449-
int dpll_unlock_dumpit(struct netlink_callback *cb)
1450-
{
1451-
mutex_unlock(&dpll_lock);
1452-
1453-
return 0;
1454-
}
1455-
14561448
int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
14571449
struct genl_info *info)
14581450
{

drivers/dpll/dpll_nl.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,7 @@ static const struct genl_split_ops dpll_nl_ops[] = {
9595
},
9696
{
9797
.cmd = DPLL_CMD_DEVICE_GET,
98-
.start = dpll_lock_dumpit,
9998
.dumpit = dpll_nl_device_get_dumpit,
100-
.done = dpll_unlock_dumpit,
10199
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
102100
},
103101
{
@@ -129,9 +127,7 @@ static const struct genl_split_ops dpll_nl_ops[] = {
129127
},
130128
{
131129
.cmd = DPLL_CMD_PIN_GET,
132-
.start = dpll_lock_dumpit,
133130
.dumpit = dpll_nl_pin_get_dumpit,
134-
.done = dpll_unlock_dumpit,
135131
.policy = dpll_pin_get_dump_nl_policy,
136132
.maxattr = DPLL_A_PIN_ID,
137133
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,

drivers/dpll/dpll_nl.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
3030
void
3131
dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
3232
struct genl_info *info);
33-
int dpll_lock_dumpit(struct netlink_callback *cb);
34-
int dpll_unlock_dumpit(struct netlink_callback *cb);
3533

3634
int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info);
3735
int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info);

0 commit comments

Comments
 (0)