From cb3cb423a0f3c627639535e5d87977ae662d779f Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 13 May 2011 02:44:02 +0000 Subject: caif: Add ref-count to framing layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce Per-cpu reference for lower part of CAIF Stack. Before freeing payload is disabled, synchronize_rcu() is called, and then ref-count verified to be zero. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller --- net/caif/cfcnfg.c | 9 ++++++++- net/caif/cffrml.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) (limited to 'net/caif') diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index 7892cc084e27..3f4f31fca2c1 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -519,6 +519,13 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) caif_assert(phy_layer->id == phyid); caif_assert(phyinfo->frm_layer->id == phyid); + /* Fail if reference count is not zero */ + if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) { + pr_info("Wait for device inuse\n"); + mutex_unlock(&cnfg->lock); + return -EAGAIN; + } + list_del_rcu(&phyinfo->node); synchronize_rcu(); @@ -537,7 +544,7 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) if (phyinfo->phy_layer != frml_dn) kfree(frml_dn); - kfree(frml); + cffrml_free(frml); kfree(phyinfo); mutex_unlock(&cnfg->lock); diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c index f4b88924f83a..4f4f756c49ac 100644 --- a/net/caif/cffrml.c +++ b/net/caif/cffrml.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ struct cffrml { struct cflayer layer; bool dofcs; /* !< FCS active */ + int __percpu *pcpu_refcnt; }; static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt); @@ -31,12 +33,19 @@ static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, static u32 cffrml_rcv_error; static u32 cffrml_rcv_checsum_error; struct cflayer *cffrml_create(u16 phyid, bool use_fcs) + { struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC); if (!this) { pr_warn("Out of memory\n"); return NULL; } + this->pcpu_refcnt = alloc_percpu(int); + if (this->pcpu_refcnt == NULL) { + kfree(this); + return NULL; + } + caif_assert(offsetof(struct cffrml, layer) == 0); memset(this, 0, sizeof(struct cflayer)); @@ -49,6 +58,13 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs) return (struct cflayer *) this; } +void cffrml_free(struct cflayer *layer) +{ + struct cffrml *this = container_obj(layer); + free_percpu(this->pcpu_refcnt); + kfree(layer); +} + void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up) { this->up = up; @@ -148,8 +164,23 @@ static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, void cffrml_put(struct cflayer *layr) { + struct cffrml *this = container_obj(layr); + if (layr != NULL && this->pcpu_refcnt != NULL) + irqsafe_cpu_dec(*this->pcpu_refcnt); } void cffrml_hold(struct cflayer *layr) { + struct cffrml *this = container_obj(layr); + if (layr != NULL && this->pcpu_refcnt != NULL) + irqsafe_cpu_inc(*this->pcpu_refcnt); +} + +int cffrml_refcnt_read(struct cflayer *layr) +{ + int i, refcnt = 0; + struct cffrml *this = container_obj(layr); + for_each_possible_cpu(i) + refcnt += *per_cpu_ptr(this->pcpu_refcnt, i); + return refcnt; } -- cgit v1.2.1