Вы здесь

initrd, lvm, ошибка активации lv с включенным cache [SOLVED]

Доброго времени суток.

У меня возникла проблема с активацией lvm в initrd.

Что было:
несколько hdd, разбивка следующая: 1 раздел - основные данные, 2 раздел - boot, 3 раздел - efi
raid: md1 - raid5 (первые разделы на всех дисках), md2 - raid1 (вторые разделы),
lvm: pv - md1, vg - vgmain (в которую входит только один pv - md1), lv - их несколько, в том числе и root.
в качестве загрузчика использовал grub2.
initrd - самописный, пользовался, кажется, руководством https://wiki.gentoo.org/wiki/Custom_Initramfs
все это благополучно настроил много лет назад, все работало, все устраивало.
сейчас захотел прикрутить к root lvm cache на ssd, т.к. полностью переносить систему на ssd нехочу из соображений надежности (да, возможно предрассудки, но это мои предрассудки).
столкнулся с несколькими проблемами.
1. текущий initrd содержит старую версию lvm:

  LVM version:     2.02.97(2) (2012-08-07)
Library version: 1.02.76 (2012-08-07)
Driver version: 4.39.0

которая не понимает что такое lvm cache,
не беда, обновил до той, что сейчас установлена в системе (бинарник брал, естественно, статический):

  LVM version:     2.02.184(2) (2019-03-22)
Library version: 1.02.156 (2019-03-22)
Driver version: 4.39.0

2. для работы lvm cache нужно утилита cache_check.
добавил её в initrd.
3. этого оказалось мало. изменилось поведение lvm.
старый init для активации lvm выполнял следущие действия:

activate_lvm(){
lvm vgscan --mknodes &&
lvm vgchange -ay
}

их было достаточно, чтобы в /dev/mapper/ появились block device (имя формата vgname-lvname),
но с новой версии lvm такого не происходит, создаются только /dev/dm-[0-9]*, это не большая проблема, всего-то пройтись по uuid и найти нужный. это я решил.
4. не работает активация lv с включенным cache'ем (опцию --sysinit пробовал добавлять в качестве теста, что с ней, что без неё - результат одниковый):

/ # lvm vgchange -ay --sysinit
WARNING: Failed to connect to lvmetad. Falling back to device scanning.
modprobe: chdir(4.19.97-gentoo): No such file or directory
/sbin/modprobe failed: 1
modprobe: chdir(4.19.97-gentoo): No such file or directory
/sbin/modprobe failed: 1
/dev/mapper/vgtest-lvt--cache_cmeta: open failed: No such file or directory
0 logical volume(s) is volume group "vgtest" now active
[ 81.111886] lvm (1140) used greatest stack depth: 13952 bytes left

как побороть ошибку *_cmeta я так и не нашел.

это вывод из тестового стенда, конфиг lvm, которого повторяет мою проблему (а именно включение lvm cache ломает активацию lv на этапе initrd):

# pvdisplay  -m
--- Physical volume ---
PV Name /dev/vdb1
VG Name vgtest
PV Size <5,00 GiB / not usable 3,00 MiB
Allocatable yes (but full)
PE Size 4,00 MiB
Total PE 1279
Free PE 0
Allocated PE 1279
PV UUID zvOsLX-em4a-tqck-ZYSv-OjW4-Fjio-rzQDok

--- Physical Segments ---
Physical extent 0 to 1278:
Logical volume /dev/vgtest/lvt-test_corig
Logical extents 0 to 1278

--- Physical volume ---
PV Name /dev/vde
VG Name vgtest
PV Size 1,00 GiB / not usable 4,00 MiB
Allocatable NO
PE Size 4,00 MiB
Total PE 255
Free PE 0
Allocated PE 255
PV UUID avPvww-1DKk-IySB-iA5F-N5B0-aeSL-1BSoQk

--- Physical Segments ---
Physical extent 0 to 1:
Logical volume /dev/vgtest/lvol0_pmspare
Logical extents 0 to 1
Physical extent 2 to 3:
Logical volume /dev/vgtest/lvt-cache_cmeta
Logical extents 0 to 1
Physical extent 4 to 254:
Logical volume /dev/vgtest/lvt-cache_cdata
Logical extents 0 to 250

# vgdisplay
--- Volume group ---
VG Name vgtest
System ID
Format lvm2
Metadata Areas 2
Metadata Sequence No 52
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 1
Open LV 0
Max PV 0
Cur PV 2
Act PV 2
VG Size 5,99 GiB
PE Size 4,00 MiB
Total PE 1534
Alloc PE / Size 1534 / 5,99 GiB
Free PE / Size 0 / 0
VG UUID 4sYlbf-HZAZ-BhYs-D9AK-bQnr-p7mh-cUCmYe

