Kernel panic when unloading libertas_sdio driver.
Marek Vasut
marek.vasut at gmail.com
Fri Jun 4 23:51:05 EDT 2010
Dne Čt 3. června 2010 05:03:53 dinuliang at sina.com napsal(a):
> Dear All
> I am porting wifi support on Android to the s3c6410 developement board, and
> my kernel version is 2.6.32. The problem i'm dealing with is that
> sometimes when user unload the libertas_sdio driver,the kernel panic at
> lbs_stop_card.
>
> I track the problem, and find out it is cause by the kill system call.I
> tried to fix this, but i'm not sure if i did it right.
>
> My analysis of this problem is as follows:
> In Android, when user want to disable the driver,the java service will ask
> the init process to stop the wpa_supplicant process,and then unload the
> wifi driver.The init process will call kill system call to do stop
> wpa_supplicant. This may cause a problem:
>
> When kernel send a kill signal,it has to wake up the target process,and
> wpa_supplicant process is probably sleeping in __lbs_cmd while waiting for
> a command to complete,and at the mean time the command may still in the
> priv->cmdpendingq, not submitted yet.
>
> int __lbs_cmd(struct lbs_private *priv, uint16_t command,
> struct cmd_header *in_cmd, int
> in_cmd_size, int (*callback)(struct
> lbs_private *, unsigned long, struct cmd_header *),
> unsigned long callback_arg)
> {
> struct cmd_ctrl_node *cmdnode;
> unsigned long flags;
> int ret = 0;
>
> lbs_deb_enter(LBS_DEB_HOST);
>
> cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
> callback, callback_arg);
> if (IS_ERR(cmdnode)) {
> ret = PTR_ERR(cmdnode);
> goto done;
> }
>
> might_sleep();
> ret = wait_event_interruptible(cmdnode->cmdwait_q,
> cmdnode->cmdwaitqwoken);
> spin_lock_irqsave(&priv->driver_lock, flags);
> ret = cmdnode->result;
> if (ret)
> lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
> command, ret);
>
> __lbs_cleanup_and_insert_cmd(priv, cmdnode);
> spin_unlock_irqrestore(&priv->driver_lock, flags);
>
> done:
> lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
> return ret;
> }
>
> So after kernel wake up the process from wait_event_interruptible and clean
> up the node and add it to the free list, the other pending list node or
> head is still keep link to it. When user unload the driver,the kernel will
> crash at __wake_up_common in lbs_stop_card.*/ /* Flush pending
> command nodes */
> spin_lock_irqsave(&priv->driver_lock, flags);
> lbs_deb_main("clearing pending commands\n");
> list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
> cmdnode->result = -ENOENT;
> cmdnode->cmdwaitqwoken = 1;
> wake_up_interruptible(&cmdnode->cmdwait_q);
> }
>
> This is because the command node still linked in the priv->cmdpendingq,and
> it self link to the priv->cmdfreeq.The list_for_each_entry will step to
> the list head of priv->cmdfreeq,which is doesn't have a command node
> structure,and this will cause kernel penic when doing wake_up to it. The
> dump log is as follows, i dump the command node structure befor the wake
> up:
>
> libertas enter: lbs_stop_card()
> libertas main: clearing pending commands
> lbs_stop_card:has pending command node.
> Dump command node:address of command node =c7ef00d8,list->prev
> =c7f38d98,list->next=c7f38d90, result = 0, address of callback=0,
> callback_arg = 0,address of cmdbuf = c1d8d000, cmdwaitqwoken = 1,
> address of cmdwait_q = c7ef00f4.
> task state= 0, PID= 0.
> Dump command node:address of command node =c7f38d90,list->prev
> =c7ef00d8,list->next=c7ef0000, result = -940637992, address of
> callback=c7ef0120, callback_arg = c7f38da0,address of cmdbuf = c7f38da0,
> cmdwaitqwoken = 8449, address of cmdwait_q = c7f38dac.
> task state= 4001b508, PID= 65686361.
> Unable to handle kernel NULL pointer dereference at virtual address
> 00000000 pgd = c7eb4000
> [00000000] *pgd=57ead031, *pte=00000000, *ppte=00000000
> Internal error: Oops: 80000007 [#1]
> last sysfs file: /sys/android_power/request_state
> Modules linked in: wlan(-) [last unloaded: wlan]
> CPU: 0 Tainted:
> G W
> (2.6.32-00003-g930aecc-dirty #46) PC is at 0x0
> LR is at __wake_up_common+0x34/0x78
> pc : [<00000000>] lr : [<c0043d28>]
> psr: a00000b3 sp : c7fbbdc8 ip : 00015000 fp : c7fbbdf4
> r10: 00000000 r9 : 00000001 r8 : c7f38dac
> r7 : 00000001 r6 : 00000001 r5 : 001027fc r4 : 00014ff4
> r3 : 00000000 r2 : 00000000 r1 : 00000001 r0 : 00014ff4
> Flags: NzCv IRQs off FIQs on Mode SVC_32 ISA
> Thumb Segment user Control: 00c5387d Table: 57eb4008
> DAC: 00000015
> Process WifiService (pid: 1731, stack limit = 0xc7fba268)
> Stack: (0xc7fbbdc8 to 0xc7fbc000)
> bdc0: &nbs
> p; 00000000 60000093 c7f38d90 c7f382c0
> c7f38d98 c7f38000 bde0: c7fba000 00000013 c7fbbe14 c7fbbdf8 c0043d94
> c0043d00 00000000 c7fbbe18 be00: c020239c c7f38dac c7fbbe54 c7fbbe18
> c02023b0 c0043d78 c7ef00d8 c7ef0120 be20: c7f38da0 c7f38da0 00002101
> c7f38dac c7cef3e0 c7fe0000 c7cef3e0 00000880 be40: c002c028 00000000
> c7fbbe84 c7fbbe58 bf03015c c02021fc 00000000 c7cef3f0 be60: bf032a30
> c7cef3e8 bf032a30 c7cef3e0 bf032a30 bf032a30 c7fbbe9c c7fbbe88 be80:
> c024bbac bf03000c c7cef3e8 bf032a30 c7fbbeb4 c7fbbea0 c01d11f4 c024bb98
> bea0: c7cef3e8 c7cef41c c7fbbed4 c7fbbeb8 c01d129c c01d1194 bf032a30
> bf032a30 bec0: c041d93c 00000880 c7fbbef4 c7fbbed8 c01d04a4 c01d1240
> 00000000 bf032a30 bee0: 00000000 00000880 c7fbbf14 c7fbbef8 c01d1800
> c01d0418 00000000 bf032a64 bf00: c7fbbf3c 00000880 c7fbbf24 c7fbbf18
> c024bd9c c01d17a4 c7fbbf34 c7fbbf28 bf20: bf03208c c024bd88 c7fbbfa4
> c7fbbf38 c006ccbc bf032024 c1c4f1e0 6e616c77 bf40: c7892200 00000006
> c002c028 00000000 c7fbbf6c c7fbbf60 c009d3c0 c009d1d4 bf60: c7fbbf8c
> c7fbbf70 c009a00c c009d39c c7892240 00c4f1e0 bf032a64 00000880 bf80:
> c7fbbf84 00000000 a9c07658 ffffffff 00000009 00000081 00000000 c7fbbfa8
> bfa0: c002be80 c006caf4 a9c07658 ffffffff a9c062e4 00000880 42747f3c
> 425f327c bfc0: a9c07658 ffffffff 00000009 00000081 46364d88 42747ee4
> 42747ed0 002d90c8 bfe0: a9c07680 46364d50 a9c05c69 afe0d8ac 00000010
> a9c062e4 00000000 00000000 Backtrace:
> [<c0043cf4>] (__wake_up_common+0x0/0x78) from [<c0043d94>]
> (__wake_up+0x28/0x34) The command node at the address 0xc7f38d90 is
> the node we discussed,it link to the head of free list.
> To fix that, i do some change in __lbs_cmd, and the problem seems go
> away.
> ret = wait_event_interruptible(cmdnode->cmdwait_q,
> cmdnode->cmdwaitqwoken); if (ret == -ERESTARTSYS || cmdnode->result
> == -ENOENT) {
> lbs_pr_info("Remove command node from pending list,have pending
> signal, cmdnode address %lx.\n", cmdnode);
> if (cmdnode != priv->cur_cmd)
> list_del(&cmdnode->list);
> }
>
> Am i do it right?Thanks very much and Best Regards Liang Yifei
Good god ... please fix your mailer and resend this again.
More information about the libertas-dev
mailing list