Commit 7d311304 authored by sjur.brandeland@stericsson.com's avatar sjur.brandeland@stericsson.com Committed by David S. Miller

caif: Stash away hijacked skb destructor and call it later

This patch adds functionality for avoiding orphaning SKB too early.
The original skb is stashed away and the original destructor is called
from the hi-jacked flow-on callback. If CAIF interface goes down and a
hi-jacked SKB exists, the original skb->destructor is restored.
Signed-off-by: default avatarSjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0e4c7d85
...@@ -36,6 +36,8 @@ struct caif_device_entry { ...@@ -36,6 +36,8 @@ struct caif_device_entry {
struct net_device *netdev; struct net_device *netdev;
int __percpu *pcpu_refcnt; int __percpu *pcpu_refcnt;
spinlock_t flow_lock; spinlock_t flow_lock;
struct sk_buff *xoff_skb;
void (*xoff_skb_dtor)(struct sk_buff *skb);
bool xoff; bool xoff;
}; };
...@@ -133,6 +135,7 @@ static struct caif_device_entry *caif_get(struct net_device *dev) ...@@ -133,6 +135,7 @@ static struct caif_device_entry *caif_get(struct net_device *dev)
void caif_flow_cb(struct sk_buff *skb) void caif_flow_cb(struct sk_buff *skb)
{ {
struct caif_device_entry *caifd; struct caif_device_entry *caifd;
void (*dtor)(struct sk_buff *skb) = NULL;
bool send_xoff; bool send_xoff;
WARN_ON(skb->dev == NULL); WARN_ON(skb->dev == NULL);
...@@ -145,8 +148,17 @@ void caif_flow_cb(struct sk_buff *skb) ...@@ -145,8 +148,17 @@ void caif_flow_cb(struct sk_buff *skb)
spin_lock_bh(&caifd->flow_lock); spin_lock_bh(&caifd->flow_lock);
send_xoff = caifd->xoff; send_xoff = caifd->xoff;
caifd->xoff = 0; caifd->xoff = 0;
if (!WARN_ON(caifd->xoff_skb_dtor == NULL)) {
WARN_ON(caifd->xoff_skb != skb);
dtor = caifd->xoff_skb_dtor;
caifd->xoff_skb = NULL;
caifd->xoff_skb_dtor = NULL;
}
spin_unlock_bh(&caifd->flow_lock); spin_unlock_bh(&caifd->flow_lock);
if (dtor)
dtor(skb);
if (send_xoff) if (send_xoff)
caifd->layer.up-> caifd->layer.up->
ctrlcmd(caifd->layer.up, ctrlcmd(caifd->layer.up,
...@@ -210,8 +222,10 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt) ...@@ -210,8 +222,10 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt)
netif_queue_stopped(caifd->netdev), netif_queue_stopped(caifd->netdev),
qlen, high); qlen, high);
caifd->xoff = 1; caifd->xoff = 1;
caifd->xoff_skb = skb;
caifd->xoff_skb_dtor = skb->destructor;
skb->destructor = caif_flow_cb;
spin_unlock_bh(&caifd->flow_lock); spin_unlock_bh(&caifd->flow_lock);
skb_orphan(skb);
caifd->layer.up->ctrlcmd(caifd->layer.up, caifd->layer.up->ctrlcmd(caifd->layer.up,
_CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND, _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND,
...@@ -420,6 +434,24 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, ...@@ -420,6 +434,24 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
caifd->layer.up->ctrlcmd(caifd->layer.up, caifd->layer.up->ctrlcmd(caifd->layer.up,
_CAIF_CTRLCMD_PHYIF_DOWN_IND, _CAIF_CTRLCMD_PHYIF_DOWN_IND,
caifd->layer.id); caifd->layer.id);
spin_lock_bh(&caifd->flow_lock);
/*
* Replace our xoff-destructor with original destructor.
* We trust that skb->destructor *always* is called before
* the skb reference is invalid. The hijacked SKB destructor
* takes the flow_lock so manipulating the skb->destructor here
* should be safe.
*/
if (caifd->xoff_skb_dtor != NULL && caifd->xoff_skb != NULL)
caifd->xoff_skb->destructor = caifd->xoff_skb_dtor;
caifd->xoff = 0;
caifd->xoff_skb_dtor = NULL;
caifd->xoff_skb = NULL;
spin_unlock_bh(&caifd->flow_lock);
caifd_put(caifd); caifd_put(caifd);
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment