diff options
author | Prasanna S. Panchamukhi <prasannax.s.panchamukhi@intel.com> | 2010-04-13 19:35:58 -0400 |
---|---|---|
committer | Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | 2010-05-11 17:08:23 -0400 |
commit | d11a6e4495ee1fbb38b59bc88d49d050d3736929 (patch) | |
tree | 08afc7d7909dc451878f2ec04747071e2999e6e4 /drivers/net/wimax/i2400m/i2400m.h | |
parent | ded0fd62a8a7cb3b12bb007079bff2b858a12d2b (diff) |
wimax i2400m: fix race condition while accessing rx_roq by using kref count
This patch fixes the race condition when one thread tries to destroy
the memory allocated for rx_roq, while another thread still happen
to access rx_roq.
Such a race condition occurs when i2400m-sdio kernel module gets
unloaded, destroying the memory allocated for rx_roq while rx_roq
is accessed by i2400m_rx_edata(), as explained below:
$thread1 $thread2
$ void i2400m_rx_edata() $
$Access rx_roq[] $
$roq = &i2400m->rx_roq[ro_cin] $
$ i2400m_roq_[reset/queue/update_ws] $
$ $ void i2400m_rx_release();
$ $kfree(rx->roq);
$ $rx->roq = NULL;
$Oops! rx_roq is NULL
This patch fixes the race condition using refcount approach.
Signed-off-by: Prasanna S. Panchamukhi <prasannax.s.panchamukhi@intel.com>
Diffstat (limited to 'drivers/net/wimax/i2400m/i2400m.h')
-rw-r--r-- | drivers/net/wimax/i2400m/i2400m.h | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 7a9c2c5b25cb..b8c7dbfead49 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h | |||
@@ -412,7 +412,7 @@ struct i2400m_barker_db; | |||
412 | * | 412 | * |
413 | * @tx_size_max: biggest TX message sent. | 413 | * @tx_size_max: biggest TX message sent. |
414 | * | 414 | * |
415 | * @rx_lock: spinlock to protect RX members | 415 | * @rx_lock: spinlock to protect RX members and rx_roq_refcount. |
416 | * | 416 | * |
417 | * @rx_pl_num: total number of payloads received | 417 | * @rx_pl_num: total number of payloads received |
418 | * | 418 | * |
@@ -436,6 +436,10 @@ struct i2400m_barker_db; | |||
436 | * delivered. Then the driver can release them to the host. See | 436 | * delivered. Then the driver can release them to the host. See |
437 | * drivers/net/i2400m/rx.c for details. | 437 | * drivers/net/i2400m/rx.c for details. |
438 | * | 438 | * |
439 | * @rx_roq_refcount: refcount rx_roq. This refcounts any access to | ||
440 | * rx_roq thus preventing rx_roq being destroyed when rx_roq | ||
441 | * is being accessed. rx_roq_refcount is protected by rx_lock. | ||
442 | * | ||
439 | * @rx_reports: reports received from the device that couldn't be | 443 | * @rx_reports: reports received from the device that couldn't be |
440 | * processed because the driver wasn't still ready; when ready, | 444 | * processed because the driver wasn't still ready; when ready, |
441 | * they are pulled from here and chewed. | 445 | * they are pulled from here and chewed. |
@@ -597,10 +601,12 @@ struct i2400m { | |||
597 | tx_num, tx_size_acc, tx_size_min, tx_size_max; | 601 | tx_num, tx_size_acc, tx_size_min, tx_size_max; |
598 | 602 | ||
599 | /* RX stuff */ | 603 | /* RX stuff */ |
600 | spinlock_t rx_lock; /* protect RX state */ | 604 | /* protect RX state and rx_roq_refcount */ |
605 | spinlock_t rx_lock; | ||
601 | unsigned rx_pl_num, rx_pl_max, rx_pl_min, | 606 | unsigned rx_pl_num, rx_pl_max, rx_pl_min, |
602 | rx_num, rx_size_acc, rx_size_min, rx_size_max; | 607 | rx_num, rx_size_acc, rx_size_min, rx_size_max; |
603 | struct i2400m_roq *rx_roq; /* not under rx_lock! */ | 608 | struct i2400m_roq *rx_roq; /* access is refcounted */ |
609 | struct kref rx_roq_refcount; /* refcount access to rx_roq */ | ||
604 | u8 src_mac_addr[ETH_HLEN]; | 610 | u8 src_mac_addr[ETH_HLEN]; |
605 | struct list_head rx_reports; /* under rx_lock! */ | 611 | struct list_head rx_reports; /* under rx_lock! */ |
606 | struct work_struct rx_report_ws; | 612 | struct work_struct rx_report_ws; |