我在Linux内核中观察到了以下代码模式,例如net/sched/act_api.c或许多其他地方:
rtnl_lock();
rtnetlink_rcv_msg(skb, ...);
replay:
ret = process_msg(skb);
...
/* try to obtain symbol which is in module. */
/* if fail, try to load the module, otherwise use the symbol */
a = get_symbol();
if (a == NULL) {
rtnl_unlock();
request_module();
rtnl_lock();
/* now verify that we can obtain symbols from requested module and return EAGAIN.*/
a = get_symbol();
module_put();
return -EAGAIN;
}
...
if (ret == -EAGAIN)
goto replay;
...
rtnl_unlock();在request_module成功之后,我们感兴趣的符号在内核内存空间中变得可用,我们可以使用它。然而,我不明白为什么返回EAGAIN并重新读取符号,为什么不直接在request_module()之后继续
发布于 2017-03-14 00:20:14
如果你看一下Linux内核中的current implementation,在第二次调用之后有一个注释,它相当于上面代码中的get_symbol() (它是tc_lookup_action_n()),它确切地解释了为什么:
rtnl_unlock();
request_module("act_%s", act_name);
rtnl_lock();
a_o = tc_lookup_action_n(act_name);
/* 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.
*/
if (a_o != NULL) {
err = -EAGAIN;
goto err_mod;
}即使可以请求和加载模块,因为为了加载模块而丢弃了信号量,这是一个可以休眠的操作(并且不是执行该函数的“标准方式”,该函数返回EAGAIN来通知它。
编辑以澄清:
如果我们查看添加新操作时的调用序列(这可能导致加载所需的模块),我们会得到这样的序列:tc_ctl_action() -> tcf_action_add() -> tcf_action_init() -> tcf_action_init_1()。现在,如果将EAGAIN错误“移回”到case RTM_NEWACTION:中的tc_ctl_action(),我们可以看到,使用EAGAIN ret值,会重复调用tcf_action_add。
https://stackoverflow.com/questions/42767329
复制相似问题