systemd: сериализация загрузки

systemd: сериализация загрузки

Загрузка Ubuntu 17.04 не удалась, и я хочу устранить неполадки.

Загрузка время от времени прерывается, и я полагаю, что это происходит из-за состояния гонки.

Могу ли я попросить systemdне распараллеливать какие-либо задачи, чтобы я мог увидеть, приведет ли это к предсказуемому сбою загрузки?

решение1

Обходной путь: запуск служб вручную

У меня естьсбой при запуске. В моем случае сбой произошел после достижения basic.targetцели, но до multi-user.target, поэтому я хотел выяснить, какая из запущенных служб multi-user.targetвызвала сбой.

Сначала я организовал загрузку в basic.targetплюс root shell. Вы можете сделать это постоянно (если вам вообще удастся загрузиться!) с

systemctl set-default basic.target
systemctl enable debug-shell

Служба debug-shellзапускает оболочку root на tty 9.

Вы можете получить тот же эффект, добавив параметры systemd.unit=basic.target systemd.debug-shellв командную строку ядра. Например, в Grub отредактируйте командную строку на что-то вроде

linux /vmlinuz-4.13.0-38-generic root=/dev/mapper/crypt-root ro systemd.unit=basic.target systemd.debug-shell

Из этой оболочки я запустил следующий скрипт для запуска служб по одной. Обратите внимание, что это в значительной степени не протестировано (я запустил его один раз, и он, как и ожидалось, упал на проблемной службе).

#!/bin/sh
wants=$(systemctl show -p Wants multi-user.target | sed 's/^Wants=//' | tr ' ' '\n' | sort)
log=/var/tmp/multi-user-steps-$(date +%Y%m%d-%H%M%S)

log () {
  echo "$* ..." | tee -a "$log"
  sync
  "$@"
  ret=$?
  echo "$* -> $ret" | tee -a "$log"
  sync
  return $ret
}

# systemd services
for service in $wants; do
  log systemctl start $service
  sleep 2
done

# upstart services
for conf in /etc/init/*.conf; do
  service=${conf##*/}; service=${service%.conf}
  log service ${service} start
  sleep 2
done

# sysvinit services
for service in /etc/rc3.d/S*; do
  log ${service} start
  sleep 2
done

Добавить дополнительные зависимости

Скрипт ниже объявляет зависимости «Before» для модулей systemd, которые являются прямыми зависимостями данной цели, чтобы заставить их запускаться в определенном порядке. Вы можете захотеть запустить его на multi-user.targetили basic.target.

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

Обратите внимание, что это не влияет на службы Upstart и SysVinit.

Сделайте резервную копию /etcперед запуском! (Я настоятельно рекомендую использоватьetckeeper.)

#!/bin/sh
set -e

if [ $# -eq 0 ] || [ "$1" = "--help" ]; then
  cat <<EOF
Usage: $0 TARGET
Linearize the dependencies of a systemd target so it starts deterministically.
This scripts adds systemd unit files called linearize-for*.conf containing
extra Before= dependencies for each dependency of TARGET.
EOF
fi

service_dir=/etc/systemd/system
target=$1

wants=$(systemctl show -p Wants "$target" | sed 's/[^= ]*=//' |
                                            tr ' ' '\n' | sort)
previous=
for want in $wants; do
  [ -d "$service_dir/$want.d" ] || mkdir "$service_dir/$want.d"
  cat <<EOF >"$service_dir/$want.d/linearize-for-${target%.*}.conf"
[Unit]
Before=$previous
EOF
  previous=$want
done

Связанный контент