On 12/18/2017 06:20 PM, Cong Wang wrote: > On Mon, Dec 18, 2017 at 5:25 PM, John Fastabend > <john.fastab...@gmail.com> wrote: >> On 12/18/2017 02:34 PM, Cong Wang wrote: >>> First, the check of &q->ring.queue against NULL is wrong, it >>> is always false. We should check the value rather than the address. >>> >> >> Thanks. >> >>> Secondly, we need the same check in pfifo_fast_reset() too, >>> as both ->reset() and ->destroy() are called in qdisc_destroy(). >>> >> >> not that it hurts to have the check here, but if init fails >> in qdisc_create it seems only ->destroy() is called without >> a ->reset(). >> >> Is there another path for init() to fail that I'm missing. > > Pretty sure ->reset() is called in qdisc_destroy() and also before > ->destroy(): >
Except, the failed init path does not call qdisc_destroy. static struct Qdisc *qdisc_create(struct net_device *dev, [...] if (ops->init) { err = ops->init(sch, tca[TCA_OPTIONS]); if (err != 0) goto err_out5; } [...] err_out5: /* ops->init() failed, we call ->destroy() like qdisc_create_dflt() */ if (ops->destroy) ops->destroy(sch); err_out3: dev_put(dev); kfree((char *) sch - sch->padded); err_out2: module_put(ops->owner); err_out: *errp = err; return NULL; [...] > > void qdisc_destroy(struct Qdisc *qdisc) > { > const struct Qdisc_ops *ops = qdisc->ops; > struct sk_buff *skb, *tmp; > > if (qdisc->flags & TCQ_F_BUILTIN || > !refcount_dec_and_test(&qdisc->refcnt)) > return; > > #ifdef CONFIG_NET_SCHED > qdisc_hash_del(qdisc); > > qdisc_put_stab(rtnl_dereference(qdisc->stab)); > #endif > gen_kill_estimator(&qdisc->rate_est); > if (ops->reset) > ops->reset(qdisc); > if (ops->destroy) > ops->destroy(qdisc); >