diff options
author | Vinayak Pane <vpane@nvidia.com> | 2014-06-17 18:45:14 -0700 |
---|---|---|
committer | Mandar Padmawar <mpadmawar@nvidia.com> | 2014-07-10 02:05:15 -0700 |
commit | 9244bf2a676ccef4da4448f388db273072a1e52e (patch) | |
tree | 001a6d910de5ef00314aca2f8932fb815804353f | |
parent | 2d988b0dd9beaa29aa92d3194608f0da445085fc (diff) |
staging: ozwpan: protect oz_pd_destroy
oz_pd_destroy() is called mulitple times when network
down notifier gets triggered. Destroy workqueue is scheduled
from tasklet and also from oz_binding_remov function.
Protecting it by strictly scheduling workqueue only once.
Bug 1522180
Bug 1522708
Change-Id: I47c92a5e7ef1067d5dc4cdf67653a785eff34bca
Signed-off-by: Vinayak Pane <vpane@nvidia.com>
Reviewed-on: http://git-master/r/426904
(cherry picked from commit 2115acceab535b3b493519c23cb076045618482b)
Reviewed-on: http://git-master/r/435717
GVS: Gerrit_Virtual_Submit
Reviewed-by: Anshul Jain (SW) <anshulj@nvidia.com>
Tested-by: Anshul Jain (SW) <anshulj@nvidia.com>
-rw-r--r-- | drivers/staging/ozwpan/ozpd.c | 26 | ||||
-rw-r--r-- | drivers/staging/ozwpan/ozpd.h | 1 |
2 files changed, 23 insertions, 4 deletions
diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c index def50af78132..b3140fe26fc5 100644 --- a/drivers/staging/ozwpan/ozpd.c +++ b/drivers/staging/ozwpan/ozpd.c @@ -39,6 +39,7 @@ static void oz_def_app_term(void); static int oz_def_app_start(struct oz_pd *pd, int resume); static void oz_def_app_stop(struct oz_pd *pd, int pause); static void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt); +static void oz_pd_free(struct work_struct *work); /*------------------------------------------------------------------------------ * Counts the uncompleted isoc frames submitted to netcard. */ @@ -160,8 +161,12 @@ void oz_pd_get(struct oz_pd *pd) */ void oz_pd_put(struct oz_pd *pd) { - if (atomic_dec_and_test(&pd->ref_count)) - oz_pd_destroy(pd); + atomic_dec(&pd->ref_count); + + if (atomic_read(&pd->ref_count) > 0 || atomic_read(&pd->ref_count) < 0) + return; + + oz_pd_destroy(pd); } /*------------------------------------------------------------------------------ * Context: softirq-serialized @@ -197,6 +202,9 @@ struct oz_pd *oz_pd_alloc(const u8 *mac_addr) hrtimer_init(&pd->timeout, CLOCK_MONOTONIC, HRTIMER_MODE_REL); pd->heartbeat.function = oz_pd_heartbeat_event; pd->timeout.function = oz_pd_timeout_event; + atomic_set(&pd->pd_destroy_scheduled, 0); + memset(&pd->workitem, 0, sizeof(pd->workitem)); + INIT_WORK(&pd->workitem, oz_pd_free); } return pd; } @@ -249,6 +257,7 @@ static void oz_pd_free(struct work_struct *work) oz_trace_msg(M, "dev_put(%p)\n", pd->net_dev); dev_put(pd->net_dev); } + atomic_set(&pd->pd_destroy_scheduled, 0); kfree(pd); } @@ -260,13 +269,17 @@ void oz_pd_destroy(struct oz_pd *pd) { int ret; + if (atomic_read(&pd->pd_destroy_scheduled) > 0) { + pr_info("%s: not rescheduling oz_pd_free\n", __func__); + return; + } + atomic_inc(&pd->pd_destroy_scheduled); + if (hrtimer_active(&pd->timeout)) hrtimer_cancel(&pd->timeout); if (hrtimer_active(&pd->heartbeat)) hrtimer_cancel(&pd->heartbeat); - memset(&pd->workitem, 0, sizeof(pd->workitem)); - INIT_WORK(&pd->workitem, oz_pd_free); ret = schedule_work(&pd->workitem); if (!ret) pr_info("failed to schedule workitem\n"); @@ -578,6 +591,11 @@ static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f) { struct list_head *e; struct oz_elt_info *ei; + + if (f == NULL) { + pr_info("%s: oz_tx_frame is null\n", __func__); + return; + } e = f->elt_list.next; while (e != &f->elt_list) { ei = container_of(e, struct oz_elt_info, link); diff --git a/drivers/staging/ozwpan/ozpd.h b/drivers/staging/ozwpan/ozpd.h index 5f5e7241ff47..f21c830db564 100644 --- a/drivers/staging/ozwpan/ozpd.h +++ b/drivers/staging/ozwpan/ozpd.h @@ -110,6 +110,7 @@ struct oz_pd { unsigned long tasklet_sched; struct work_struct workitem; struct work_struct uevent_workitem; + atomic_t pd_destroy_scheduled; u8 up_audio_buf; }; |