Hi,
This simple test case
tc qdisc add dev eth0 root handle 1: htb
tc class add dev eth0 root classid 1: htb rate 1Gbit
tc class add dev eth0 parent 1: classid 1:1 htb rate 1Gbit
tc filter add dev eth0 parent 1: basic match 'cmp(u8 at 0 eq 0)' classid 1:1
fails with the following
RTNETLINK answers: No such file or directory
We have an error talking to the kernel
if em_cmp.ko is not loaded beforehand.
After that, lsmod shows that em_cmp.ko is loaded indeed, but its usage count
is -1 and an attempd to unload the module results in a "BUG at
kernel/module.c:752".
This has been broken pretty recently, I'm currently attempting a git bisect on
this.
--
Ignacy Gawędzki
R&D Engineer
Green Communications
In tcf_em_validate(), when calling tcf_em_lookup(), don't put the resulting
pointer directly into em->ops, if the function is to possibly return -EAGAIN
after module auto-loading. Otherwise, module_put() will be called by
tcf_em_tree_destroy() on em->ops->owner, while it has already been called by
tcf_em_validate() before return.
Signed-off-by: Ignacy Gawędzki <redacted>
---
net/sched/ematch.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
@@ -176,6 +176,7 @@ static int tcf_em_validate(struct tcf_proto *tp,{interr=-EINVAL;structtcf_ematch_hdr*em_hdr=nla_data(nla);+structtcf_ematch_ops*em_ops;intdata_len=nla_len(nla)-sizeof(*em_hdr);void*data=(void*)em_hdr+sizeof(*em_hdr);structnet*net=dev_net(qdisc_dev(tp->q));
@@ -213,27 +214,29 @@ static int tcf_em_validate(struct tcf_proto *tp,*here.Beaware,thedestroyfunctionassumesthatthe*moduleisheldiftheopsfieldisnonzero.*/-em->ops=tcf_em_lookup(em_hdr->kind);+em_ops=tcf_em_lookup(em_hdr->kind);-if(em->ops==NULL){+if(em_ops==NULL){err=-ENOENT;#ifdef CONFIG_MODULES__rtnl_unlock();request_module("ematch-kind-%u",em_hdr->kind);rtnl_lock();-em->ops=tcf_em_lookup(em_hdr->kind);-if(em->ops){+em_ops=tcf_em_lookup(em_hdr->kind);+if(em_ops){/* We dropped the RTNL mutex in order to*performthemoduleload.Tellthecaller*toreplaytherequest.*/-module_put(em->ops->owner);+module_put(em_ops->owner);err=-EAGAIN;}#endifgotoerrout;}+em->ops=em_ops;+/* ematch module provides expected length of data, so we*candoabasicsanitycheck.*/
From: Cong Wang <hidden> Date: 2015-02-16 18:36:07
On Mon, Feb 16, 2015 at 10:13 AM, Ignacy Gawędzki
[off-list ref] wrote:
In tcf_em_validate(), when calling tcf_em_lookup(), don't put the resulting
pointer directly into em->ops, if the function is to possibly return -EAGAIN
after module auto-loading. Otherwise, module_put() will be called by
tcf_em_tree_destroy() on em->ops->owner, while it has already been called by
tcf_em_validate() before return.
Or simply reset em->ops to NULL after module_put()?
On Mon, Feb 16, 2015 at 10:36:06AM -0800, thus spake Cong Wang:
On Mon, Feb 16, 2015 at 10:13 AM, Ignacy Gawędzki
[off-list ref] wrote:
quoted
In tcf_em_validate(), when calling tcf_em_lookup(), don't put the resulting
pointer directly into em->ops, if the function is to possibly return -EAGAIN
after module auto-loading. Otherwise, module_put() will be called by
tcf_em_tree_destroy() on em->ops->owner, while it has already been called by
tcf_em_validate() before return.
Or simply reset em->ops to NULL after module_put()?
Yeah, why not. I just got my inspiration from what's done in cls_api.c and
act_api.c. What do you think, should the same simplification be applied to
cls_api.c?
--
Ignacy Gawędzki
R&D Engineer
Green Communications
From: Cong Wang <hidden> Date: 2015-02-17 18:00:16
On Mon, Feb 16, 2015 at 10:50 AM, Ignacy Gawędzki
[off-list ref] wrote:
On Mon, Feb 16, 2015 at 10:36:06AM -0800, thus spake Cong Wang:
quoted
On Mon, Feb 16, 2015 at 10:13 AM, Ignacy Gawędzki
[off-list ref] wrote:
quoted
In tcf_em_validate(), when calling tcf_em_lookup(), don't put the resulting
pointer directly into em->ops, if the function is to possibly return -EAGAIN
after module auto-loading. Otherwise, module_put() will be called by
tcf_em_tree_destroy() on em->ops->owner, while it has already been called by
tcf_em_validate() before return.
Or simply reset em->ops to NULL after module_put()?
Yeah, why not. I just got my inspiration from what's done in cls_api.c and
act_api.c. What do you think, should the same simplification be applied to
cls_api.c?
I prefer the smaller change, we don't have to align with cls_api.c.
Yeah, you can always clean it up for net-next.
Thanks.
In tcf_em_validate(), after calling request_module() to load the
kind-specific module, set em->ops to NULL before returning -EAGAIN, so
that module_put() is not called again by tcf_em_tree_destroy().
Signed-off-by: Ignacy Gawędzki <redacted>
---
net/sched/ematch.c | 1 +
1 file changed, 1 insertion(+)
From: Cong Wang <hidden> Date: 2015-02-18 05:17:04
On Tue, Feb 17, 2015 at 11:15 AM, Ignacy Gawędzki
[off-list ref] wrote:
In tcf_em_validate(), after calling request_module() to load the
kind-specific module, set em->ops to NULL before returning -EAGAIN, so
that module_put() is not called again by tcf_em_tree_destroy().
Signed-off-by: Ignacy Gawędzki <redacted>
In tcf_em_validate(), after calling request_module() to load the
kind-specific module, set em->ops to NULL before returning -EAGAIN, so
that module_put() is not called again by tcf_em_tree_destroy().
Signed-off-by: Ignacy Gawędzki <redacted>