Jump to content

    

Sysupgrade / switch root to ram

Привет, Электроникс!

 

Пытаюсь обновиться из-под линукса.

В 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) пишу в пямять по отдельности.

Share this post


Link to post
Share on other sites
В sysupgrade нет поддержки UBI, так что пытаюсь сделать обновление вручную.

Поскольку никто Вам не отвечает, решил вставить реплику.

Сразу скажу, что ответов на ваши конкретные вопросы у меня нет. Но есть другая мысль.

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

 

Еще несколько преимуществ использования пакетов:

- Не надо заново выкачивать и перезаписывать образ всей файловой системы ради крошечного обновления (к примеру, чтобы обновить SSL-сертификат), достаточно одного малюсенького пакетика.

- Перерыв в работе системы отсутствует совсем или минимален - после обновления требуется перезапуск только реально обновившихся компонентов.

- Гибкость - на разных системах может быть разный набор пакетов.

Edited by alx2

Share this post


Link to post
Share on other sites

Вообще да, можно и так.

Но это же каждый раз надо вписывать в скрипт, какие пакеты и файлы ты обновлял.

Может Вы и ответа не получаете именно потому, что выбранным Вами путем мало кто идет?

Я посчитал такой вариант наиболее верным с оглядкой на то, как это сделано, например, в роутерах.

В любом случае, большое спасибо за совет.

Share this post


Link to post
Share on other sites

Сделал полное обновление немного кривым способом, потеряв где-то 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, вроде, есть проверка бэдблоков при записи.

Edited by vgovseychuk

Share this post


Link to post
Share on other sites
Вообще да, можно и так.

Но это же каждый раз надо вписывать в скрипт, какие пакеты и файлы ты обновлял.

Не понял, о каком скрипте Вы говорите.

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

 

Например, нет команды mtd read в OpenWrt, и не проверить, правильно ли все записалось.

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

 

Или как узнать, все ли бутлоадер правильно прочтет, если в разделе есть так любимые NAND-ом бэдблоки.

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

 

Нормально ли то, что я копирую весь раздел операцией read/write а не размер файла(понятно, что это медленнее, но что будет происходить при наличии бэдблоков)?

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

 

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

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

 

И еще вопрос - зачем Вы fdt и ядро переписываете дважды (через промежуточные разделы)? С файловой системой понятно - Вы не можете переписать ее пока она смонтирована. Но с fdt и kernel-то какая проблема? Вы не перемудрили ли здесь?

Share this post


Link to post
Share on other sites
Не понял, о каком скрипте Вы говорите.
Скрипт для обновления изначальных конфигов, например, или добавления новых файлов. В общем для тех файлов, которые не охвачены менеджером пакетов. Я понимаю, что по-хорошему все файлы должны генериться тем или иным пакетом, но я до этого пока не дошел и почти вручную меняю некоторые конфиги.

 

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

 

Иначе, если в процессе записи будет пропуск бэдблока, запись "вылезет" за пределы раздела.
Вот, это и подозревал, спасибо, исправлю

 

зачем Вы 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. Большое спасибо!

Share this post


Link to post
Share on other sites
Например 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);

 

как они запишутся и как их считать правильно в оперативку из 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 |     -     |
----------------------------------------------------------------------

Share this post


Link to post
Share on other sites
Посмотрел код U-Boot (cmd_nand.c). Просто nand read(write) тоже учитывает бэдблоки: (в районе 690 строки)

Да, верно. В 2014.10 просто read бэдблоки пропускает. Я использую другую версию, там просто read не пропускает...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this