X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsched%2Fsch_api.c;h=5da7b73126426a7b00188ebb93b854cb90914210;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=1f9bf9d0834cf0404bad6396453ba350efad84cb;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 1f9bf9d08..5da7b7312 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -371,6 +371,8 @@ int qdisc_graft(struct net_device *dev, struct Qdisc *parent, u32 classid, unsigned long cl = cops->get(parent, classid); if (cl) { err = cops->graft(parent, cl, new, old); + if (new) + new->parent = classid; cops->put(parent, cl); } } @@ -389,7 +391,8 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) { int err; struct rtattr *kind = tca[TCA_KIND-1]; - struct Qdisc *sch = NULL; + void *p = NULL; + struct Qdisc *sch; struct Qdisc_ops *ops; int size; @@ -406,21 +409,22 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) err = -EINVAL; if (ops == NULL) goto err_out; - - size = sizeof(*sch) + ops->priv_size; - - sch = kmalloc(size, GFP_KERNEL); - err = -ENOBUFS; - if (!sch) + err = -EBUSY; + if (!try_module_get(ops->owner)) goto err_out; - /* Grrr... Resolve race condition with module unload */ - - err = -EINVAL; - if (ops != qdisc_lookup_ops(kind)) - goto err_out; + /* ensure that the Qdisc and the private data are 32-byte aligned */ + size = ((sizeof(*sch) + QDISC_ALIGN_CONST) & ~QDISC_ALIGN_CONST); + size += ops->priv_size + QDISC_ALIGN_CONST; - memset(sch, 0, size); + p = kmalloc(size, GFP_KERNEL); + err = -ENOBUFS; + if (!p) + goto err_out2; + memset(p, 0, size); + sch = (struct Qdisc *)(((unsigned long)p + QDISC_ALIGN_CONST) + & ~QDISC_ALIGN_CONST); + sch->padded = (char *)sch - (char *)p; INIT_LIST_HEAD(&sch->list); skb_queue_head_init(&sch->q); @@ -439,7 +443,7 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) handle = qdisc_alloc_handle(dev); err = -ENOMEM; if (handle == 0) - goto err_out; + goto err_out3; } if (handle == TC_H_INGRESS) @@ -447,10 +451,6 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) else sch->handle = handle; - err = -EBUSY; - if (!try_module_get(ops->owner)) - goto err_out; - /* enqueue is accessed locklessly - make sure it's visible * before we set a netdevice's qdisc pointer to sch */ smp_wmb(); @@ -466,12 +466,14 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) #endif return sch; } +err_out3: + dev_put(dev); +err_out2: module_put(ops->owner); - err_out: *errp = err; - if (sch) - kfree(sch); + if (p) + kfree(p); return NULL; } @@ -821,7 +823,7 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) q_idx++; continue; } - if (tc_fill_qdisc(skb, q, 0, NETLINK_CB(cb->skb).pid, + if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) { read_unlock_bh(&qdisc_tree_lock); goto done;