romfs
Rev.1を表示中。最新版はこちら。
romfsのソースボリュームとその名称から、ramfsに書き込み処理を端折ったものだろう。と認識していた。しかし調べると、ramfsとは根本的に異なるファイルシステムのようである。romfsだからramディスクと言うイメージだが・・・。ramfsとromfsの根本的な違いは、ramfsはストレージを持たないが、romfsはストレージを有することである。ところで通常のHD下でromfsを構築することが可能である。
[root@localhost test]# ls 111 aaa [root@localhost test]# cat 111 1234567890 [root@localhost test]# cat aaa abcdefghijklmn [root@localhost test]# genromfs -f ../romfs.img [root@localhost test]# mount -t romfs -o loop ../romfs.img /dir1 [root@localhost test]# ls /dir1 111 aaagenromfsコマンドでromfsのファイルシステムを作成する。上の場合はext3物理ファイル上に作成したわけだが、当然RAMデバイス上に構築することも可能である。romfsは組み込みシステムの低スペックの用途を目的として導入されたらしい。それだけにそのサイズ、ストレージリソースを最大限に活用するよう実装されている。
書き込み処理が必要でないことは、かかるコーディング量が小さくなるというだけでなく、inode取得にかかるぐちゃぐちゃした処理が必要でない。ファイルフォーマットについては、inodeにかかるブロックが存在しいない。ファイル階層はそのままベタに展開されており、また、それぞれの構成部位の末端は16バイトアライメントで区切られているが、ext2/ext3で言うところのブロックという取り扱いをしていないようである。
以下はromfsの内部フォーマットである。先頭にスーパブロックのromfs_super_blockがあって、次にファイル情報(inode情報)である、romfs_inodeが続き、この後にそのファイルの実態が存在する。このペアーをファイル数に応じて繰り返している。
struct romfs_super_block { __be32 word0; __be32 word1; __be32 size; __be32 checksum; char name[0]; /* volume name */ }; struct romfs_inode { __be32 next; /* low 4 bits see ROMFH_ */ __be32 spec; __be32 size; __be32 checksum; char name[0]; };上記romfs.imgをダンプしてものだ。ファイル名のnameおよびかかる実態は16アライメントされている。
[root@localhost test]# od -tx1z ../romfs.img 0000000 2d 72 6f 6d 31 66 73 2d 00 00 00 c0 82 e5 97 49 >-rom1fs-.......I< | word0 | word1 | size | cheksum | 0000020 72 6f 6d 20 34 63 30 36 39 35 33 63 00 00 00 00 >rom 4c06953c....< | name | ファイル(親ディレクトリ) 0000040 00 00 00 49 00 00 00 20 00 00 00 00 d1 ff ff 97 >...I... ........< | next | spec | size | checksum | 0000060 2e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................< | name | ファイル(カレンドディレクトリ) 0000100 00 00 00 60 00 00 00 20 00 00 00 00 d1 d1 ff 80 >...`... ........< | next | spec | size | checksum | 0000120 2e 2e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................< | name | ファイル(aaa) 0000140 00 00 00 92 00 00 00 00 00 00 00 0f 9e 9e 9e 5f >..............._< | next | spec | size | checksum | 0000160 61 61 61 00 00 00 00 00 00 00 00 00 00 00 00 00 >aaa.............< | name | 0000200 61 62 63 64 65 66 67 68 6a 6a 6b 6c 6d 6e 0a 00 >abcdefghjjklmn..< ファイル(111) 0000220 00 00 00 02 00 00 00 00 00 00 00 0b ce ce ce f3 >................< | next | spec | size | checksum | 0000240 31 31 31 00 00 00 00 00 00 00 00 00 00 00 00 00 >111.............< | name | 0000260 31 32 33 34 35 36 37 38 39 30 0a 00 00 00 00 00 >1234567890......< 0000300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<inode番号はinodeとそのブロック(実データ部)を対応ずけるインデックスである。デバイスファイルのようにブロックを有しないものは、内部的にシーケンスに割り振っていく。roomfsではどのようにしているのだろうか?下記はromfsマウント時にスーパブロックを設定する際にコールされるromfs_fill_super関数である。ここでrootのinode番号を設定している箇所がある。
static int romfs_fill_super(struct super_block *s, void *data, int silent) { : : /* Find the start of the fs */ sz = (ROMFH_SIZE + strnlen(rsb->name, ROMFS_MAXFN) + 1 + ROMFH_PAD) & ROMFH_MASK; s->s_op = &romfs_ops; root = romfs_iget(s, sz); : : return ret; }szは親ディレクトリのオフセットとなり、romfs_iget関数でszをrootのinode番号とするよう設定している。通常はromfs_lookup関数からinodeを取得して、同様にそのオフセット計算しromfs_iget関数でinode番号を設定するようになっている。そしてそのオフセットをromfs_inode_info->i_dataoffsetにセットする。(たぶん)
struct romfs_inode_info { unsigned long i_metasize; /* size of non-data area */ unsigned long i_dataoffset; /* from the start of fs */ struct inode vfs_inode; };そしてromfs_readpage関数で、ストレージからinodeのromfs_inode_info->i_dataoffsetとしてデータを読み込むようになっている。
static int romfs_readpage(struct file *file, struct page * page) { : : offset = page_offset(page); size = i_size_read(inode); filled = 0; result = 0; if (offset < size) { unsigned long readlen; size -= offset; readlen = size > PAGE_SIZE ? PAGE_SIZE : size; filled = romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen); : : } if (filled < PAGE_SIZE) memset(buf + filled, 0, PAGE_SIZE-filled); : : }