Jump to content

    
Sign in to follow this  
vgovseychuk

Sysupgrade / switch root to ram

Recommended Posts

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

 

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

В 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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this