Что за баг
В начале года разработчики внесли ряд изменений в ядро Linux 5.1. После этого на системах с SSD от компании Samsung, которые используют шифрование dm-crypt/LUKS c device-mapper/LVM, начала проявляться ошибка, приводящая к потере данных. Но о проблеме стало известно только в середине мая — тогда же её начали активно обсуждать на тематических форумах.
Известно как минимум о двух людях, столкнувшихся с багом, — это участник рассылки LKML Майкл Ласс (Michael Laß), который впервые сообщил о проблеме, и пользователь ArchLinux.
Майкл запустил команду fstrim, которая говорит накопителю, какие блоки данных больше не используются, для смонтированного тома btrfs. После он получил следующие системные сообщения:
Код: Выделить всё
attempt to access beyond end of device
sda1: rw=16387, want=252755893, limit=250067632
BTRFS warning (device dm-5): failed to trim 1 device(s), last error -5
BTRFS warning (device dm-5): csum failed root 257 ino 16634085 off 21504884736 csum 0xd47cc2a2 expected csum 0xcebd791b mirror 1
В случае с пользователем ArchLinux проблема коснулась криптозащиты LUKS. После перезагрузки операционной системы и выполнения fstrim заголовки LUKS (которые используются для поиска томов) оказались нечитаемыми, что не позволило расшифровать зашифрованные данные.
В чем причина
Проблема заключалась в подсистеме device mapper (DM), задача которой — создавать виртуальные блочные устройства. Она как раз используется для реализации менеджера логических томов LVM, программного RAID и системы шифрования дисков dm-crypt.
Патч«Команда fstrim помечала слишком большое количество блоков за раз без учета предела max_io_len_target_boundary. В результате освобождались те сегменты памяти, которые до сих пор используются, — комментирует Сергей Белкин, начальник отдела развития 1cloud.ru. — Поскольку ошибка была связана с device mapper, в теории потеря данных могла произойти на любой файловой системе».
Патч для бага разработчики ядра выпустили в конце мая. Были изменены всего четыре строчки в файле drivers/md/dm.c. Соответствующие изменения также внесли в грядущее ядро Linux 5.2 (добавленные и удаленные строки отмечены знаками «+» и «-» соответственно):
Код: Выделить всё
@@ -1467,7 +1467,7 @@ static unsigned get_num_write_zeroes_bios(struct dm_target *ti)
static int __send_changing_extent_only(struct clone_info *ci, struct dm_target *ti,
unsigned num_bios)
{
- unsigned len = ci->sector_count;
+ unsigned len;
@@ -1478,6 +1478,8 @@ static int __send_changing_extent_only(struct clone_info *ci, struct dm_target *
if (!num_bios)
return -EOPNOTSUPP;
+ len = min((sector_t)ci->sector_count, max_io_len_target_boundary(ci->sector, ti));
+
__send_duplicate_bios(ci, ti, num_bios, &len);
ci->sector += len;
Исключить ситуацию с потерей данных можно и не устанавливая патч. Достаточно отключить сервис fstrim.service/timer с помощью команд:
Код: Выделить всё
systemctl disable fstrim.timer
systemctl stop fstrim.timer
Источник: https://habr.com/ru/company/1cloud/blog/454978/