Вопрос или проблема
Я хочу размонтировать некоторые локальные разделы, когда компьютер переходит в режим гибернации, то есть “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
.
Решение проблемы с состоянием
Для достижения необходимого поведения предлагаю следующий подход:
- Создание отдельного юнита для монтирования раздела при восстановлении. Это позволит явно указать порядок и зависимости.
[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
- Изменение юнита размонтирования (
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 позволяет прерывать зависимости без необходимости изменять преднастроенные юниты, что соответствует лучшим практикам системного администрирования.