ramfs
Rev.1を表示中。最新版はこちら。
ramfsはfs/ramfs配下にそのソースがある。中を見るとコーディングの少なさに驚かされる。まるでファイルシステムモジュールのサンプルスケルトンのようで、これでRAMディスクが構築来るのかと。実はramfsというのは、Linuxの要素コンポーネントであるVFSとページキャッシュで成せる技と言える。ユーザが見るファイル構造はVFSのそれを見ている。そしてVFSのストレージはページ゙キャッシュとも言える。ext2/ex3のような物理デバイス下のファイルシステムも、VFSから見ると、ある意味RAMディスクと言えなくはない。そしてその物理デバイスは、そのバックアップと言う風にみると、ramfsの実装が見えてくる。
ファイル処理では、そのinodeオペレーションのコールバック関数がコールされる。inodeを操作するものと、ブロックを操作するものを、ファイルとディレクトリにfile_operations、 inode_operationsとしてそれぞれ定義している。そして実際の物理デバイスとのやり取りとしてはaddress_space_operationsで定義する。
VFSからファイルの読み込みでは、ページキャッシュに目的のデータが無いときのみ、address_space_operationsで設定されるreadpageがコールされる。
下記はディレクトリのinode_operationsで、
static const struct inode_operations ramfs_dir_inode_operations = { .create = ramfs_create, .lookup = simple_lookup, .link = simple_link, .unlink = simple_unlink, .symlink = ramfs_symlink, .mkdir = ramfs_mkdir, .rmdir = simple_rmdir, .mknod = ramfs_mknod, .rename = simple_rename, };ramfs_mkdirはどのようになっているかというと、
static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) { int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0); : } static int ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { struct inode * inode = ramfs_get_inode(dir->i_sb, mode, dev); : : } struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev) { struct inode * inode = new_inode(sb); if (inode) { inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; inode->i_blocks = 0; inode->i_mapping->a_ops = &ramfs_aops; inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info; mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER); inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { default: init_special_inode(inode, mode, dev); break; case S_IFREG: inode->i_op = &ramfs_file_inode_operations; inode->i_fop = &ramfs_file_operations; break; case S_IFDIR: inode->i_op = &ramfs_dir_inode_operations; inode->i_fop = &simple_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); break; case S_IFLNK: inode->i_op = &page_symlink_inode_operations; break; } } return inode; }new_inode関数は、スーパブロックオペレーションのalloc_inodeコールバック関数が定義されているなら、それを、そうでないならkmem_cache_alloc関数としてinodeを取得する。ramfsではalloc_inodeは定義されていない。ext2/ex3なら、ここで、がりがりとinodeを取得の処理となるわけだ。要は実デバイスにかかる処理は行っていないと言う事だ。これは他のコールバック関数についても当てはまる。(たぶん)
それでは、実デバイスとやり取りするaddress_space_operations はどのようになっているのだろうか?
const struct address_space_operations ramfs_aops = { .readpage = simple_readpage, .write_begin = simple_write_begin, .write_end = simple_write_end, .set_page_dirty = __set_page_dirty_no_writeback, };simple_readpage関数はページキャッシュがないということで、ページキャッシュをアロケートして、そのページを引数としてコールされる。simple_readpage関数はpageを0クリアする処理のようで、readでこの関数をコールすれば、結果は0ということだ。実はこの処理で悩んでしまった。これではいくらreadしてもnullしか返ってこないのではと。でもよくよく考えると、ramディスクであり、この関数が呼ばれるということは、すでにwriteでこのファイ内容を作成済みということだ。従ってこのページはすぜにページキャッシュ上にあるわけで、たぶんファイルフォール等のケースで呼ばれる事を想定しての処理ではないかと・・・。
int simple_readpage(struct file *file, struct page *page) { clear_highpage(page); flush_dcache_page(page); SetPageUptodate(page); unlock_page(page); return 0; }write時の場合、simple_write_begin、simple_commit_write、simple_commit_write関数とコールされ、ページキャッシュを獲得し、書き込みデータがページサイズに満たない末端部を0クリアし、inodeにそのサイズを設定し、ページにPG_uptodateおよび汚れているのマークを付けているだけのようである。
上で見てきたようにramfsは完全にページキャッシュに依存した実装になっており、従ってかかる機能はページキャッシュのそれに依存するとも言える。ページキャッシュはメモリーの許す限り獲得される(たぶん)。したがってramfsのサイズは不定で、物理メモリの許す限り増えていくと言う訳だ。