mirror of
https://github.com/shenmintao/aic8800d80.git
synced 2026-11-10 16:49:17 +00:00
Merge pull request #106 from xuxinchun1003/fix/legacy-teardown-lifetime
This commit is contained in:
commit
6e8222c10a
3 files changed
+52
-3
No files matched your search
@@ -210,6 +210,15 @@ void aicwf_bus_deinit(struct device *dev)
|
|||||||
AICWFDBG(LOGINFO, "%s Enter\r\n", __func__);
|
AICWFDBG(LOGINFO, "%s Enter\r\n", __func__);
|
||||||
|
|
||||||
bus_if = dev_get_drvdata(dev);
|
bus_if = dev_get_drvdata(dev);
|
||||||
|
/* 入口判空:本函数在探测失败路径上会被调用**两次**
|
||||||
|
* aicwf_bus_init() 的 `fail:` 先调一次,随后 aicwf_usb_probe() 的
|
||||||
|
* `out_free_bus:` 再调一次(用局部 bus_if 做 kfree,不依赖 drvdata)。
|
||||||
|
* 第二次进入时 drvdata 已在**上一次调用的末尾**被清空 → 必然命中本判空。
|
||||||
|
* 若不清空,第二次会对已完整拆解的对象重复执行整套 teardown。 */
|
||||||
|
if (!bus_if) {
|
||||||
|
AICWFDBG(LOGINFO, "%s: already deinitialized, skip\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
aicwf_bus_stop(bus_if);
|
aicwf_bus_stop(bus_if);
|
||||||
|
|
||||||
#ifdef AICWF_USB_SUPPORT
|
#ifdef AICWF_USB_SUPPORT
|
||||||
@@ -260,6 +269,20 @@ void aicwf_bus_deinit(struct device *dev)
|
|||||||
tasklet_kill(&usb->xmit_tasklet);
|
tasklet_kill(&usb->xmit_tasklet);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* 清空 drvdata:全部拆解完成之后、对象由调用方释放之前。
|
||||||
|
* (评审 shenmintao/aic8800d80#103 指出的顺序问题:此前清空点位于
|
||||||
|
* bus_stop 之后、URB/platform/rx/cmd 拆解与 TX 线程 join 之前。)
|
||||||
|
* 1) 顺序双 deinit:第二次调用靠上方入口判空在本行之后必然 skip;
|
||||||
|
* 2) 过早清空会伤害仍在运行的读者——TX 链
|
||||||
|
* usb_bustx_thread → aicwf_bus_txdata(usbdev->bus_if) →
|
||||||
|
* ops->txdata = aicwf_usb_bus_txdata()(usb.c 在该处重读
|
||||||
|
* dev_get_drvdata)仅靠 state 检查做 check-then-act、无锁,
|
||||||
|
* 且该线程直到上方 kthread_stop(bustx_thread) 才被 join——
|
||||||
|
* 必须先 join 再清;
|
||||||
|
* 3) cmd/rx/platform 拆解与 rwnx_close() 等读者在本行之前全程
|
||||||
|
* 看到非空 drvdata,行为与未打补丁树一致。 */
|
||||||
|
dev_set_drvdata(dev, NULL);
|
||||||
|
|
||||||
AICWFDBG(LOGINFO, "%s Exit \n", __func__);
|
AICWFDBG(LOGINFO, "%s Exit \n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1409,6 +1409,11 @@ static int aicwf_usb_bus_txmsg(struct device *dev, u8 *buf, u32 len)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct aicwf_bus *bus_if = dev_get_drvdata(dev);
|
struct aicwf_bus *bus_if = dev_get_drvdata(dev);
|
||||||
|
/* Defense in depth (review #103): with the parent commit's ordering the
|
||||||
|
* cmd thread is quiesced before drvdata is cleared, so this should be
|
||||||
|
* unreachable — guard anyway against a future/premature caller. */
|
||||||
|
if (bus_if == NULL)
|
||||||
|
return -ENODEV;
|
||||||
struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb;
|
struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb;
|
||||||
|
|
||||||
if (usb_dev->state != USB_UP_ST)
|
if (usb_dev->state != USB_UP_ST)
|
||||||
@@ -1667,6 +1672,10 @@ static int aicwf_usb_bus_txdata(struct device *dev, struct sk_buff *pkt)
|
|||||||
uint prio;
|
uint prio;
|
||||||
int ret = -EBADE;
|
int ret = -EBADE;
|
||||||
struct aicwf_bus *bus_if = dev_get_drvdata(dev);
|
struct aicwf_bus *bus_if = dev_get_drvdata(dev);
|
||||||
|
/* Defense in depth (review #103): usb_bustx_thread is joined before
|
||||||
|
* drvdata is cleared; guard any other/premature caller. */
|
||||||
|
if (bus_if == NULL)
|
||||||
|
return -ENODEV;
|
||||||
struct aic_usb_dev *usbdev = bus_if->bus_priv.usb;
|
struct aic_usb_dev *usbdev = bus_if->bus_priv.usb;
|
||||||
|
|
||||||
//printk("%s\n", __func__);
|
//printk("%s\n", __func__);
|
||||||
@@ -1703,6 +1712,10 @@ static int aicwf_usb_bus_txdata(struct device *dev, struct sk_buff *skb)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct aicwf_bus *bus_if = dev_get_drvdata(dev);
|
struct aicwf_bus *bus_if = dev_get_drvdata(dev);
|
||||||
|
/* Defense in depth (review #103): usb_bustx_thread is joined before
|
||||||
|
* drvdata is cleared; guard any other/premature caller. */
|
||||||
|
if (bus_if == NULL)
|
||||||
|
return -ENODEV;
|
||||||
struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb;
|
struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb;
|
||||||
struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)skb->data;
|
struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)skb->data;
|
||||||
struct rwnx_hw *rwnx_hw = usb_dev->rwnx_hw;
|
struct rwnx_hw *rwnx_hw = usb_dev->rwnx_hw;
|
||||||
@@ -1946,9 +1959,15 @@ void aicwf_usb_cancel_all_urbs(struct aic_usb_dev *usb_dev){
|
|||||||
static void aicwf_usb_bus_stop(struct device *dev)
|
static void aicwf_usb_bus_stop(struct device *dev)
|
||||||
{
|
{
|
||||||
struct aicwf_bus *bus_if = dev_get_drvdata(dev);
|
struct aicwf_bus *bus_if = dev_get_drvdata(dev);
|
||||||
struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb;
|
struct aic_usb_dev *usb_dev;
|
||||||
|
|
||||||
AICWFDBG(LOGINFO, "%s\r\n", __func__);
|
AICWFDBG(LOGINFO, "%s\r\n", __func__);
|
||||||
|
/* 正常时序下 aicwf_bus_init() 已 set_drvdata、且 aicwf_bus_deinit()
|
||||||
|
* 调到本函数时 drvdata 尚未清空(清空在 deinit 末尾),故此处应非空;
|
||||||
|
* 判空为纵深防御:覆盖 probe 早期失败(set_drvdata 之前)等异常来源。 */
|
||||||
|
if (bus_if == NULL)
|
||||||
|
return;
|
||||||
|
usb_dev = bus_if->bus_priv.usb;
|
||||||
if (usb_dev == NULL)
|
if (usb_dev == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -1666,9 +1666,16 @@ static int rwnx_close(struct net_device *dev)
|
|||||||
rwnx_ipc_tx_drain(rwnx_hw);
|
rwnx_ipc_tx_drain(rwnx_hw);
|
||||||
#else
|
#else
|
||||||
#if defined(AICWF_USB_SUPPORT)
|
#if defined(AICWF_USB_SUPPORT)
|
||||||
if (usbdev->bus_if->state != BUS_DOWN_ST && usbdev->state != USB_DOWN_ST)
|
/* 002 在 deinit 时摘 drvdata,disconnect→close 时序下本函数读到
|
||||||
|
* usbdev=NULL:实测断开在此裸解引用 usbdev->bus_if 崩溃
|
||||||
|
* (rwnx_close 偏移处 reloc=rwnx_send_reset,CR2=0x8)。
|
||||||
|
* 上游 usbdev 为悬挂非空、此条件求值为假而侥幸跳过——本判空
|
||||||
|
* 对两种情形给出同一语义:bus 已断 → 跳过 reset/重配。 */
|
||||||
|
if (usbdev != NULL && usbdev->bus_if != NULL &&
|
||||||
|
usbdev->bus_if->state != BUS_DOWN_ST && usbdev->state != USB_DOWN_ST)
|
||||||
#else
|
#else
|
||||||
if (sdiodev->bus_if->state != BUS_DOWN_ST)
|
if (sdiodev != NULL && sdiodev->bus_if != NULL &&
|
||||||
|
sdiodev->bus_if->state != BUS_DOWN_ST)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
rwnx_send_reset(rwnx_hw);
|
rwnx_send_reset(rwnx_hw);
|
||||||
|
|||||||
Reference in new issue
Block a user