--- linux-2.6/net/sched/sch_api.c.orig 2005-03-29 01:20:18.000000000 +0300 +++ linux-2.6/net/sched/sch_api.c 2005-03-31 22:44:41.000000000 +0300 @@ -406,11 +406,29 @@ 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. + * We replay the request because the device may + * go away in the mean time. + */ + rtnl_unlock(); request_module("sch_%s", name); + rtnl_lock(); ops = qdisc_lookup_ops(kind); + if (ops != NULL) { + /* We will try again qdisc_lookup_ops, + * so don't keep a reference. + */ + module_put(ops->owner); + err = -EAGAIN; + goto err_out; + } } } #endif @@ -606,14 +624,20 @@ 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: + /* Reinit, just in case something touches this. */ + 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 +731,11 @@ 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) + goto replay; return err; + } graft: if (1) {