# lvdisplay
--- Logical volume ---
LV Path /dev/vgtest/lvt-test
LV Name lvt-test
VG Name vgtest
LV UUID 620xp0-coGe-fykI-nQGV-I79l-KMG6-OIViQe
LV Write Access read/write
LV Creation host, time localhost, 2020-03-07 09:26:43 +0200
LV Cache pool name lvt-cache
LV Cache origin name lvt-test_corig
LV Status available
# open 0
LV Size <5,00 GiB
Cache used blocks 0,11%
Cache metadata blocks 2,83%
Cache dirty blocks 0,00%
Cache read hits/misses 328 / 136
Cache wrt hits/misses 0 / 0
Cache demotions 0
Cache promotions 0
Current LE 1279
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 256
Block device 252:3

содержимое init из initrd:

#!/bin/busybox sh

rescue_shell() {
echo "Something went wrong. Dropping you to a shell."
busybox --install -s
exec /bin/sh
}

load_modules() {
MOD_PATH="/lib/modules"
MODULES=`ls ${MOD_PATH}`
for MODULE in ${MODULES} ; do
insmod -f ${MOD_PATH}/${MODULE}
done
}

activate_lvm(){
lvm vgscan --mknodes &&
lvm vgchange -ay
}

uuidlabel_root() {
for cmd in $(cat /proc/cmdline) ; do
case $cmd in
root=*)
dev=${cmd#root=}
type=${dev%%=*}
if [ $type = "LABEL" ] || [ $type = "UUID" ] ; then
mount -o ro $(findfs "$dev") /mnt/root || rescue_shell
else
mount -o ro ${dev} /mnt/root || rescue_shell
fi
;;
esac
done
}

mount -t proc none /proc || exit
mount -t sysfs none /sys
mount -t devtmpfs none /dev

load_modules || rescue_shell

rescue_shell
# Mount the root filesystem.
mdadm --assemble --scan /dev/md1 || rescue_shell
activate_lvm || rescue_shell
uuidlabel_root || rescue_shell

# Clean up.
umount /proc
umount /sys
umount /dev

# Boot the real thing.
exec switch_root /mnt/root /sbin/init

конфиг ядра (опции lvm находятся в device drivers -> Multiple devices driver support (RAID and LVM), в сами названия начинаются на CONFIG_DM):

# CONFIG_DM_MQ_DEFAULT is not set
# CONFIG_DM_DEBUG is not set
CONFIG_DM_BUFIO=y
# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set
CONFIG_DM_BIO_PRISON=y
CONFIG_DM_PERSISTENT_DATA=y
# CONFIG_DM_UNSTRIPED is not set
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_THIN_PROVISIONING=m
CONFIG_DM_CACHE=y
CONFIG_DM_CACHE_SMQ=y
CONFIG_DM_WRITECACHE=y
# CONFIG_DM_ERA is not set
CONFIG_DM_MIRROR=m
CONFIG_DM_LOG_USERSPACE=m
CONFIG_DM_RAID=m
CONFIG_DM_ZERO=y
CONFIG_DM_MULTIPATH=m
CONFIG_DM_MULTIPATH_QL=m
CONFIG_DM_MULTIPATH_ST=m
CONFIG_DM_DELAY=m
# CONFIG_DM_UEVENT is not set
CONFIG_DM_FLAKEY=m
CONFIG_DM_VERITY=m
# CONFIG_DM_VERITY_FEC is not set
# CONFIG_DM_SWITCH is not set
# CONFIG_DM_LOG_WRITES is not set
# CONFIG_DM_INTEGRITY is not set

т.е. то, что мне нужно собрано в ядре (а не модулем), и в должно работать. на загруженной системе (стенд), lv с cache подхватывается и его можно использовать (тестовый lv, root не на нем), а вот на этапе initrd ошибка.

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

lvm vgscan 2>&1
lvm vgchange -ay --sysinit 2>&1
lvm vgmknodes --ignorelockingfailure

но она тоже результата не дают - vgchange возвращает ту же ошибку.

буду благодарен за свежие идеи, ибо мои уже закончились.

