Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Sysupgrade / switch root to ram
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > Linux
vgovseychuk
Привет, Электроникс!

Пытаюсь обновиться из-под линукса.
В sysupgrade нет поддержки UBI, так что пытаюсь сделать обновление вручную.
При попытке переписать в лоб - ошибка (хотя mtd write работает):
Код
root@TestTest:/# ubiupdatevol dev/ubi0_0 /tmp/rootfs.img
[ 2885.328555] UBI error: ubi_open_volume: cannot open device 0, volume 0, error -16
ubiupdatevol: can't open 'dev/ubi0_0': Device or resource busy

Посмотрел, как это делает sysupgrade:
Сначала копирует необходимые бинарники, а затем переключается на работу из оперативки.
У меня переключение рута в tmp/root не удалось (не понял принципа, ибо нуб)

В общем интересуют 2 вопроса:
1. Как переключаться на работу из оперативки, освобождая тем самым /dev/ubi0_0?
2. Если есть более удобный способ обновления системы с UBI?

P.S. разделы у меня такие:
Код
-----------------------------------------------------------------
      |bootloader|boot_env|  fdt  |  kernel  |       root       |
MTD   |    3M    |  256k  |  128k |    5M    |        -         |
-----------------------------------------------------------------
                                             |rootfs|rootfs_data|
UBI                                          |  40M |     -     |
-----------------------------------------------------------------

Части системы (fdt, kernel, rootfs) пишу в пямять по отдельности.
alx2
Цитата(vgovseychuk @ Mar 11 2016, 19:45) *
В sysupgrade нет поддержки UBI, так что пытаюсь сделать обновление вручную.

Поскольку никто Вам не отвечает, решил вставить реплику.
Сразу скажу, что ответов на ваши конкретные вопросы у меня нет. Но есть другая мысль.
Насколько я понял (после гугленья sysupgrade), Вы планируете делать апгрейд следующим образом: нужные файлы (например конфиги) сохраняются на другой FS, корневая FS полностью стирается и переписывается новым образом, после чего сохраненные файлы возвращаются на место. Суть моей реплики - нафига Вам переписывать всю файловую систему целиком? Почему бы не воспользоваться системой пакетов и каким-либо пакетным менеджером? Описанной проблемы тогда у Вас не будет в принципе, в процессе обновления будут переписываться только реально обновляемые файлы... Может Вы и ответа не получаете именно потому, что выбранным Вами путем мало кто идет?

Еще несколько преимуществ использования пакетов:
- Не надо заново выкачивать и перезаписывать образ всей файловой системы ради крошечного обновления (к примеру, чтобы обновить SSL-сертификат), достаточно одного малюсенького пакетика.
- Перерыв в работе системы отсутствует совсем или минимален - после обновления требуется перезапуск только реально обновившихся компонентов.
- Гибкость - на разных системах может быть разный набор пакетов.
vgovseychuk
Вообще да, можно и так.
Но это же каждый раз надо вписывать в скрипт, какие пакеты и файлы ты обновлял.
Цитата(alx2 @ Mar 17 2016, 07:56) *
Может Вы и ответа не получаете именно потому, что выбранным Вами путем мало кто идет?

Я посчитал такой вариант наиболее верным с оглядкой на то, как это сделано, например, в роутерах.
В любом случае, большое спасибо за совет.
vgovseychuk
Сделал полное обновление немного кривым способом, потеряв где-то 20% места на NAND: выделил разделы под запись обновляемых файлов: updfdt(размер 0х40000), updkernel(0х500000), updroot(последний включен в UBI, 0х2а00000). Из этого вытекает вопрос контроля того, что записали.

Я пишу из-под линукса скачанные файлы обновления в запасные разделы командами встроенных утилит:
Код
mtd erase updroot
mtd write rootfs.img  updroot
mtd erase updkern
mtd write openwrt-mxs-uImage updkern
fw_setenv filesize_kernel $(printf %x $(stat -c %s openwrt-mxs-uImage))
mtd erase updfdt
mtd write TestTest.dtb updfdt
fw_setenv filesize_fdt $(printf %x $(stat -c %s TestTest.dtb))

