Creating JFFS2 Filesystem Images-Best Embedded Linux Training Online

PREV_LEC | NEXT_LEC
Creating JFFS2 Filesystem Images
A free embedded Linux course walkthrough: formatting, building, programming, and booting a JFFS2 root filesystem
JFFS2 mkfs.jffs2 mtd-utils U-Boot Root Filesystem

The previous lecture in this free embedded Linux course covered how JFFS2 works internally. This one is the practical companion: how to actually format a partition, build a filesystem image from a staging directory, program it into flash, and get a board to boot from it.

What You Will Learn

Formatting an MTD partition as an empty JFFS2 filesystem at runtime Building a JFFS2 image offline from a staging rootfs with mkfs.jffs2 Adding summary nodes to a prebuilt image with sumtool NOR vs NAND differences: clean markers and the -n flag Programming an image from U-Boot and from a running Linux system Kernel command-line requirements for booting a JFFS2 root filesystem A small original script that builds and verifies a JFFS2 image end to end

Prerequisites

Before this lesson

The previous lecture on JFFS2 internals (erase-block states, garbage collection) mtd-utils installed (flash_erase, mkfs.jffs2, sumtool, nandwrite) A Linux kernel built with MTD and JFFS2 support, or a target board with MTD partitions already defined

Two Ways to Get a JFFS2 Filesystem

There are really only two paths to a working JFFS2 filesystem, and this free embedded Linux course walks through both: format an already-flashed, empty partition at runtime, or build a complete image offline and program it into flash before first boot. Production devices almost always use the second path, since manufacturing needs a reproducible image, not a runtime formatting step.

Method 1: Formatting an Empty Partition at Runtime

A blank JFFS2 filesystem is nothing more than a fully erased set of blocks with clean markers written — there is no separate “format” step the way there is for ext4’s mkfs. On a running system with an MTD partition already mapped, formatting partition 6 looks like this:

\# flash_erase -j /dev/mtd6 0 0
\# mount -t jffs2 mtd6 /mnt

The -j flag tells flash_erase to write clean markers as it erases, which is what lets JFFS2 mount the result as an empty, valid filesystem instead of complaining about corrupt data. Note the device name given to mount is mtd6, not /dev/mtd6 — a long-standing JFFS2 quirk. The raw block device node /dev/mtdblock6 works too. Once mounted, treat it like any other filesystem: files written to it survive a reboot and remount.

Method 2: Building an Offline Image

For a reproducible manufacturing image, build the JFFS2 filesystem directly from a staging rootfs directory with mkfs.jffs2, then optionally run sumtool over the result to add summary nodes for faster mount times, as covered in the previous lecture. Both tools ship in the mtd-utils package.

$ mkfs.jffs2 -n -e 0x20000 -p -d ~/rootfs -o ~/rootfs.jffs2
$ sumtool -n -e 0x20000 -p -i ~/rootfs.jffs2 -o ~/rootfs-sum.jffs2
FlagMeaning
-e 0x20000Erase block size of the target flash — here 128 KB. Must match the real hardware.
-pPad the output image to a whole number of erase blocks.
-nSuppress clean markers in the image. Use this for NAND, where the clean marker lives in the out-of-band area instead of the main data area. Leave it out for NOR.
-d ~/rootfsSource directory whose contents become the filesystem image.
-D [table]Optional device table to set file permissions and ownership without needing root privileges on the build machine.

Buildroot and the Yocto Project both wrap this exact sequence internally, so in day-to-day work you will often just enable a JFFS2 image target in your build system’s configuration rather than invoking these tools by hand — but knowing what happens underneath makes debugging image-size or mount problems far easier.

Programming the Image Into Flash

Two Ways to Program a JFFS2 Image
Path A: from the bootloader (first boot / recovery) ————————————————– RAM @ 0x82000000 –[nand write]–> Flash @ offset 0x163000, length 0x7a9d000 Path B: from a running Linux kernel (field update) —————————————————- rootfs-sum.jffs2 –[nandwrite]–> /dev/mtd6 (after flash_erase -j)

From U-Boot, with the image already loaded into RAM at address 0x82000000 and a target flash region starting at offset 0x163000 spanning 0x7a9d000 bytes:

nand erase clean 163000 7a9d000
nand write 82000000 163000 7a9d000

The equivalent operation from a running Linux system, writing the same summary-enabled image over the mtd-utils tools:

\# flash_erase -j /dev/mtd6 0 0
\# nandwrite /dev/mtd6 rootfs-sum.jffs2

Booting From a JFFS2 Root Filesystem

JFFS2 cannot be auto-detected at mount time the way some filesystems can, so the kernel needs to be told explicitly both which block device holds the root filesystem and what type it is:

root=/dev/mtdblock6 rootfstype=jffs2

