Yesterday

snapd, загрузка cpu и баг ядра

Еще одна поучительная история из жизни Linux, чтобы вы потеряли сон и покой, узнав что такое вообще возможно.

Тот самый баг

Вводная

Эмм с чего бы такого начать, чтобы вы не обосрались раньше времени от прочитанного и не побежали устанавливать *BSD.

Есть на свете одна компания, которой мы помогаем с ИТ, у нее было несколько виртуальных серверов на Ubuntu Linux, используемых в основном для разработки и тестов.

Ubuntu там использовалась нормальной LTS-версии, но в какой-то момент в погоне за патчами безопасности ее обновили до текущей.

Все происходило летом 2025 года, поэтому речь про 25.04 версию Ubuntu, которая использует ядро 6.14 — запомните этот момент:

Баг

Однажды админ компании заметил слишком частую и сильную нагрузку на CPU, создаваемую процессом snapd, отвечающим за подсистему установки и обновления пакетов Snap.

Скриншот не мой, поэтому шакальего качества ;)

Проблема мягко говоря не нова — «проклятый snapd» гадил линуксоидам с момента своего появления на свет и вообще видимо был придуман в качестве «кары за грехи».

Но в этот раз загрузка CPU происходила.. строго по расписанию:

Разумеется первым делом были опробованы стандартные решения, вроде снижения частоты проверок обновлений или полного отключения сервиса:

Особо порадовала выдача ответа ИИ по данной проблеме:

Т.е. дословно «снести к х#ям и использовать что-то другое» — можно сказать первый разумный совет от машины за всю историю искусственного интеллекта!

Дальнейшие изыскания привели в багтрекер snapd к упомянутому багу, где третий же комментарий от разработчика snapd, с приложенной трассировкой вызовов показал что проблема именно в ядре:

Тут стоит добавить, что встал вопрос проверки этого бага на локальной машине, поскольку на момент изучения вопроса все успело обновиться, а отлаживать ядро Linux на сервере заказчика все же не очень хорошая затея.

Чуть ниже по переписке видно что баг особо ярко проявляется на ноутбуке, работающем от батареи:

Так что решено было пробовать отловить именно в таких условиях.

На счастье, на машине осталась сборка 6.14 версии ядра с патчами от Xanmod, которая использовалась для статьи про l9ec.

В последние годы у Linux выпускается очень много промежуточных релизов, поэтому на какой именно версии внутри 6.14 ветки что-то пошло не так еще пришлось выяснять:

Наконец источник проблем был найден:

Чуть ниже по переписке обнаружился и тестовый код на Cи, демонстрирующий проблему, вот такой:

#include <sys/epoll.h>
#include <sys/time.h>
#include <sys/wait.h>

int main() {
  int e = epoll_create1(0);
  struct epoll_event event = {.events = EPOLLIN};
  epoll_ctl(e, EPOLL_CTL_ADD, 0, &event);
  const struct timespec timeout = {.tv_nsec = 1};
  epoll_pwait2(e, &event, 1, &timeout, 0);
}

А так это выглядит в действии:

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

Патч находится тут, само место исправления выглядит вот так:

Да, как видите это еще один случай когда ситуацию радикально исправляет буквально пара символов логической конструкции.

Текущее состояние

Формально проблема была решена еще летом, патч попал в mainline и пакет с обновлением ядра от команды Ubuntu:

На осень 2025 года даже стабильная версия ядра Linux уже имеет верси 6.16 — т. е. паровоз разработки уехал уже очень далеко от описываемых проблем:

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

Но если есть подозрение, что источник проблем именно в данном баге — попробуйте собрать тестовое приложение (см. выше) и запустить в своем окружении.

Если начнется загрузка CPU запущенным процессом — проблема точно есть, поскольку в ядрах с патчем поведение тестового приложения отличается:

Как можно заметить тут не происходит блокировки и приложение немедленно завершается.

Что касается нашей компании-заказчика, то поскольку патч был опубликован довольно быстро — мы на время разборок с согласованиями попадания в mainline банальным образом перенесли патч вручную в версию ядра, которая использовалась на сервере.

Позже обновили уже штатными средствами дистрибутива до текущей актуальной версии.

Эпилог

Из этой статьи можно сделать сразу несколько интересных выводов:

1. Н#хуй Linux, даешь BSD

Шучу, разумеется неподготовленным пользователям в BSD-системы лучше не лезть, но задуматься (или хотя-бы просто знать) о реалиях использования Linux все же стоит.

2.Граница между прикладкой и системной разработкой весьма абстрактна

Проще говоря — ее нет совсем, поэтому в любой произвольный момент времени у вас есть неиллюзорный шанс наткнуться на баг ядра, даже программируя на JavaScript в браузере.

3.Любой уважающий себя сисадмин и DevOps должен знать Си

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

Все изыскания по теме «почему тормозит» или «почему упало» рано или поздно приводят к Си и отладчику ядра, чудес нет.

4.Считайте деньги

Описанная в статье проблема случилась в локализованном окружении (на собственных физических серверах компании), но точно такая же Ubuntu часто используется и облачными провайдерами вроде Amazon, где есть тарификация за использование ресурсов, в первую очередь CPU.

Как нетрудно догадаться, 100% загрузка процессора в облаке каждые пять минут если ее вовремя не заметить и не исправить — больно отразится на счете.

Так что проверяйте загруженность — пиковых 100% в современных реалиях быть не должно, если только вы целенаправленно не занимаетесь вычислительными задачами.