А из бутлоадера
Код
"nand read ${loadaddr} updfdt 0x40000;"
"nand erase.part fdt;"
"nand write ${loadaddr} fdt 0x40000;"
"nand read ${loadaddr} updkern 0x500000;"
"nand erase.part kernel;"
"nand write ${loadaddr} kernel 0x500000;"
"ubi part root; "
"ubi read ${loadaddr} updroot 0x2A00000; "    
"nand erase.part root; "
"ubi part root; "
"ubi create updroot 0x2A00000; "
"ubi create rootfs 0x2A00000; "
"ubi create rootfs_data; "
"ubi write ${loadaddr} rootfs 0x2A00000"

Меня интересуют механизмы работы команд mtd, nand, ubi (проверяют ли они бэдблоки, надо ли следить, что они записали).
Например, нет команды mtd read в OpenWrt, и не проверить, правильно ли все записалось. Или как узнать, все ли бутлоадер правильно прочтет, если в разделе есть так любимые NAND-ом бэдблоки.
Нормально ли то, что я копирую весь раздел операцией read/write а не размер файла(понятно, что это медленнее, но что будет происходить при наличии бэдблоков)?

P.S. В Openwrt есть еще команда nandwrite. Может, ее применять вместо mtd write?

P.P.S Посмотрел в коде mtd и nandwrite, вроде, есть проверка бэдблоков при записи.
alx2
Цитата(vgovseychuk @ Mar 17 2016, 14:06) *
Вообще да, можно и так.
Но это же каждый раз надо вписывать в скрипт, какие пакеты и файлы ты обновлял.

Не понял, о каком скрипте Вы говорите.
Возможно, Вы не совсем понимаете, как работают менеджеры пакетов. В системе имеется список пакетов, установленных в текущий момент. При необходимости обновиться менеджер пакетов скачивает из репозитория свежий список пакетов и сравнивает с установленными. Если он видит в списке пакет более поздней версии, чем установленный, то новый пакет скачивается и устанавливается. Все это (и многое другое, я тут сильно упростил процесс) выполняет готовый менеджер пакетов, Вам как разработчику об этом заботиться не надо, разве что не забывать менять версию пакета (да и это можно автоматизировать, у меня версии пакетов формируются автоматически из ревизии SVN)...

Цитата(vgovseychuk @ Mar 17 2016, 16:09) *
Например, нет команды mtd read в OpenWrt, и не проверить, правильно ли все записалось.

Хм... Да, mdt read нет. Но чем Вас не устраивает mtd verify?

Цитата(vgovseychuk @ Mar 17 2016, 16:09) *
Или как узнать, все ли бутлоадер правильно прочтет, если в разделе есть так любимые NAND-ом бэдблоки.

Смотрите документацию/код вашего бутлоадера. Вы, кстати, не сказали, каким бутлоадером пользуетесь. Например u-boot может читать как с учетом, так и без учета бэдблоков. В вашем случае, очевидно, бэдблоки надо учитывать, поэтому вместо nand read следует использовать nand read.jffs2 (если у Вас u-boot). То же самое касается nand write.

Цитата(vgovseychuk @ Mar 17 2016, 16:09) *
Нормально ли то, что я копирую весь раздел операцией read/write а не размер файла(понятно, что это медленнее, но что будет происходить при наличии бэдблоков)?

В общем случае - не нормально. Это может быть нормально, если целевой раздел (куда мы копируем) больше размера копируемых данных, и даже при наличии бэдблоков данные в него заведомо влезут. Иначе, если в процессе записи будет пропуск бэдблока, запись "вылезет" за пределы раздела. У Вас здесь, кстати, вообще какая-то путаница с размерами: в первом сообщении Вы пишете, что размер раздела fdt 128k. А теперь Вы пишете в него данные размером 0x40000, то есть 256k! sm.gif Надеюсь, это не ошибка, а Вы просто поменяли разбивку...

Цитата(vgovseychuk @ Mar 17 2016, 16:09) *
P.S. В Openwrt есть еще команда nandwrite. Может, ее применять вместо mtd write?

Это - на Ваш вкус. Лично я именно nandwrite использую для обновления ядра.

И еще вопрос - зачем Вы fdt и ядро переписываете дважды (через промежуточные разделы)? С файловой системой понятно - Вы не можете переписать ее пока она смонтирована. Но с fdt и kernel-то какая проблема? Вы не перемудрили ли здесь?
vgovseychuk
Цитата(alx2 @ Mar 18 2016, 09:36) *
Не понял, о каком скрипте Вы говорите.
Скрипт для обновления изначальных конфигов, например, или добавления новых файлов. В общем для тех файлов, которые не охвачены менеджером пакетов. Я понимаю, что по-хорошему все файлы должны генериться тем или иным пакетом, но я до этого пока не дошел и почти вручную меняю некоторые конфиги.

