Pull to refresh

Comments 12

Спасибо, весьма познавательно. Пожалуйста, пишите еще статей о ядре Linux. Материалов решительно не хватает!
А в чем собственно суть ошибки? Почему сокет не должен был быть захвачен в tcp_tasklet_func и как это пофиксить, если это баг в ядре?
Конкретно в том случае проблема была в том, что нарушалась локальность обработки данных. Сокет, а вместе с ним и сетевое соединение, обслуживалось разными CPU. С точки зрения производительности на SMP-системах это плохой вариант, т.к. страдают кеши, возникают кросс-блокировки между ядрами.
Хм. А по списку «живых» процессов не было очевидно, кто зохавал спинлок? Или соответствующий процесс забирал спинлок и забывал отдать?
Могу поделиться «фильтром процессов» для крэша — оно выкидывает спящие и консольные процессы, и объединяет одинаковые стектрейсы.
Не совсем понял как анализ процессов может помочь. Сеть в soft-IRQ работает, это ядерный контекст, там понятия current-процесса не существует.

По поводу фильтра — делитесь, конечно.
Мнда, мне ещё копать и копать ядро — про тасклеты читал, но вспомнил только сейчас. Пошел перечитывать https://habrahabr.ru/company/embox/blog/244071/ 8-\

Я исходил из предположения, что спинлок должен быстро отдаваться, а если он не отдаётся быстро — то в стеке одного из «рабочих тредов/тасков» будет функция, которая и забрала спинлок. Ну и если в этот момент сделать BUG(), то при анализе работающих процессов должно быть очевидно, кто этот спинлок держит.

Скрипт тут: https://gist.github.com/win32asm/96dca779362bbd04a1730b109e452fce
Мне очень помогает при дебаге ядерного модуля. 8-)
то в стеке одного из «рабочих тредов/тасков» будет функция, которая и забрала спинлок

Нет, это не верно. Спинлок в упрощённом варианте это что-то типа lock=1 для захвата и lock=0 для освобождения. То есть захват/освобождение — это просто смена состояний объекта. Соответствующие функции скорее-всего inline, поэтому следов в стеке они не оставляют, да и анализ стека выше стекового указателя — это не правильно, там будет мусор.

ну да, вызовов собственно spin_lock*() в трейсах не будет, но сам спинлок будет «кривой» (верхнее слово не равно нижнему), и обычно (иногда?) по «верхней» функции в трейсе можно догадаться, не могла ли именно эта фн его забрать.
Если работа со спинлоком «разнесена», как в iget_locked() / unlock_new_inode(), то приходится смотреть ещё на пару уровней «в ширину». Но КМК хорошим стилем является отпускать спинлок в той же фн, где он взят.

Не, ну трейсы безусловно помогают. Иногда достаточно сделать WARN_ON(1) чтобы понять что происходит :)

Расскажите, пожалуйста, как вы программируете и дебажите ядро поподробнее. Вся разработка идет через QEMU или с реальным железом тоже?

QEMU позволяет безболезненно ронять систему по много раз + собирать креш-дампы. В остальном — основной метод это отладочная печать через printk… Несколько раз пользовался kgdb, но он нужен в редких случаях, даже сейчас сходу не скажу в каких :)

Sign up to leave a comment.

Articles