Skip to content

Commit 4f619d5

Browse files
Jinjian-Songkuba-moo
authored andcommitted
net: wwan: t7xx: Fix FSM command timeout issue
When driver processes the internal state change command, it use an asynchronous thread to process the command operation. If the main thread detects that the task has timed out, the asynchronous thread will panic when executing the completion notification because the main thread completion object has been released. BUG: unable to handle page fault for address: fffffffffffffff8 PGD 1f283a067 P4D 1f283a067 PUD 1f283c067 PMD 0 Oops: 0000 [#1] PREEMPT SMP NOPTI RIP: 0010:complete_all+0x3e/0xa0 [...] Call Trace: <TASK> ? __die_body+0x68/0xb0 ? page_fault_oops+0x379/0x3e0 ? exc_page_fault+0x69/0xa0 ? asm_exc_page_fault+0x22/0x30 ? complete_all+0x3e/0xa0 fsm_main_thread+0xa3/0x9c0 [mtk_t7xx (HASH:1400 5)] ? __pfx_autoremove_wake_function+0x10/0x10 kthread+0xd8/0x110 ? __pfx_fsm_main_thread+0x10/0x10 [mtk_t7xx (HASH:1400 5)] ? __pfx_kthread+0x10/0x10 ret_from_fork+0x38/0x50 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1b/0x30 </TASK> [...] CR2: fffffffffffffff8 ---[ end trace 0000000000000000 ]--- Use the reference counter to ensure safe release as Sergey suggests: https://lore.kernel.org/all/[email protected]/ Fixes: 13e920d ("net: wwan: t7xx: Add core components") Signed-off-by: Jinjian Song <[email protected]> Acked-by: Sergey Ryazanov <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 03c8d0a commit 4f619d5

File tree

2 files changed

+20
-11
lines changed

2 files changed

+20
-11
lines changed

drivers/net/wwan/t7xx/t7xx_state_monitor.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,21 @@ void t7xx_fsm_broadcast_state(struct t7xx_fsm_ctl *ctl, enum md_state state)
104104
fsm_state_notify(ctl->md, state);
105105
}
106106

107+
static void fsm_release_command(struct kref *ref)
108+
{
109+
struct t7xx_fsm_command *cmd = container_of(ref, typeof(*cmd), refcnt);
110+
111+
kfree(cmd);
112+
}
113+
107114
static void fsm_finish_command(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd, int result)
108115
{
109116
if (cmd->flag & FSM_CMD_FLAG_WAIT_FOR_COMPLETION) {
110-
*cmd->ret = result;
111-
complete_all(cmd->done);
117+
cmd->result = result;
118+
complete_all(&cmd->done);
112119
}
113120

114-
kfree(cmd);
121+
kref_put(&cmd->refcnt, fsm_release_command);
115122
}
116123

117124
static void fsm_del_kf_event(struct t7xx_fsm_event *event)
@@ -475,7 +482,6 @@ static int fsm_main_thread(void *data)
475482

476483
int t7xx_fsm_append_cmd(struct t7xx_fsm_ctl *ctl, enum t7xx_fsm_cmd_state cmd_id, unsigned int flag)
477484
{
478-
DECLARE_COMPLETION_ONSTACK(done);
479485
struct t7xx_fsm_command *cmd;
480486
unsigned long flags;
481487
int ret;
@@ -487,11 +493,13 @@ int t7xx_fsm_append_cmd(struct t7xx_fsm_ctl *ctl, enum t7xx_fsm_cmd_state cmd_id
487493
INIT_LIST_HEAD(&cmd->entry);
488494
cmd->cmd_id = cmd_id;
489495
cmd->flag = flag;
496+
kref_init(&cmd->refcnt);
490497
if (flag & FSM_CMD_FLAG_WAIT_FOR_COMPLETION) {
491-
cmd->done = &done;
492-
cmd->ret = &ret;
498+
init_completion(&cmd->done);
499+
kref_get(&cmd->refcnt);
493500
}
494501

502+
kref_get(&cmd->refcnt);
495503
spin_lock_irqsave(&ctl->command_lock, flags);
496504
list_add_tail(&cmd->entry, &ctl->command_queue);
497505
spin_unlock_irqrestore(&ctl->command_lock, flags);
@@ -501,11 +509,11 @@ int t7xx_fsm_append_cmd(struct t7xx_fsm_ctl *ctl, enum t7xx_fsm_cmd_state cmd_id
501509
if (flag & FSM_CMD_FLAG_WAIT_FOR_COMPLETION) {
502510
unsigned long wait_ret;
503511

504-
wait_ret = wait_for_completion_timeout(&done,
512+
wait_ret = wait_for_completion_timeout(&cmd->done,
505513
msecs_to_jiffies(FSM_CMD_TIMEOUT_MS));
506-
if (!wait_ret)
507-
return -ETIMEDOUT;
508514

515+
ret = wait_ret ? cmd->result : -ETIMEDOUT;
516+
kref_put(&cmd->refcnt, fsm_release_command);
509517
return ret;
510518
}
511519

drivers/net/wwan/t7xx/t7xx_state_monitor.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,9 @@ struct t7xx_fsm_command {
110110
struct list_head entry;
111111
enum t7xx_fsm_cmd_state cmd_id;
112112
unsigned int flag;
113-
struct completion *done;
114-
int *ret;
113+
struct completion done;
114+
int result;
115+
struct kref refcnt;
115116
};
116117

117118
struct t7xx_fsm_notifier {

0 commit comments

Comments
 (0)