Модули ядра Linux: когда использовать try_module_get / module_put - PullRequest
16 голосов
/ 16 ноября 2009

Я читал LKMPG ( См. Раздел 4.1.4. Отмена регистрации устройства ), и мне было непонятно, когда использовать функции try_module_get / module_put. Некоторые из примеров LKMPG используют их, некоторые нет.

Чтобы добавить к путанице, try_module_get появляется 282 раза в 193 файлах в источнике 2.6.24, но в Драйверы устройств Linux (LDD3) и Основные драйверы устройств Linux они появляются даже не в одном примере кода.

Я подумал, что, возможно, они были привязаны к старому интерфейсу register_chrdev (заменен в 2.6 интерфейсом cdev), но они появляются только вместе в одном и том же файле 8 раз:

find -type f -name *.c | xargs grep -l try_module_get | sort -u | xargs grep -l register_chrdev | sort -u | grep -c .

Так когда уместно использовать эти функции и связаны ли они с использованием определенного интерфейса или набора обстоятельств?

Редактировать

Я загрузил пример sched.c из LKMPG и попробовал следующий эксперимент:

anon@anon:~/kernel-source/lkmpg/2.6.24$ tail /proc/sched -f &
Timer called 5041 times so far
[1] 14594

anon@anon:~$ lsmod | grep sched
sched                   2868  1 

anon@anon:~$ sudo rmmod sched
ERROR: Module sched is in use

Это наводит меня на мысль, что ядро ​​теперь ведет собственный учет, а получение / сдача может быть устаревшим. Кто-нибудь может это проверить?

1 Ответ

17 голосов
/ 21 мая 2011

Вы по сути никогда не должны использовать try_module_get (THIS_MODULE); почти все такие применения небезопасны, поскольку, если вы уже находитесь в своем модуле, слишком поздно увеличить счетчик ссылок - всегда будет (маленькое) окно, в котором вы выполняете код в своем модуле, но не увеличивали ссылку сосчитать. Если кто-то удаляет модуль именно в этом окне, то у вас плохая ситуация с запуском кода в незагруженном модуле.

Конкретный пример, который вы связали в LKMPG, где код выполняет try_module_get () в методе open (), будет обработан в современном ядре путем установки поля .owner в struct file_operations:

struct file_operations fops = {
        .owner = THIS_MODULE,
        .open = device_open,
        //...
};

это заставит код VFS принимать ссылку на модуль перед вызовом в него, что исключает небезопасное окно - либо try_module_get () будет успешным перед вызовом .open (), либо try_module_get () потерпит неудачу, и VFS никогда не вызовет модуль. В любом случае мы никогда не запускаем код из модуля, который уже был выгружен.

Единственное хорошее время для использования try_module_get () - это когда вы хотите получить ссылку на другой модуль, прежде чем вызывать его или использовать его каким-либо образом (например, как код открытия файла делает в Пример, который я объяснил выше). Существует несколько вариантов использования try_module_get (THIS_MODULE) в исходном коде ядра, но большинство из них, если не все, являются скрытыми ошибками, которые следует устранить.

Причина, по которой вы не смогли выгрузить пример расписания, заключается в том, что ваш

$ tail /proc/sched -f &

Команда сохраняет / proc / sched открытой, и из-за

        Our_Proc_File->owner = THIS_MODULE;

в коде sched.c открытие / proc / sched увеличивает счетчик ссылок модуля sched, который учитывает 1 ссылку, которую показывает ваш lsmod. После быстрой проверки остальной части кода, я думаю, что если вы выпустите / proc / sched, убив команду tail, вы сможете удалить модуль sched.

...