Подтвердить что ты не робот

Модули ядра Linux: когда использовать try_module_get/module_put

Я читал 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 .

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

Edit

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

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

[email protected]:~$ lsmod | grep sched
sched                   2868  1 

[email protected]:~$ sudo rmmod sched
ERROR: Module sched is in use

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

4b9b3361

Ответ 1

Вам по существу никогда не придется использовать 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 open и из-за

        Our_Proc_File->owner = THIS_MODULE;

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