We liberate any dangling gso_skb during qdisc destruction.
It really only matters for the root qdisc. But when qdiscs
can be shared by multiple netdev_queue objects, we can't
have the gso_skb in the netdev_queue any more.
Signed-off-by: David S. Miller <davem@davemloft.net>
struct net_device *dev;
struct Qdisc *qdisc;
unsigned long state;
struct net_device *dev;
struct Qdisc *qdisc;
unsigned long state;
- struct sk_buff *gso_skb;
spinlock_t _xmit_lock;
int xmit_lock_owner;
struct Qdisc *qdisc_sleeping;
spinlock_t _xmit_lock;
int xmit_lock_owner;
struct Qdisc *qdisc_sleeping;
u32 handle;
u32 parent;
atomic_t refcnt;
u32 handle;
u32 parent;
atomic_t refcnt;
+ struct sk_buff *gso_skb;
struct sk_buff_head q;
struct netdev_queue *dev_queue;
struct list_head list;
struct sk_buff_head q;
struct netdev_queue *dev_queue;
struct list_head list;
struct Qdisc *q)
{
if (unlikely(skb->next))
struct Qdisc *q)
{
if (unlikely(skb->next))
- dev_queue->gso_skb = skb;
else
q->ops->requeue(skb, q);
else
q->ops->requeue(skb, q);
-static inline struct sk_buff *dequeue_skb(struct netdev_queue *dev_queue,
- struct Qdisc *q)
+static inline struct sk_buff *dequeue_skb(struct Qdisc *q)
- if ((skb = dev_queue->gso_skb))
- dev_queue->gso_skb = NULL;
+ if ((skb = q->gso_skb))
+ q->gso_skb = NULL;
else
skb = q->dequeue(q);
else
skb = q->dequeue(q);
struct sk_buff *skb;
/* Dequeue packet */
struct sk_buff *skb;
/* Dequeue packet */
- if (unlikely((skb = dequeue_skb(txq, q)) == NULL))
+ if (unlikely((skb = dequeue_skb(q)) == NULL))
/* And release queue */
spin_unlock(&txq->lock);
/* And release queue */
spin_unlock(&txq->lock);
void *_qdisc_default)
{
struct Qdisc *qdisc_default = _qdisc_default;
void *_qdisc_default)
{
struct Qdisc *qdisc_default = _qdisc_default;
+ struct sk_buff *skb = NULL;
spin_lock_bh(&dev_queue->lock);
spin_lock_bh(&dev_queue->lock);
if (qdisc) {
dev_queue->qdisc = qdisc_default;
qdisc_reset(qdisc);
if (qdisc) {
dev_queue->qdisc = qdisc_default;
qdisc_reset(qdisc);
+
+ skb = qdisc->gso_skb;
+ qdisc->gso_skb = NULL;
- skb = dev_queue->gso_skb;
- dev_queue->gso_skb = NULL;
spin_unlock_bh(&dev_queue->lock);
spin_unlock_bh(&dev_queue->lock);