summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVinayak Pane <vpane@nvidia.com>2014-06-17 18:45:14 -0700
committerMandar Padmawar <mpadmawar@nvidia.com>2014-07-10 02:05:15 -0700
commit9244bf2a676ccef4da4448f388db273072a1e52e (patch)
tree001a6d910de5ef00314aca2f8932fb815804353f
parent2d988b0dd9beaa29aa92d3194608f0da445085fc (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.c26
-rw-r--r--drivers/staging/ozwpan/ozpd.h1
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;
};