Помните перевод статьи «When Solid State Drives are not that solid»? В ней сотрудники компании Algolia возлагали вину за повреждение данных в конфигурации RAID0 на SSD от компании Samsung.
Проблема все таки была решена в результате долгого разбирательства, в ходе которого сотрудникам Algolia пришлось даже написать ПО, эмулирующее их тип нагрузки на RAID, чтобы инженеры Samsung смогли повторить проблему на своем оборудовании. Исправление коснулось ядра Linux, а точнее — файла bio.c, отвечающего за основные операции блочного ввода-вывода.
Проблема состояла в следующем — подсистема ввода-вывода ядра может разделять операцию блочного ввода-вывода (BIO) на несколько в тех случаях, когда это целесообразно. Для разделения используется функция bio_split(). При разделении создается новый объект BIO, а информация в старом корректируется с учетом того, что часть адресов, по которым происходит ввод-вывод, «переехала» в новый объект. В целях экономии памяти новый объект создается путем копирования значений из старого, при этом указатели в новом и старом объектах указывают на одну и ту же область памяти. Для операций чтения/записи это работает нормально, поскольку при выполнении этих операций содержимое полей объекта BIO, доступных через указатели, не изменяется. Однако для операции DISCARD это не так — поле bio_vec структуры bio содержит указатель на служебные данные, необходимые для выполнения команды (начальный адрес и размер стираемой области).
Модули raid0 и raid10 ядра используют функцию bio_split() и посылают разделенные запросы драйверу SCSI/SATA, однако драйвер SCSI/SATA не предполагает что разные запросы могут использовать одну область памяти и перезаписывает содержимое по адресу, указанному в bio_vec. Поэтому следующий запрос приходит уже с указателем на некорректные данные, что и взывает DISCARD по некорректным адресам.
Первый вариант патча, предложенный инженерами Samsung, предусматривал модификацию исходного кода драйвера raid0, однако в ядро вошел более общий вариант, который предусматривает полное копирование структуры bio вместе с занимаемыми ей страницами памяти в случае выполнения DISCARD.
Данной проблеме подвержены все накопители, поддерживающие TRIM, независимо от модели, в конфигурации RAID0 или RAID10.
Неясным остается вопрос, почему проблема не проявлялась на накопителях Intel. Возможно, дело в таймингах.
Комментарии (23)
MaximChistov
31.07.2015 11:03-29Вот это круто) Никогда ничего такого не было бы возможно в не опенсорс софте
MaximChistov
31.07.2015 11:16-21Я про нахождение и исправление ошибки в самой ОС, если что…
ildarz
31.07.2015 11:29+40«Такое» (исправление ошибок в софте при совместной работе вендора оборудования и производителя софта, иногда с вовлечением клиента) в проприентарном софте происходит столько, сколько вы на свете не живете, судя по вашему профилю.
MaximChistov
31.07.2015 18:02-3То есть Microsoft на ваш взгляд так же легко отдает исходники винды всем, у кого странные проблемы с ней?
CodeRush
31.07.2015 21:26+9Большая часть проблем с оборудованием в любой приприетарной ОС решается засылом этого оборудования производителю ОС и дальнейшей совместной отладкой. Так делают все крупные игроки, и Intel, и MS, и WindRiver, и все остальные. Если вам действительно нужно и у вас контракт на тех. поддержку подписан давно и надолго — коммерческие компании вас один на один с проблемой не оставят.
Исходники никто не раздает, т.к. разбираться в них инженеры разработчиков железа не обязаны и не будут — они в нем не понимают ничего, в отличие от тех, кто его писал и поддерживает. Понятно, что сначала заставят прогнать тесты Hardware Certification Kit'а, потом будет пару недель переписки из серии «попробуйте выключить и включить», но по итогу все проблемы, которые были у нас поддержкой оборудования со стороны MS удалось успошно решить.poxu
01.08.2015 18:08Это, понятное дело, если у вас уже давно и очень долго есть деньги на подписание контракта на техподдержку. Много денег.
Mixalych
31.07.2015 11:34-19Бред сивой кобылы. Сорри, но по-другому сказать — язык не поворачивается. Зачастую коммерческий софт написан… хотя, код закрыт. Я видел несколько корпоративных продуктов, код там до ужаса неадекватный. Конечно, далеко не у всех. А опенсорс — его смотрят тысячи, тут в любом случае код причесывается. Да и народ охотно поддерживает все опенсорсное. «Не опенсоср» — там, как правило, все очень и очень медленно исправляется, причем, в прямо-пропорциональной зависимости. Чем дороже продукт, тем больше клали на ваше «хочу». Ну кроме тех, кто за монету может все исправить дабы не потерять репутацию.
Это мое имхо.rinat_crone
31.07.2015 11:45+23Фраза «моё имхо» – самое маслянистое из всех маслянистых масельных масел. ИМХО.
youROCK
31.07.2015 12:41+4драйвер SCSI/SATA не предполагает что разные запросы могут использовать одну область памяти и перезаписывает содержимое по адресу, указанному в bio_vec
А это вообще законно для драйвера? Переписывать содержимое памяти, которое ему дают на вход.KawaiDesu
31.07.2015 14:23+2Подразумевается память на диске. А как ещё? Драйвер должен быть оракулом и сам догадаться по какому адресу потребовать у диска затереть данные?
lovecraft Автор
31.07.2015 21:58+1Ну, драйвер справедливо полагает, что раз запрос спустился на его уровень, то с памятью запроса можно делать что угодно.
youROCK
03.08.2015 12:53Может, я что-то неправильно понял? Например, давайте посмотрим на системный вызов write(int fildes, const void *buf, size_t nbyte) — ему на вход дают указатель на буфер buf, из которого нужно взять данные для записи в файл. Я лично не могу представить себе ситуацию, когда в этот буфер будет что-нибудь записано операционной системой, «потому что это её буфер». Грубо говоря, вы можете спокойно разделять этот буфер с другими системными вызовами и не беспокоиться о сохранности данных. Почему для драйвера не используется тот же самый подход?
lovecraft Автор
04.08.2015 11:33+1В объявлении write() указатель const void *buf константный, что в какой-то мере защищает его от случайных изменений, а вот как объявлена функция драйвера, которая меняет содержимое в bio_vec — большой вопрос. А вообще, вопрос интересный: то что у нас драйвер меняет данные в команде — еще не худший вариант. Например данные, которые пишутся на диск, могут быть изменены извне в процессе исполнения диском команды записи. Процитирую уважаемого amarao:
В линуксе давным-давно идёт срач на тему персистентных страниц при записи. Другими словами, «можно ли писать в грязные страницы». Срач типовой для подобной ситуации — одних ужасает, что данные могут меняться в середине записи (и записываться непонятно как), других ужасает то, как дорого и медленно выглядит решение проблемы.
[Решение: полный отказ от кешей на запись любого уровня и переход на ssd].
при этом на lvm.net считают дефект чисто косметическим.
Mithgol
04.08.2015 12:13Этот комментарий стёрт, потому что тег <twitter> на Хабрахабре глючит и результат работы его непригляден.
edwardoid
Шикарно, пацаны! Молодцы и Angolia, и Samsung, и коммитеры Oracle/FB!
HomoLuden
AngoliaAlgolia