Я изучал проблему, которая возникла у меня с Мендер, из-за которой ход установки (то есть копирование файла на блочное устройство) не отображается правильно.
Я чувствую, что речь идет о кеше страниц ядра: индикатор выполнения показывает «100%», когда код прочитал все изображение, но это не означает, что ядро закончило его запись.
Более конкретно, Mender вызывает n, err := io.Copy(dev, image)
, который возвращается после завершения записи ядра. Но индикатор выполнения связан с «изображением» Reader
, которое полностью считывается за десятки секунд до возврата io.Copy
.
Поскольку файл открывается с флагами здесь, я наивно думал, что надо просто поставить flag |= O_SYNC
, чтобы io.Copy(dev, image)
не читал image
быстрее, чем пишет в dev
.
Но установка O_SYNC
не имеет значения.
Мне не ясно, является ли O_SYNC
просто подсказкой (поэтому я не могу на это рассчитывать), может ли быть так, что я что-то упускаю на своем устройстве (например, я забыл параметр ядра на своем Raspberry Pi и поэтому O_SYNC
бесполезен ), или если я просто неправильно понял, что делает O_SYNC
?
Обновлено: я также пытался установить O_SYNC | O_DIRECT
(хотя O_DIRECT
, по-видимому, не отображается в Go, и поэтому я сделал O_SYNC | 0o40000
), но при открытии блочного устройства я получил следующую ошибку:
Opening device: /dev/mmcblk0p2 for writing with flag: 1069058
Failed to open the device: "/dev/mmcblk0p2": open /dev/mmcblk0p2: not a directory
Я добавил тег линукс, так как это действительно внутренний вопрос Linux. Я не думаю, что O_SYNC
много для вас делает здесь. Он предназначен для синхронной записи, но если он не передан в драйвер устройства и драйвер не подчиняется ему, а аппаратное обеспечение не взаимодействует, это буквально не мочь поможет вам. O_DIRECT
для обхода буферного кеша. больше здесь
Спасибо @torek! Я также попробовал O_DIRECT, а потом подумал, что это неправильный путь (также из-за этого: svetlinmladenov.wordpress.com/2013/01/20/on-o_direct). Я отредактировал свой вопрос тем, что пробовал. Должен ли O_DIRECT работать с блочным устройством? Я не понимаю, почему написано: «не каталог», но, может быть, 0o40000
неправильно...?
@YotamSalmon: Судя по коду (но я его не проверял), индикатор выполнения — это своего рода «декоратор» (не уверен, что это правильное слово) вокруг Reader
изображения. Таким образом, индикатор выполнения обновляется напрямую, когда читается Reader
. Следовательно, я достаточно уверен, что «100%» означает, что Reader
прочитал все байты. Если только где-то в коде не работает какой-то странный прокси, который я пропустил, то есть :-).
040000
(0o40000
для Go) — это По умолчанию из linux/bits/fcntl-linux.h, но ваша архитектура может иметь другое (зависящее от архитектуры) значение. Похоже, что RPi (рука) имеет этот бит как O_DIRECTORY
и O_DIRECT
, определенный как 0200000
: см. github.com/raspberrypi/tools/blob/master/arm-bcm2708/…Между тем, если индикатор выполнения украшает только часть io.Reader
, это, вероятно, будет частью проблемы...
@torek: вы правы, в логике завершения индикатора выполнения была ошибка -_-. Не могли бы вы написать свои комментарии об O_SYNC и O_DIRECT (также о части Raspberry Pi) в качестве ответа, который я могу принять? Я немного отредактирую свой вопрос, чтобы сосредоточиться на части O_SYNC (если вам это подходит)
@YotamSalmon: Итак, вы были правы, это было на стороне индикатора выполнения. Благодаря вам я познакомилась с ним поближе! Большое спасибо :)
Синхронизация не имела бы значения. Если установщик думал, что запись завершена (но на самом деле она ожидалась), то же самое сделает и остальная часть системы, и установка будет «завершена». Объяснение декоратора io.Reader
имеет гораздо больше смысла.
Резюмируя комментарии:
Основная проблема заключается в том, что индикатор выполнения украшает средство чтения (как Йотам Салмон отметил), а не средство записи; задержка на стороне автора.
В большинстве систем Linux O_DIRECT
действительно 0o40000
, но на ARM (включая Raspberry Pi) это 0o200000
, а 0o40000
— это O_DIRECTORY
. Это объясняет ошибку «не каталог».
O_SYNC
на самом деле является тем битом, который вам нужен, или вы можете просто выполнить системный вызов fsync
(используйте Flush
, если это уместно, а затем Sync
, как указано в Когда сбрасывать файл в Go?). Бит O_SYNC
подразумевает fsync
системный вызов как часть каждого write
системного вызова.
Полностью синхронный ввод-вывод — это своего рода минное поле: некоторые устройства лгут о том, записывали ли они данные в энергонезависимую память. Тем не менее, O_SYNC
или fsync
— это наибольшая гарантия, которую вы здесь получите. O_DIRECT
, скорее всего, не имеет значения, поскольку вы переходите непосредственно к файлу раздела устройства /dev
. O_SYNC
или fsync
мая передается драйверу устройства, который мая что-то с ним делает, а мая заставляет устройство записывать в энергонезависимую память. Подробнее об этом читайте в Что на самом деле означает O_DIRECT?.
Вы знать или предполагать, который
image
полностью прочитан до того, какio.Copy
вернется? В первом случае, как вы это проверили?