ホーム  |  製品 & サービス   |  サポート & ダウンロード  |  開発者向け情報  |  お問い合わせ
jffs2 を使う

JFFS2 を使う方法と、デバッグのtipsを書き留めておきます。

 

JFFS2カーネルコンフィグレーションパラメータと意味

特に難しい設定が必要なわけではありませんが、JFFS2はMTDに依存するため、MTDの設定も気にする必要があります。

JFFS2 に関連するコンフィグレーションパラメータ(2.6.27) のヘルプを日本語訳しました。

 

ホストでの作業

テスト用に、コンパクトなJFFS2形式のファイルシステムを扱う例を書きます。
まずはホストマシンでファイルシステムを作ります。
$ sudo apt-get install mtd-tools     <- mkfs.jffs2 をインストールするため

$ mkdir testRootFS
$ echo "test file in jffs2" > ./testFS/test.txt
$ mkfs.jffs2 -o jffs2_FS.bin -p -r ./testFS/

$ file jffs2_FS.bin 
jffs2_FS.bin: Linux jffs2 filesystem data little endian

$ ls -l jffs2_FS.bin 
-rw-r--r-- 1 hal hal 65536 2009-09-29 15:59 jffs2_FS.bin
mkfs.jffs2 のオプション -p は、データの残り部分を 0xff で埋めるためのオプションです。 -r は、ディレクトリをまるまるファイルシステムにする場合に指定するオプションです。
上記は little endian の ARM 向けの手順です。MicroBlaze のような big endian のシステムで JFFS2 を使う場合は、オプション -b が必要です。
 
ls するとわかりますが、出来上がったファイルシステムのサイズは非常に小さく、わずか64kしかありません。
しかし、実際にこのファイルシステムが利用出来る領域は、ファイルシステムを配置する mtd のサイズに依存します。
たとえば 1M の容量がある mtdblock2 に JFFS2 のファイルシステムを配置しマウントした場合、jffs2 で扱える領域は1Mになります。64k ではありません。
 

ARM9 CPU カードからマウントする

64k のファイルシステムを、/dev/mtdblock2 に配置します。
BLANCA の ARM9 CPU カードを使う場合、samba で書き込みをするのが手っ取り早いです。
0x10700000 から、jffs2_FS.bin を書き込むとします。カーネルの起動引数で MTD のパーティショニングをしているので、kernel の起動引数を以下のように修正します。
< #define LINUX_CMD_LINE  "mem=64M console=ttyS0,115200
                     mtdparts=physmap-flash.0:2m(kernel),5m(user)
                     root=/dev/mtdblock1 ro init=/bin/msh"
> #define LINUX_CMD_LINE  "mem=64M console=ttyS0,115200
                     mtdparts=physmap-flash.0:2m(kernel),5m(user),1m(user2)
                     root=/dev/mtdblock1 ro init=/bin/msh"
 
BLANCA ARM9 CPU カード上で kernel 起動後、以下のようにしてマウントします。
# mount -n -o remount,rw /dev/root /
# mount -t proc /proc /proc
# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00200000 00010000 "kernel"
mtd1: 00500000 00010000 "user"
mtd2: 00100000 00010000 "user2"
# mkdir /mnt
# mount -t jffs2 /dev/mtdblock2 /mnt
# ls /mnt
test.txt
#

 

JFFS2をうまく使えない場合

JFFS2は、ディレクトリエントリや inode などの「ノード」の集まりで構成されており、各ノードのヘッダには、ヘッダ自身のCRCやデータに対するCRCが含まれています。
これらのCRC値は頻繁にチェックされ、不正があるとコンソール上にワーニングが表示されます。

特におかしな使い方をするわけでもないのにCRCや JFFS2 の magic が壊れるような場合、flash rom からの read がうまくいっていない可能性が疑われます。
この場合は、flash rom コントローラの設定の見直しが必要です。

以下は、私がJFFS2を使う際に利用した debug の tips です。

 

  • flash rom に書かれている JFFS2 の中身を全部読み出す