Цитата(alx2 @ Mar 18 2016, 09:36) *
Вы, кстати, не сказали, каким бутлоадером пользуетесь ... В вашем случае, очевидно, бэдблоки надо учитывать, поэтому вместо nand read следует использовать nand read.jffs2 (если у Вас u-boot).
Пользуюсь U-Boot 2014.10. Не знал, что есть функции nand read(write).jffs2. Думал, что nand write учитывает bad, а write.raw как раз пишет без них. Буду смотреть и пробовать.

Цитата(alx2 @ Mar 18 2016, 09:36) *
Иначе, если в процессе записи будет пропуск бэдблока, запись "вылезет" за пределы раздела.
Вот, это и подозревал, спасибо, исправлю

Цитата(alx2 @ Mar 18 2016, 09:36) *
зачем Вы fdt и ядро переписываете дважды (через промежуточные разделы)
Да, явно перемудрил

И еще один вопрос про чтение/запись:
Как пример, у меня есть разделы: и vol2 и они "физические", т.е. их видно в mtdparts в U-Boot, и на разделе vol2 есть логические разделы UBI (vol2_ubi1, на котором root ubifs, и vol2_ubi2, куда я пишу обновление).
Если я пишу из линукса в vol2_ubi2:
Код
mtd write rootfs.img vol2_ubi2
fw_setenv filesize_rootfs $(printf %x $(stat -c %s rootfs.img))

и в vol1:
Код
mtd write rootfs.img vol1
fw_setenv filesize_rootfs $(printf %x $(stat -c %s rootfs.img))

то как они запишутся и как их считать правильно в оперативку из U-Boot?
vol1 как nand с учетом bad, а vol2_ubi2 как UBI?

P.S. Большое спасибо!
vgovseychuk
Цитата(alx2 @ Mar 18 2016, 09:36) *
Например u-boot может читать как с учетом, так и без учета бэдблоков. В вашем случае, очевидно, бэдблоки надо учитывать, поэтому вместо nand read следует использовать nand read.jffs2 (если у Вас u-boot). То же самое касается nand write.

Посмотрел код U-Boot (cmd_nand.c). Просто nand read(write) тоже учитывает бэдблоки: (в районе 690 строки)
Код
ret = nand_read_skip_bad(nand, off, &rwsize,
                             NULL, maxsize,
                             (u_char *)addr);


Цитата(vgovseychuk @ Mar 18 2016, 11:39) *
как они запишутся и как их считать правильно в оперативку из U-Boot?
vol1 как nand с учетом bad, а vol2_ubi2 как UBI?

Методом проверки на своем девайсе (как раз бэдблок в root) выяснил, что вроде все так.
Только есть нюанс: если мы записываем из линукса файл в UBI, и передаем в переменную бута его размер(как в линуксе), этот размер не сойдется с размером для убута.
В итоге при перезаписи целостность не сохранится и как минимум получаем предупреждение:
Код
UBI warning: ubi_io_read: error -74 (ECC error) while reading 2048 bytes from PEB 1206:2048, read only 2048 bytes, retry
[    3.319056] UBI error: ubi_io_read: error -74 (ECC error) while reading 2048 bytes from PEB 1206:2048, read 2048 bytes
[    3.329885] CPU: 0 PID: 1 Comm: swapper Not tainted 3.18.23 #73
[    3.335829] Backtrace:
....


Итог: переразметил так:
Код
----------------------------------------------------------------------
      |bootloader|  fdt   |  kernel  |   updroot  |       root       |
MTD   |    5M    |  256k  |    5M    |     40M    |        -         |
----------------------------------------------------------------------
                                                  |rootfs|rootfs_data|
UBI                                               |  40M |     -     |
----------------------------------------------------------------------
alx2
Цитата(vgovseychuk @ Mar 18 2016, 17:18) *
Посмотрел код U-Boot (cmd_nand.c). Просто nand read(write) тоже учитывает бэдблоки: (в районе 690 строки)

Да, верно. В 2014.10 просто read бэдблоки пропускает. Я использую другую версию, там просто read не пропускает...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.