aboutsummaryrefslogtreecommitdiffstats
path: root/net/caif
diff options
context:
space:
mode:
authorsjur.brandeland@stericsson.com <sjur.brandeland@stericsson.com>2011-12-04 06:22:55 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-05 18:27:56 -0500
commit7d3113042823344dcc175b0ea00a83d0273c98a4 (patch)
tree7557851b0c2a3da774a36448cd78fedcc0958e6d /net/caif
parent0e4c7d85d5e522d5839bdc5745235428faf38d44 (diff)
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: Sjur Brændeland <sjur.brandeland@stericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/caif')
-rw-r--r--net/caif/caif_dev.c34
1 files changed, 33 insertions, 1 deletions
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
index 74c12734db74..9b298c14028d 100644
--- a/net/caif/caif_dev.c
+++ b/net/caif/caif_dev.c
@@ -36,6 +36,8 @@ struct caif_device_entry {
36 struct net_device *netdev; 36 struct net_device *netdev;
37 int __percpu *pcpu_refcnt; 37 int __percpu *pcpu_refcnt;
38 spinlock_t flow_lock; 38 spinlock_t flow_lock;
39 struct sk_buff *xoff_skb;
40 void (*xoff_skb_dtor)(struct sk_buff *skb);
39 bool xoff; 41 bool xoff;
40}; 42};
41 43
@@ -133,6 +135,7 @@ static struct caif_device_entry *caif_get(struct net_device *dev)
133void caif_flow_cb(struct sk_buff *skb) 135void caif_flow_cb(struct sk_buff *skb)
134{ 136{
135 struct caif_device_entry *caifd; 137 struct caif_device_entry *caifd;
138 void (*dtor)(struct sk_buff *skb) = NULL;
136 bool send_xoff; 139 bool send_xoff;
137 140
138 WARN_ON(skb->dev == NULL); 141 WARN_ON(skb->dev == NULL);
@@ -145,8 +148,17 @@ void caif_flow_cb(struct sk_buff *skb)
145 spin_lock_bh(&caifd->flow_lock); 148 spin_lock_bh(&caifd->flow_lock);
146 send_xoff = caifd->xoff; 149 send_xoff = caifd->xoff;
147 caifd->xoff = 0; 150 caifd->xoff = 0;
151 if (!WARN_ON(caifd->xoff_skb_dtor == NULL)) {
152 WARN_ON(caifd->xoff_skb != skb);
153 dtor = caifd->xoff_skb_dtor;
154 caifd->xoff_skb = NULL;
155 caifd->xoff_skb_dtor = NULL;
156 }
148 spin_unlock_bh(&caifd->flow_lock); 157 spin_unlock_bh(&caifd->flow_lock);
149 158
159 if (dtor)
160 dtor(skb);
161
150 if (send_xoff) 162 if (send_xoff)
151 caifd->layer.up-> 163 caifd->layer.up->
152 ctrlcmd(caifd->layer.up, 164 ctrlcmd(caifd->layer.up,
@@ -210,8 +222,10 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt)
210 netif_queue_stopped(caifd->netdev), 222 netif_queue_stopped(caifd->netdev),
211 qlen, high); 223 qlen, high);
212 caifd->xoff = 1; 224 caifd->xoff = 1;
225 caifd->xoff_skb = skb;
226 caifd->xoff_skb_dtor = skb->destructor;
227 skb->destructor = caif_flow_cb;
213 spin_unlock_bh(&caifd->flow_lock); 228 spin_unlock_bh(&caifd->flow_lock);
214 skb_orphan(skb);
215 229
216 caifd->layer.up->ctrlcmd(caifd->layer.up, 230 caifd->layer.up->ctrlcmd(caifd->layer.up,
217 _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND, 231 _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND,
@@ -420,6 +434,24 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
420 caifd->layer.up->ctrlcmd(caifd->layer.up, 434 caifd->layer.up->ctrlcmd(caifd->layer.up,
421 _CAIF_CTRLCMD_PHYIF_DOWN_IND, 435 _CAIF_CTRLCMD_PHYIF_DOWN_IND,
422 caifd->layer.id); 436 caifd->layer.id);
437
438 spin_lock_bh(&caifd->flow_lock);
439
440 /*
441 * Replace our xoff-destructor with original destructor.
442 * We trust that skb->destructor *always* is called before
443 * the skb reference is invalid. The hijacked SKB destructor
444 * takes the flow_lock so manipulating the skb->destructor here
445 * should be safe.
446 */
447 if (caifd->xoff_skb_dtor != NULL && caifd->xoff_skb != NULL)
448 caifd->xoff_skb->destructor = caifd->xoff_skb_dtor;
449
450 caifd->xoff = 0;
451 caifd->xoff_skb_dtor = NULL;
452 caifd->xoff_skb = NULL;
453
454 spin_unlock_bh(&caifd->flow_lock);
423 caifd_put(caifd); 455 caifd_put(caifd);
424 break; 456 break;
425 457