X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsched%2Fsch_api.c;h=07977f8f2679b30cf93808f93fbbcce3c3dbc776;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=10714716d4c7bfa32f284fee06762a46f4c1b73b;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 10714716d..07977f8f2 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -406,11 +406,29 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) 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 *skb, struct nlmsghdr *n, void *arg) 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) { @@ -1262,6 +1289,7 @@ static int __init pktsched_init(void) subsys_initcall(pktsched_init); +EXPORT_SYMBOL(qdisc_lookup); EXPORT_SYMBOL(qdisc_get_rtab); EXPORT_SYMBOL(qdisc_put_rtab); EXPORT_SYMBOL(register_qdisc);