--- linux-2.6.11.6/net/sched/sch_api.c.orig 2005-03-29 01:20:18.000000000 +0300 +++ linux-2.6.11.6/net/sched/sch_api.c 2005-03-29 01:40:57.000000000 +0300 @@ -406,11 +406,24 @@ qdisc_create(struct net_device *dev, u32 ops = qdisc_lookup_ops(kind); #ifdef CONFIG_KMOD - if (ops==NULL && tca[TCA_KIND-1] != NULL) { + if (ops==NULL && kind != NULL) { char name[IFNAMSIZ]; if (rtattr_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) { + /* We dropped the RTNL semaphore in order to + * perform the module load. So, even if we + * succeeded in loading the module we have to + * tell the caller to replay the request. We + * indicate this using -EAGAIN. + */ + rtnl_unlock(); request_module("sch_%s", name); + rtnl_lock(); ops = qdisc_lookup_ops(kind); + if (ops != NULL) { + module_put(ops->owner); + err = -EAGAIN; + goto err_out; + } } } #endif @@ -606,14 +619,19 @@ static int tc_get_qdisc(struct sk_buff * static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct tcmsg *tcm = NLMSG_DATA(n); - struct rtattr **tca = arg; + struct tcmsg *tcm; + struct rtattr **tca; struct net_device *dev; - u32 clid = tcm->tcm_parent; - struct Qdisc *q = NULL; - struct Qdisc *p = NULL; + u32 clid; + struct Qdisc *q, *p; int err; + replay: + tcm = NLMSG_DATA(n); + tca = arg; + clid = tcm->tcm_parent; + q = p = NULL; + if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) return -ENODEV; @@ -707,8 +725,14 @@ create_n_graft: q = qdisc_create(dev, tcm->tcm_parent, tca, &err); else q = qdisc_create(dev, tcm->tcm_handle, tca, &err); - if (q == NULL) + if (q == NULL) { + if (err == -EAGAIN) { + /* Replay the request */ + dev_put(dev); + goto replay; + } return err; + } graft: if (1) {