единственная догадка - это изменилось поведение lvm и те команды, которыми я пользовался ранее, уже не создают нужные мне /dev/mapper/vgname-lvname либо /dev/vgname/lvname block device (либо symlink'и на /dev/dm-[0-9]*), а на этапе инициализации lv с включенным cache выполняется запуск check_cache, которому в качестве аргумента передается путь к lv:

# strace -f -s 1024 lvm vgchange -ay  2>&1|grep execve
[pid 3422] execve("/sbin/modprobe", ["/sbin/modprobe", "dm-cache-smq"], 0x7ffeee8ebef8 /* 30 vars */) = 0
[pid 3439] execve("/sbin/cache_check", ["/sbin/cache_check", "-q", "--clear-needs-check-flag", "/dev/mapper/vgtest-lvt--cache_cmeta"], 0x7ffeee8ebef8 /* 30 vars */) = 0

к слову тут же видно и с какими параметрами выполняется modprobe (но я не понимаю на кой он нужен, если ядро собрано с CONFIG_DM_CACHE_SMQ=y).

ради интереса попробовал (для теста разумеется) заменить /sbin/cache_check на /bin/true дабы пропустить его проверку, но вывод ошибки, которая возникает на этапе initrd не меняется, значит до его запуска даже не доходит.

lvm cache не сама цель. в конечном итоге хочу получить кеширование нескольких lv на ssd и в моей текущей конфигурации его внедрение было вроде самой легкой задачей.
bcache попросит переформатировать разделы, и как поведет себя после смерти ssd я не знаю.
переводить lvm на zfs нет возможности.

Может доки недочитал?
Вот тут ещё пару сайтов, где для домохозяек на пальцах объясняют, как надо делать:
https://lukas.zapletalovi.com/2019/05/lvm-cache-in-six-easy-steps.html
https://ahelpme.com/linux/lvm/ssd-cache-device-to-a-hard-disk-drive-using-lvm/

в целов да, arch доки не читал, нашел другую.
но ведь не в этом проблема - создание lvm cache прошло у меня успешно.
проблема в том, что не работает его активация на этапе initrd, тогда как в загруженной системе все ок.
cache примерно так и создавал:

vgextend vgtest /dev/vde
lvcreate --type cache-pool -l 100%FREE -n lvt-cache vgtest /dev/vde
lvconvert --type cache --cachepool vgtest/lvt-cache vgtest/lvt-test

он создается и работает, но перезагрузку система не пережила.

тут нашел упоминание об genkernel-next
попробовал, он генерирует те же команды активации lvm что и genkernel, которые не работает с lvm cache.

нашел способ воспроизвести на загруженной системе:

localhost ~ # /etc/init.d/udev status
* status: stopped
localhost ~ # /etc/init.d/lvm status
* status: stopped
localhost ~ # /etc/init.d/lvmetad status
* status: stopped
localhost ~ # vgchange -ay --sysinit
WARNING: Failed to connect to lvmetad. Falling back to device scanning.
/dev/mapper/vgtest-lvt--cache_cmeta: open failed: Нет такого файла или каталога
0 logical volume(s) in volume group "vgtest" now active
localhost ~ # /etc/init.d/udev start
* Starting udev ... [ ok ]
localhost ~ # vgchange -ay
WARNING: Failed to connect to lvmetad. Falling back to device scanning.
1 logical volume(s) in volume group "vgtest" now active

но только где же я в initrd возьму udev то(

в initrd можно включить все, что угодно! Читай теорию...

та да, уже тоже нашел упоминание, что в arch он по-умолчанию включен в initrd,
и более того в initrd сгенерированном genkernel/genkernel-next он есть, что объясняет почему там работают команды активации.
вангую что через 20 лет в initrd будет полноценный stage3, только для того чтобы примонтировать root(.
такого подвоха от lvm я не ожидал... Поттеринг их покусал чтоли)

А что тут не так? Разберись как работает система, и все станет понятно и логично!
Очевидно же, что при запуске системы нужно при себе иметь все, что использует при этом.
Для того и придумали initrd (а это и есть статическая минисистема!), чтобы не подключать все нужные ресурсы статически в ядро и/или утилиты, как это сделал ты! ;)
И, в отличие от твоего костыля, при правильном использовании initrd нет ненужного разбазаривания ресурсов - ведь твой lvm будет жрать больше памяти всегда - и при нормальной работе системы тоже! А то что initrd стал больше - кого это волнует, ибо он используется только при запуске, а с флоппиков давно уже никто не грузится... :)

эм, а чем костыль?
и почему "ведь твой lvm будет жрать больше памяти всегда"?

я в ядро запихнул все что нужно для работы моей системы (raid, lvm, еще там по мелочи), что позволило не пересобирать initrd после каждого обновления ядра.
lvm с нужными флагами собрал единожды чтобы получить бинарник, который положил в initrd, затем пересобрал с предидущими use-флагами.

что не учел?

USE="static-libs static -udev" emerge -1Nav sys-fs/lvm2

полностью решает мою проблему. на выходе получается бинарник, который активирует lvm cache в initrd без udev.