поведение модуля разблокировки и запроса мьютекса ()
Я наблюдал следующий шаблон кода в ядре 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()
?
1 ответ:
Если вы посмотрите на текущую реализацию в ядре Linux, сразу после второго вызова есть комментарий, эквивалентный
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
обратно вtc_ctl_action()
вcase RTM_NEWACTION:
, мы увидим, что при значенииEAGAIN
ret вызовtcf_action_add
повторяется.