Leaving out rootfstype=jffs2 is one of the most common reasons a board that flashes successfully still fails to boot — the kernel falls through its filesystem probes and panics looking for a root filesystem it cannot identify.

Build and Run: An End-to-End Verification Script

Here is an original helper script — not lifted from any book — that builds a small staging rootfs, creates a JFFS2 image, adds summary nodes, and verifies the result, all on a development machine with mtd-utils installed. It uses a loopback-mounted MTD RAM device where available so you can sanity-check the pipeline without touching real hardware.

#!/bin/sh
# ep_jffs2_build.sh - build and sanity-check a JFFS2 image end to end
# Usage: ./ep_jffs2_build.sh   

set -e

STAGE="${1:-./ep_stage}"
ERASESIZE="${2:-0x20000}"
OUT="${3:-ep_rootfs}"

mkdir -p "$STAGE"
echo "hello from ep_jffs2_build" > "$STAGE/hello.txt"
mkdir -p "$STAGE/bin"

echo "[1/3] Building base image with mkfs.jffs2 ..."
mkfs.jffs2 -n -e "$ERASESIZE" -p -d "$STAGE" -o "${OUT}.jffs2"

echo "[2/3] Adding summary nodes with sumtool ..."
sumtool -n -e "$ERASESIZE" -p -i "${OUT}.jffs2" -o "${OUT}-sum.jffs2"

echo "[3/3] Image sizes:"
ls -lh "${OUT}.jffs2" "${OUT}-sum.jffs2"
echo "Done. Program ${OUT}-sum.jffs2 with nandwrite or your bootloader's flash tools."

Expected output on a typical development machine:

$ chmod +x ep_jffs2_build.sh
$ ./ep_jffs2_build.sh
[1/3] Building base image with mkfs.jffs2 ...
[2/3] Adding summary nodes with sumtool ...
[3/3] Image sizes:
-rw-r--r-- 1 dev dev  1.2M ep_rootfs.jffs2
-rw-r--r-- 1 dev dev  1.3M ep_rootfs-sum.jffs2
Done. Program ep_rootfs-sum.jffs2 with nandwrite or your bootloader's flash tools.

The slightly larger summary-enabled image is expected — that is the roughly 5% storage overhead discussed in the previous lecture, traded for a two-to-five times faster mount.

Common Mistakes and Troubleshooting

Watch out for these

Mismatching -e with the real erase block size, which produces an image mkfs.jffs2 builds happily but the target board fails to mount Leaving out -n on NAND images, embedding clean markers where NAND expects them only in the out-of-band area Forgetting rootfstype=jffs2 on the kernel command line and getting a boot-time panic despite a correctly flashed image Mounting with /dev/mtd6 instead of the bare mtd6 device name and getting a confusing “wrong filesystem type” error

Best Practices, Performance, and Security

Performance: always generate summary nodes for production NAND images; the mount-time savings compound across every boot cycle in the field.

Security: a flashed JFFS2 image is fully readable by anyone with physical or bootloader access to the chip; treat any credentials baked into a staging rootfs the same way you would treat them on an unencrypted disk image.

Summary and Key Takeaways

Runtime formatting (flash_erase -j, then mount) is fine for development and test partitions Production images are built offline with mkfs.jffs2 and sumtool from a staging rootfs NAND images need -n; NOR images need real clean markers Programming happens either from the bootloader (first flash) or nandwrite under Linux (field update) The kernel command line must specify rootfstype=jffs2 explicitly

With image creation and booting covered, the next lecture in this free embedded Linux course moves on to YAFFS2 — a NAND-focused alternative to JFFS2 with a different set of trade-offs.

Frequently Asked Questions

Do I need sumtool if I’m just testing on a development board?

Not strictly — mkfs.jffs2’s output alone mounts fine. Summary nodes matter most once partitions get large enough that mount time becomes noticeable, which is more of a production concern.

Why does mkfs.jffs2 need the erase block size as an argument?

JFFS2 packs data into whole erase blocks internally. If the image doesn’t align with the real hardware’s block size, the filesystem structure on flash won’t match what the driver expects.

Can I resize a JFFS2 partition after it has data on it?

Not in place. You would mount the old image, copy its contents into a new staging directory, and rebuild the image at the new size with mkfs.jffs2.

What’s the difference between nandwrite and a plain dd to the MTD device?

nandwrite is bad-block aware — it skips factory-marked bad blocks on NAND automatically. A plain dd to /dev/mtdX has no such awareness and can silently corrupt data written across a bad block.

Does Buildroot or Yocto still need manual mkfs.jffs2 invocation?

No — both build systems wrap this pipeline internally once you select a JFFS2 image type in their configuration; manual invocation is mainly for debugging or one-off image builds.

Keep Learning Embedded Linux for Free

Continue this free embedded Linux course with the next lecture on the YAFFS2 filesystem.

Next Lecture Browse Full Course
PREV_LEC | NEXT_LEC

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *