diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index a8dcb16c27ac6f41e8b9f534eec43c527d32fc8a..cb9c6f1a9569a92c07a55f5ec7d25c49978dc987 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -99,6 +99,8 @@ struct Qdisc { * for 32-bit kernel. */ struct rcu_head rcu; + /* onwer will use 4 Bytes, and the space is enough.*/ + int owner; #endif /* * For performance sake on SMP, we put highly modified fields at the end diff --git a/net/core/dev.c b/net/core/dev.c index a9aca8971a59ea83c840478462b6caf100d133af..f570d33b3bc7e223d226f3acf6ed84c20d718487 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3472,6 +3472,10 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, return rc; } + if (unlikely(READ_ONCE(q->owner) == smp_processor_id())) { + kfree_skb(skb); + return NET_XMIT_DROP; + } /* * Heuristic to force contended enqueues to serialize on a * separate lock before trying to get qdisc main lock. @@ -3507,7 +3511,9 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, qdisc_run_end(q); rc = NET_XMIT_SUCCESS; } else { + WRITE_ONCE(q->owner, smp_processor_id()); rc = q->enqueue(skb, q, &to_free) & NET_XMIT_MASK; + WRITE_ONCE(q->owner, -1); if (qdisc_run_begin(q)) { if (unlikely(contended)) { spin_unlock(&q->busylock); diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 64ae84bea587ad74328ca2ec660c4aaadea0a617..18b587cf9db88e0b5bf6d8e629b27e50204a2223 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -881,6 +881,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, sch->enqueue = ops->enqueue; sch->dequeue = ops->dequeue; sch->dev_queue = dev_queue; + sch->owner = -1; dev_hold(dev); refcount_set(&sch->refcnt, 1);