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のサイズは不定で、物理メモリの許す限り増えていくと言う訳だ。