read が悪いか write が悪いかの判断材料になります。
ちなみに、JFFS2 を1度でも mount すると、JFFS2 の配置された flash rom に node 情報が強制的に書き込まれますが、これにはタイムスタンプなどは含まれません。
# dd if=/dev/mtdblock2 of=readJFFS2.bin
2048+0 records in
2048+0 records out
# od -x readJFFS2.bin | head
0000000     1985    2003    000c    0000    b0b1    e41e    1985    e001
0000020     0030    0000    be78    fa3e    0001    0000    0000    0000
0000040     0002    0000    81ac    ffff    0808    0000    a34b    bfd8
0000060     9b12    d3eb    6574    7473    742e    7478    1985    e002
0000100     0062    0000    0bff    1dae    0002    0000    0001    0000
0000120     81a4    0000    03e9    03e9    001e    0000    81ac    ffff
0000140     81ac    ffff    81ac    ffff    0000    0000    001e    0000
0000160     001e    0000    0000    0000    3714    ca32    8c8b    27a6
0000200     6874    7369    6920    2073    6574    7473    6620    6c69
0000220     2065    6e69    6a20    6666    3273    6620    0a73    ffff
#

 

  • flash rom から読み出した値を毎回チェックする

毎回2度読みし、読んだ値を CRC32 にかけて比較することで、read がうまくいっているかチェック出来ます。
BLANCA ARM9 CPU カードを使う場合、以下のようにソースを修正することでこの検証が可能になります:

diff -r ./drivers/mtd/chips/cfi_cmdset_0002.c /home/hal/sam91/linux-2.6.27/d
rivers/mtd/chips/cfi_cmdset_0002.c
38a39,40
> #include <linux/crc32.h>
>
905c907,916
<       ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
---
>       {
>           uint32_t crc1, crc2;
>           ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
>           crc1 = crc32( 0, buf, thislen );
>           ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
>           crc2 = crc32( 0, buf, thislen );
>           if ( crc1 != crc2 ) {
>               printk( "********************* crc err at 0x%08X, %d\n", ofs, thislen );
>           }
>       }

diff -r ./drivers/mtd/mtdblock.c /home/hal/sam91/linux-2.6.27/drivers/mtd/mt
dblock.c
20a21,22
> #include <linux/crc32.h>
>
246c248,260
<   return do_cached_read(mtdblk, block<<9, 512, buf);
---
>   int ret;
>   uint32_t crc1, crc2;
>
> //    printk( "mtdblock_readsect 0x%X\n", block<<9 );
>
>   do_cached_read(mtdblk, block<<9, 512, buf);
>   crc1 = crc32( 0, buf, 512 );
>   ret = do_cached_read(mtdblk, block<<9, 512, buf);
>   crc2 = crc32( 0, buf, 512 );
>   if ( crc1 != crc2 ) {
>       printk( "********************* crc err at 0x%08X\n", block );
>   }
>   return ret;

  • tmpfs

dd で /dev/mtdblock2 をまるまる読むと容量が大きいため、仮想メモリベースの tmpfs を使うのも良いかもしれません。
tmpfs は利用するための準備コストが低いというメリットがあります。以下のようにして、簡単に利用可能です。
(カーネルコンフィグレーションの File systems -> Virtual memory file system support にチェックが必要です)

# mount -t tmpfs none /tmp -o size=5m
# df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/root                 4955      4281       418  91% /
/dev/mtdblock2            1024       196       828  19% /mnt
none                      5120         0      5120   0% /tmp


  • ホストマシンで JFFS2を mount する

ホストマシン上でも、JFFS2 ファイルシステムを mount することが可能です。また、/dev/mtdblock0 から、逆に dd で読み出すことも可能です。
読み出したデータは、ホストでも ARM9 CPU カードでも同じになるはずです。同じかどうかの検証は md5sum コマンドで可能です。

$ sudo modprobe mtdblock
$ sudo modprobe mtdram erase_size=64 total_size=1024
$ sudo dd if=jffs2_rootFS.bin of=/dev/mtdblock0
$ mount -t jffs2 /dev/mtdblock0 mnt/

$ sudo dd if=/dev/mtdblock0 of=readOut.bin