Поддерживайте активное состояние для ровно одной конфликтующей единицы с помощью systemd.

Вопрос или проблема

Я хочу размонтировать некоторые локальные разделы, когда компьютер переходит в режим гибернации, то есть “suspend-to-disk”. И (конечно!) монтировать их при возврате из этого состояния. Рассмотрим мой юнит монтирования:

[Unit]
Description=Некоторый раздел
DefaultDependencies=no
Conflicts=umount.target hibernate.target
Before=umount.target hibernate.target
After=local-fs-pre.target

[Mount]
What=/dev/disk/by-uuid/<UUID>
Where=/mnt/point
Options=defaults

[Install]
WantedBy=multi-user.target

Технически я хочу, чтобы моя машина находилась в одном из следующих состояний:

  • юнит монтирования активен
  • достигается цель гибернации (или в общем случае работает конфликтующий юнит)

Мой компьютер гибернизируется следующим образом:

Достигнута цель sleep.target
Запуск systemd-hibernate.service - Гибернация системы...
<ядро сохраняет / восстанавливает состояние>
Завершено systemd-hibernate.service - Гибернация системы.
Достигнута цель hibernate.target - Гибернация системы.
Остановлена цель hibernate.target - Гибернация системы.

Таким образом, mnt-point.mount должен конфликтовать либо с hibernation.target, либо с systemd-hibernate.service. В примере я использую первое, так как это выглядит более идиоматично (точно так же, как юнит монтирования подразумевает конфликт с umount.target). Но теоретически hibernation.target достигается только при восстановлении, поэтому может быть безопаснее оставить systemd-hibernate.service в качестве конфликтующего юнита. Это не совсем важный выбор на данный момент.

Параметр Conflicts= решает только первую часть проблемы. Я могу остановить юнит монтирования при гибернации. Но я не могу запустить юнит монтирования, когда гибернация заканчивается.

В руководстве systemd.unit говорится о Conflicts=:

Если у юнита есть настройка Conflicts= для другого юнита, запуск первого остановит последний и наоборот.

Похоже, что наоборот равносильно запуск последнего остановит первый, но мне дополнительно нужна семантика остановка последнего запустит первый. Я не смог найти никакое условие systemd, которое помогло бы мне с этим.

Я не верю, что нет идиоматического способа сделать это, так как механизмы зависимости systemd выглядят довольно сложными, так что, возможно, кто-то мог бы указать мне правильное направление. Возможно, мы могли бы просто ExecStop(Post?)= в systemd-hibernate.service, но это слишком общее, можно запустить произвольную команду с помощью этого. Также желательно не переопределять предустановленные юниты systemd при добавлении каждого следующего монтирования.

Ответ или решение

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

Анализ текущей конфигурации

Ваш юнит mnt-point.mount включает следующие секции:

  • Unit: прописаны зависимости и порядок выполнения.
  • Mount: ссылка на устройство и точку монтирования.
  • Install: указание цели, к которой этот юнит должен быть подключен.

Вы правильно указали конфликты с umount.target и hibernate.target. Однако, чтобы запустить юнит при выходе из режима гибернации, потребуется обработка в секции After.

Решение проблемы с состоянием

Для достижения необходимого поведения предлагаю следующий подход:

  1. Создание отдельного юнита для монтирования раздела при восстановлении. Это позволит явно указать порядок и зависимости.
[Unit]
Description=Mount unit for hibernation resume
After=suspend.target
PartOf=mnt-point.mount 

[Mount]
What=/dev/disk/by-uuid/<UUID>
Where=/mnt/point
Options=defaults

[Install]
WantedBy=suspend.target
  1. Изменение юнита размонтирования (mnt-point.mount). Здесь вы будете использовать OnFailure для определения действия в случае неудачи, а также добавление зависимости Before для корректного управления состояниями.
[Unit]
Description=Some partition
DefaultDependencies=no
Conflicts=umount.target hibernate.target
Before=umount.target hibernate.target
After=local-fs-pre.target

[Mount]
What=/dev/disk/by-uuid/<UUID>
Where=/mnt/point
Options=defaults

[Install]
WantedBy=multi-user.target

Использование зависимостей

Необходимо также создать зависимости таким образом, чтобы при завершении systemd-hibernate.service запускался ваш монтирующий юнит. Это можно сделать через настройку в /etc/systemd/system/systemd-hibernate.service.d/custom.conf:

[Service]
ExecStopPost=/bin/systemctl start mnt-point.mount

Общая структура

Скомбинировав эти элементы, ваша конфигурация позволит достичь желаемого результата через следующее:

  • При инициировании гибернации systemd-hibernate.service будет завершен, а ваш монтирующий юнит запустится.
  • При выходе из гибернации раздел будет автоматически смонтирован для дальнейшего использования.

Заключение

Таким образом, внедрив предложенные изменения в конфигурацию ваших юнитов, вы обеспечите желаемое поведение системы в режиме гибернации. Это решит проблему конфликта между монтированием раздела и процессом гибернации, обеспечивая необходимую интеграцию и автоматическую обработку состояния. Кроме того, использование собственных конфигураций для systemd позволяет прерывать зависимости без необходимости изменять преднастроенные юниты, что соответствует лучшим практикам системного администрирования.

Оцените материал
Добавить комментарий

Капча загружается...