Skip to main content.
Navigation:
DENX
>
DULG
>
AN2008_05_ChangingYourRoots
Translations:
Edit
|
Attach
|
Raw
|
Ref-By
|
Printable
|
More
DULG
Sections of this site:
DENX Home
|
DULG
|
ELDK-5
|
Know
|
Training
|
U-Boot
|
U-Bootdoc
Topics
DULG Home
BoardSelect
Manual
FAQ
Application Notes
Changes
Index
List of pages in DULG
Search
---+ Changing Your Roots or How to Switch to a New Root-fs in a Live Linux System ---++ Author This document was written by Detlev Zundel (dzu {at} denx {dot} de). ---++ Context A common problem in embedded devices is to update the firmware on the device itself. In a GNU/Linux system this also includes updating the root filesystem used. There are several possibilities to do this depending on the type and storage location of it. As updating a "hot" filesystem is rather problematic, many solutions use two separate storage areas together with a technique resembling the well known "pointer flip" in programming languages. Usually toggling between the file systems involves rebooting the Linux system, rendering the device non-functional for some time. This application note shows one Linux specific approach to minimize this interval. As always, it is very likely that other approaches will have comparable results. ---++ Theory of operation In order to do the "root flip" multiple times (including unmounting the old root)_all_ references to the old root filesystem must be freed. Minimally this means that all applications need to be stopped (they will have at least a =cwd= on the old root) and restarted later, which is rather easily accomplished. The hard part will be to get =init=, the ancestor of all Unix processes, to free all references to the old root filesystem, including its =cwd= and its connections to =/dev/console= on =stdin=, =stdout= and =stderr=. The neccessary help from the Linux kernel is offered by the =pivot_root(2)= system call: <verbatim> pivot_root() moves the root file system of the calling process to the directory put_old and makes new_root the new root file system of the calling process. </verbatim> Usually this system call is used in the following way (taken from =pivot_root(8)= man page): <verbatim> cd new_root pivot_root . put_old exec chroot . command </verbatim> Note, that this of course only works if the commands are really executed from the init process. This now poses the question on how to use it in the (embedded) common case of =busybox= [1] being the init process. Studying the source code, we find that this case was properly anticipated and can be handled elegantly with a small addition to =/etc/inittab=, namely <verbatim> ~ # grep restart /etc/inittab /dev/console::restart:/sbin/init ~ # </verbatim> This action instructs =init= from =busybox= to reopen =/dev/console= and do an =exec(2)= of =/sbin/init= on reception of =SIGHUP= or =SIGQUIT=. This is exactly what we need, so let's see how this works in practice. For the following demo, we have two (jffs2) root filesystems on /dev/mtdblock4 and /dev/mtdblock5. Currently the former is the active root. The respective =/etc/inittab= files include the entry above and respawn =/bin/application= printing a short message what root filesystem is currently active. Furthermore we have =/new-root= and =/new-root/old-root= directories in both file systems. <verbatim> ~ # mount -t jffs2 /dev/mtdblock5 /new-root ~ # cd /new-root/ /new-root # pivot_root . old-root ~ # umount /old-root/proc ~ # chroot . kill -QUIT 1 The system is going down NOW! Sending SIGTERM to all processes init started: BusyBox v1.7.1 (2008-04-01 21:48:01 MEST) starting pid 97, tty '': '/etc/rc.sh' starting pid 102, tty '': '/bin/application' ### Application running ... (mtd5) starting pid 108, tty '': '/bin/sh' ~ # ls -l /proc/1/fd lrwx------ 1 root root 64 Sep 15 23:30 0 -> /dev/console lrwx------ 1 root root 64 Sep 15 23:30 1 -> /dev/console lrwx------ 1 root root 64 Sep 15 23:30 2 -> /dev/console ~ # mount rootfs on / type rootfs (rw) /dev/mtdblock4 on /old-root type jffs2 (rw) /dev/mtdblock5 on / type jffs2 (rw) proc on /proc type proc (rw) ~ # umount /old-root ~ # process '/bin/application' (pid 102) exited. Scheduling it for restart. starting pid 112, tty '': '/bin/application' ### Application running ... (mtd5) </verbatim> As we can see, after sending the signal, init properly shuts down and restarts from the new root filesystem. Note that we manually unmounted /proc from the old root-filesystem. [1] For this demo, busybox version 1.7.1 from ELDK 4.2 was used.