Как теперь процессить kernel crash и bug report? Или несколько слов о разнице между интересным и удивительным

    Широко известен исторический анекдот о том, что царица Екатерина II писала простое русское слово из 3 букв с 4 ошибками. Куда менее известно, что эта ошибка вовсе не уникальна. Дети европейских экспатов, изучающие русский язык, запросто могут в диктанте слово “ёжик” написать как Й-О-Ш-Е-Г.

    И ведь дети отнюдь не безграмотные, просто они уже привыкли к своему родному языку. Услышанное слово разбивается на буквы на родном языке, затем побуквенно же транслируется на русский и записывается чужими “прикольными” иероглифами. Этот алгоритм хотя и неоптимальный, но, в принципе, рабочий. На каждом его этапе срабатывает испорченный телеграф, что приводит к закономерным искажениям оригинала. Так что, да, интересно, но, если вдуматься, ничего удивительного. И о подобной ситуации относительно новых ядер Linux я расскажу в этом посте.

    Автор этих строк много лет пилит гирю OpenVz linux kernel maintenance. OpenVz сейчас потихоньку переезжает с ядра RHEL7 на RHEL8. Ядро в Red Hat за 5 лет сильно изменилось, поэтому мы очередной раз пересматриваем наши старые патчи и думаем, что с ними делать: перетащить как есть, переделать получше или дропнуть за неактуальностью.

    В рамках этой большой задачи я разбирался с memcg accounting. OpenVZ аккаунтит различные kernel objects практически с самого рождения — с v2.2.x ядер далекого 2001 года. Зачем и почему мы решили аккаунтить тот или иной объект, сейчас сходу понять довольно затруднительно, приходится поднимать историю по старым багам и коммитам.

    В стародавние времена мы использовали свою собственную систему accounting, так называемые user beancounters. Там была пара десятков разных параметров, и правильно их настраивать было затруднительно для админов. В upstream эту подсистему тоже принимать не особо хотели, для них приходилось изобретать namespaces и cgroups, а для своих ядер — скрещивать ежа, ужа и трепетную лань.

    Пересмотрев наш memcg accounting из Virtuozzo Hybrid Server 7.5, я большую их часть перетащил в Virtuozzo Hybrid Server 8, посмотрел, что из этого до сих пор отсутствует в последнем upstream и подготовил соответствующий патчсет. Если кому интересно, кстати говоря, вот он.

    Перед отсылкой в upstream изменения полагается хотя бы минимально проверить. Я скомпилил свое ядро, взгромоздил его на свою тестовую VM с Fedora Rawhide и давай его по-всякому тестить.

    Чтобы разобраться в деталях memcg аккаунтинга в ядро в свое время засунули per-memcg sysfs файлик memory.kmem.slabinfo. В нем показывается количество тех или иных SLAB объектов, которые нашлись в соответствующей memory cgroup, нечто типа обычного /proc/slabinfo. В новых upstream ядрах из соответствующие файлики тоже были, однако из них почему то вообще ничего не вычитывалось. Я посмотрел на своем ядре, посмотрел на оригинальном ядре Fedora — то же самое: файл есть, контента нет.

    Стал разбираться. Выяснилось, что с полгода назад memcg подсистему очередной раз переделали, но с выводом контента в memory.kmem.slabinfo возникли сложности. Поэтому вывод решили обнулить, а для тех, кому он все таки интересен, в ядро закоммитили drgn скрипт tools/cgroup/memcg_slabinfo.py.

    Обычно с ядром разбираются посредством crash — но на живом ядре это довольно тяжелый способ. сrash долго стартует, потребляет кучу ресурсов, и на сильно загруженной production node такое делать стремно — можно запросто разбудить OOM-killerа. Можно пытаться заюзать ftrace, perf или systemtap — но у каждого из них свои недостатки и неудобства.

    drgn — их легковесная альтернатива. Позволяет добраться до внутренностей ядра, и удобным образом переходить по ссылкам структур ядра. Много говорить про него не буду, кому интересно -- посмотрите-покрутите самостоятельно. В целом, по-моему, удобно, впечатления от использования положительные, рекомендую. Исходник здесь: https://github.com/osandov/drgn.

    Закоммиченный полгода назад скрипт на новом ядре уже не работал, структуры ядра за это время уже успели несколько раз поменяться. Неудивительно, на это обречен любой внешний скрипт или out-ouf-tree модуль. Однако благодаря простоте drgn исправить скрипт оказалось несложным.

    Я проверил исправленным скриптом свое ядро со своими фиксами accounting — все отработало нормально. Потом решил, что стоит посмотреть на то, как вело себя непропатченное ядро. Откатывать свои патчи и перекомпилировать свое ядро заново мне было лениво. Тем более, что у меня уже было другое upstream ядро — от Fedora Rawhide aka fc35. Я специально проапдейтился, загрузил самое последнее ядро, запускаю скрипт — а он не работает. И проблема похоже даже не в самом скрипте: drgn сам по себе не запускается.

     [root@localhost test]# rpm -q drgn

    drgn-0.0.11-2.fc35.x86_64

    [root@localhost test]# drgn -s /usr/lib/debug/lib/modules/5.12.0-0.rc8.191.fc35.x86_64/vmlinux

    Traceback (most recent call last):

    File "/usr/bin/drgn", line 33, in

    sys.exit(load_entry_point('drgn==0.0.11', 'console_scripts', 'drgn')())

    File "/usr/lib64/python3.9/site-packages/drgn/internal/cli.py", line 119, in main

    prog.load_debug_info(args.symbols, **args.default_symbols)

    Exception: /usr/lib/debug/usr/lib/modules/5.12.0-0.rc8.191.fc35.x86_64/vmlinux: .debug_info+0x7704ab: unknown DWARF CU version 5

    Ставлю ядро от fc34, чуть более раннее — не помогает.

    Ну хорошо, думаю, раз не получается залезть в эти ядра drgn, давай попробую crash.

    А он тоже не запускается!

    [root@localhost ~]# crash -d 1 (без дебага dwarf error не виден)

    ...

    Dwarf Error: wrong version in compilation unit header (is 5, should be 2, 3, or 4) [in module /usr/lib/debug/usr/lib/modules/5.11.12-300.fc34.x86_64/vmlinux]

    crash: /usr/lib/debug/lib/modules/5.11.12-300.fc34.x86_64/vmlinux: no debugging data available

    Рассылаю багрепорты во все стороны, выясняю:

    Fedora 34 переехала на новый gcc 11, который для всего подряд генерит debuginfo в новом формате DWARF version 5. Обычный userspace с ним вполне нормально работает, gdb этому формату уже давно обучили.

    Однако для ядра это оказалось поистине катастрофично, потому что:

    • crash использует внутри старую версию gdb, которая DWARF 5 еще не понимает

    • drgn поддержку DWARF 5 еще не прикрутил,

    • и у systemtap, похоже, аналогичные проблемы.

    И пока я рассылал во все стороны багрепорты, Fedorа 34 благополучно зарелизилась.

    М-да! Как они собираются процессить kernel crashes и bug reports? Возможно, у них есть хитрый план?

    Связался с девелоперами crash и drgn - ни там, ни там быстро прикрутить поддержку DWARF 5 не обещают. Так что похоже, хитрого плана все-таки нет. Возможно, недосмотрели. Возможно, даже, специально закрыли на это глаза, чтобы посмотреть что именно  развалится  и собрать багрепорты. В конце концов, Fedora не Red Hat и не CentOS. Она как раз и предназначена для обкатки новых технологий. Удивительно, как оно так получилось. Однако  при этом совершенно неинтересно, почему.

    Убежден, что подавляющее большинство пользователей новой Fedora, вероятнее всего, всей этой удивительно-неинтересной проблемы даже не заметят. В ядре в конце концов копаются единицы. Для них могу предложить следующие варианты:

    Во-первых, можно перекомпилировать ядро с DWARF 4, в ядре для этого есть соответствующий CONFIG_DEBUG_INFO_DWARF4. Полагаю, Fedora именно так и поступит в ближайшем будущем.

    Во-вторых, можно установить ядро от предыдущей Fedora 33. Брать, например, здесь. Проверил, вроде как то работает.

    В-третьих, вспомнить, что Fedora для production не предназначена, и смириться с тем, что в ней багов больше обычного.

    И, в любом случае, не поленитесь забить им багрепорты, это очень важно и для них, и для любого другого Open Source.

    Virtuozzo
    Разработчик ПО для контейнерной виртуализации

    Комментарии 0

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

    Самое читаемое