On 2020/9/3 15:24, Eric Dumazet wrote:
> 
> 
> On 9/2/20 6:14 PM, Yunsheng Lin wrote:
> 
>>
>> It seems semantics for some_qdisc_is_busy() is changed, which does not only 
>> do
>> the checking, but also do the reseting?
> 
> Yes, obviously, we would have to rename to a better name.
> 
>>
>> Also, qdisc_reset() could be called multi times for the same qdisc if 
>> some_qdisc_is_busy()
>> return true multi times?
> 
> This should not matter, qdisc_reset() can be called multiple times,
> as we also call it from qdisc_destroy() anyway.

How about the below patch, which does not need to change the semantics
for some_qdisc_is_busy() and avoid calling qdisc_reset() multi times?


diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 265a61d..ce9031c 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -1131,24 +1131,7 @@ EXPORT_SYMBOL(dev_activate);

 static void qdisc_deactivate(struct Qdisc *qdisc)
 {
-       bool nolock = qdisc->flags & TCQ_F_NOLOCK;
-
-       if (qdisc->flags & TCQ_F_BUILTIN)
-               return;
-       if (test_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state))
-               return;
-
-       if (nolock)
-               spin_lock_bh(&qdisc->seqlock);
-       spin_lock_bh(qdisc_lock(qdisc));
-
        set_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state);
-
-       qdisc_reset(qdisc);
-
-       spin_unlock_bh(qdisc_lock(qdisc));
-       if (nolock)
-               spin_unlock_bh(&qdisc->seqlock);
 }

 static void dev_deactivate_queue(struct net_device *dev,
@@ -1165,6 +1148,33 @@ static void dev_deactivate_queue(struct net_device *dev,
        }
 }

+static void dev_reset_qdisc(struct net_device *dev)
+{
+       unsigned int i;
+
+       for (i = 0; i < dev->num_tx_queues; i++) {
+               struct netdev_queue *dev_queue;
+               struct Qdisc *q;
+               bool nolock;
+
+               dev_queue = netdev_get_tx_queue(dev, i);
+               q = dev_queue->qdisc_sleeping;
+               nolock = q->flags & TCQ_F_NOLOCK;
+
+               if (nolock)
+                       spin_lock_bh(&q->seqlock);
+
+               spin_lock_bh(qdisc_lock(q));
+
+               qdisc_reset(q);
+
+               spin_unlock_bh(qdisc_lock(q));
+
+               if (nolock)
+                       spin_unlock_bh(&q->seqlock);
+       }
+}
+
 static bool some_qdisc_is_busy(struct net_device *dev)
 {
        unsigned int i;
@@ -1219,6 +1229,9 @@ void dev_deactivate_many(struct list_head *head)
         */
        synchronize_net();

+       list_for_each_entry(dev, head, close_list)
+               dev_reset_qdisc(dev);
+
        /* Wait for outstanding qdisc_run calls. */
        list_for_each_entry(dev, head, close_list) {
                while (some_qdisc_is_busy(dev)) {



> 
> 

Reply via email to