spinlock_irqsave с тупиком - PullRequest
       15

spinlock_irqsave с тупиком

4 голосов
/ 24 августа 2011

Я написал модуль ядра, который выполняет nf_register_hook и использует механизм символьных устройств для передачи захваченных пакетов в пространство пользователя с перехватом чтения устройства. Я использую глобальный буфер и переменные размера буфера, поэтому мне нужно заблокировать его, когда приходит новый пакет или пользователь читает мое устройство. Я использовал splinlock_irqsave и spin_unlock_irqrestore (& locker, flags), но мой модуль зашел в тупик и система зависла.

unsigned int main_hook(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int(*okfn)(struct sk_buff*)) {
unsigned long flags;
spin_lock_irqsave(&locker,flags);
...
spin_unlock_irqrestore(&locker,flags);
}

ssize_t sniffer_dev_read(struct file *filep, char *buff, size_t count, loff_t *offp) {
spin_lock_irqsave(&locker,flags);
...
spin_unlock_irqrestore(&locker,flags);
}

main_hook is registered in nf_register_hook()
sniffer_dev_read is registered in register_chrdev

когда пользователь читает с устройства, система переходит в тупик. идеи? или может быть сохранение / восстановление irq несовместимо с считыванием устройства ловушки / символа netfiler, и я должен использовать специальную блокировку здесь?

Ответы [ 3 ]

5 голосов
/ 24 августа 2011

Во-первых, вам следует перекомпилировать ядро ​​с включенными параметрами отладки блокировки и повторить попытку.Они могут помочь указать причину.

Существует несколько возможных причин тупика в spin_lock_irqsave.Это может быть рекурсивная блокировка (то есть вы пытаетесь снова вызвать spin_lock_ * в той части кода, в которой заблокирована спин-блокировка).Может случиться так, что вы спите с заблокированной спин-блокировкой (не делайте этого никогда - для каждой функции, которую вы вызываете с удерживаемой блокировкой, вы должны знать, может ли она спать или нет).Это может быть тупик AB / BA (одна часть кода сначала блокирует A, а затем B; другая часть сначала блокирует B, а затем A; если первая часть заблокирована A, но не B, а вторая часть заблокирована B, но не A, у вас естьтупиковая).И так далее.Параметры отладки блокировки могут обнаружить и предупредить вас о многих из них.

Поскольку блокируемый объект является «глобальным буфером и переменными размера буфера», попробуйте уменьшить заблокированную область до минимума.Вместо того, чтобы блокировать в верхней части функции и разблокировать в конце, делайте как можно больше за пределами блокировки и блокируйте только при манипулировании буфером.В идеале, заблокированный раздел должен быть всего лишь несколькими инструкциями без вызовов функций.В этом случае гораздо труднее зайти в тупик.


Теперь, когда я сказал все это, моя попытка психической отладки (то есть угадывание, где проблема): вы вызываете copy_to_user (который может спать) сспин-замок удерживается.

1 голос
/ 24 августа 2011

Я полагаю, что у вас, возможно, есть некоторый простой программный сбой (например, попытка определить значение NULL и т. Д.), Но поскольку spin_lock_irqsave отключает прерывания, при переходе в этот режим исключения вы отключаете прерывания, поэтому вся машина блокируется.

Обратите внимание, что поскольку ваш NF-хук работает в нижней половине контекста, вам не нужно отключать прерывания - только нижние половины. Это облегчит отладку.

1 голос
/ 24 августа 2011

Вы не должны использовать спин-блокировки для блокировки ресурса, который можно использовать на разных уровнях контекста. Он занят - блокирует процессор, на котором он заблокирован.

main_hook вызывается из прерывания / нижнего контекста? Если это так, вы можете использовать work_queues, чтобы "job" (memcpy ...) выполнялся с более низким приоритетом. Как правило, вы должны делать как можно меньше внутри спинлока.

...