ramfs文件系统,利用VFS自身结构形成的内存文件系统。RAMFS没有自己的文件存储结构,他的文件存储于page cache 中,目录结构由dentry链表本身描述,文件则由VFS的inode结构本身描述;从ramfs可看出,VFS本质上可以看成一种给予内存的文件系统,它统一了文件在内核中的表示方式并对磁盘文件进行缓冲;
1.file_system_type:
static struct file_system_type ramfs_fs_type = { .name = "ramfs", //文件系统名 .get_sb = ramfs_get_sb, //读取超级块接口,该函数分配一个新的超级块对象并初始化它 .kill_sb = ramfs_kill_sb, //删除超级块的方法 };
2.注册ramfs文件系统
/fs/ramfs/inode.c:line295
static int __init init_ramfs_fs(void) { return register_filesystem(&ramfs_fs_type); }
3.超级块的建立和初始化:
/fs/ramfs/inode.c:line265
int ramfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { return get_sb_nodev(fs_type, flags, data, ramfs_fill_super, mnt);
}
get_sb_nodev根据系统类型,创建超级块,并填充该结构;
linux/fs/super.c
int get_sb_nodev(struct file_system_type *fs_type,int flags, void *data,int (*fill_super)(struct super_block *, void *, int),struct vfsmount *mnt) { int error; struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);//分配超级块结构 if (IS_ERR(s)) return PTR_ERR(s); s->s_flags = flags; error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);//填充超级块结构 if (error) { deactivate_locked_super(s); return error; } s->s_flags |= MS_ACTIVE; simple_set_mnt(mnt, s); return 0; }
/fs/ramfs/inode.c:line217
ramfs_fill_super
static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
{
struct inode *inode = NULL;
struct dentry *root;
sb->s_fs_info = fsi;
sb->s_op = &ramfs_ops;//指向超级块的操作 static const struct super_operations ramfs_ops;
inode = ramfs_get_inode(sb, S_IFDIR | fsi->mount_opts.mode, 0);//创建inode节点
root = d_alloc_root(inode); //创建“/”根目录
sb->s_root = root;
}
4. inode操作
/fs/ramfs/inode.c:line55
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_mapping->a_ops = &ramfs_aops; inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info; mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER); mapping_set_unevictable(inode->i_mapping); 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的索引节点操作 inode->i_fop = &ramfs_file_operations; //inode的缺省文件操作 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; }
具体的文件操作
const struct file_operations ramfs_file_operations = { .mmap = ramfs_nommu_mmap, .get_unmapped_area = ramfs_nommu_get_unmapped_area, .read = do_sync_read, .aio_read = generic_file_aio_read, .write = do_sync_write, .aio_write = generic_file_aio_write, .fsync = simple_sync_file, .splice_read = generic_file_splice_read, .splice_write = generic_file_splice_write, .llseek = generic_file_llseek, };
4.文件操作
/* ramfs文件系统的文件操作接口 */
static 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, };
5.目录操作
/* ramfs文件系统的目录操作接口 */ static struct super_operations ramfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, };
6.低级页操作
struct address_space_operations ramfs_aops = { 文件的低级页操作接口 .readpage = simple_readpage, 读文件页块 .prepare_write = simple_prepare_write, 准备从用户写文件页块 .commit_write = simple_commit_write 从用户写文件页块完成 };
int simple_readpage(struct file *file, struct page *page)
{
void *kaddr;
将文件页块读入page所描述的页面
if (PageUptodate(page))
goto out;
当lseek()在文件中造成空洞时,会运行到这里
kaddr = kmap_atomic(page, KM_USER0);
memset(kaddr, 0, PAGE_CACHE_SIZE);页面清零
kunmap_atomic(kaddr, KM_USER0);
flush_dcache_page(page);
SetPageUptodate(page);标记为最新
out:
unlock_page(page);
return 0;
}
int simple_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
/* 系统将用户数据拷贝到page之前调用此函数, ;offset是文件指针在页内的起始位置,to是在页内的终止位置 ;表示系统将要在page从offset到to的位置上拷贝用户数据.*/
if (!PageUptodate(page)) {
if (to - from != PAGE_CACHE_SIZE) {
对于RAMFS,当lseek()在文件中产生空洞时,运行到这里
void *kaddr = kmap_atomic(page, KM_USER0);取页面描述结构(page)所描述页面的地址
memset(kaddr, 0, from);
memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
flush_dcache_page(page);
kunmap_atomic(kaddr, KM_USER0);
}
SetPageUptodate(page);
}
return 0;
}
int simple_commit_write(struct file *file, struct page *page,
unsigned offset, unsigned to)
{
系统将用户数据拷贝到page之后调用此函数
struct inode *inode = page->mapping->host;取page所代表的文件,mapping结构是inode的一部分
page->index表示该page在文件中的页块号,to是该页的终止偏移量
loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
/*
* No need to use i_size_read() here, the i_size
* cannot change under us because we hold the i_mutex.
*/
if (pos > inode->i_size)// inode->i_size为文件的尺寸
i_size_write(inode, pos);如果文件的写入的终止位置大于文件原来的尺寸,则更新i_size的值
set_page_dirty(page);
return 0;
}
const struct file_operations ramfs_file_operations = {
.read = generic_file_read,数据文件的通用高级读函数
.write = generic_file_write,数据文件的通用高级写函数
.mmap = generic_file_mmap,数据文件的通用高级内存映射函数
.fsync = simple_sync_file,
.sendfile = generic_file_sendfile,
.llseek = generic_file_llseek,
};
const struct file_operations simple_dir_operations = {
.open = dcache_dir_open,
.release = dcache_dir_close,
.llseek = dcache_dir_lseek,
.read = generic_read_dir,返回-EISDIR错误的函数
.readdir = dcache_readdir,目录文件的高级读目录函数
.fsync = simple_sync_file,
};
static 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,
};
static int ramfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
{
在目录dir内创建一个以dentry为目录项的普通文件
return ramfs_mknod(dir, dentry, mode | S_IFREG, 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);//创建inode
int error = -ENOSPC;
if (inode) {
if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
inode->i_mode |= S_ISGID;
}
d_instantiate(dentry, inode); //把dentry加入到inode
dget(dentry); /* Extra count - pin the dentry in core */
error = 0;
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
}
return error;
}
struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
static struct dentry_operations simple_dentry_operations = {
.d_delete = simple_delete_dentry,
};
对于ramfs,所有的目录项都已经在dentry链表中,只有企图寻找VFS中不存在的项时,才会运行到这/
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
将dentry加入目录链表,置空的inode,表示No such file ordirectories,就是说生成一个"虚"的目录项, ;之所以这样,为了加速create过程
dentry->d_op = &simple_dentry_operations;
d_add(dentry, NULL);
return NULL;
}
int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
; 在目录dir内创建一个以dentry所表示目录项的链接,指向old_entry目录项所表示的文件
if (S_ISDIR(inode->i_mode)) return -EPERM;
inode->i_nlink++; 文件的连接数,为0表示文件已删除
atomic_inc(&inode->i_count); /* New dentry reference */
dget(dentry); /* Extra pinning count for the created dentry */
d_instantiate(dentry, inode); 使目录项dentry指向文件inode
return 0;
}
; 在目录dir内删除dentry所表示的目录项
int simple_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
inode->i_nlink--;
dput(dentry); // 根据引用计数来删除目录项
return 0;
}
static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
{
struct inode *inode;
int error = -ENOSPC;
inode = ramfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
; 在目录dir中创建名称为symname的符号链接文件目录项 ; 符号链接的名称作为符号链接文件的数据体存放在page cache中
if (inode) {
int l = strlen(symname)+1;
error = page_symlink(inode, symname, l);
if (!error) {
if (dir->i_mode & S_ISGID)
inode->i_gid = dir->i_gid;
d_instantiate(dentry, inode);
dget(dentry);
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
} else
iput(inode);
}
return error;
}
static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
; 在目录dir内创建一个以dentry为目录项的目录
int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
if (!retval)
dir->i_nlink++;
return retval;
}
int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
struct inode *inode = old_dentry->d_inode;
int they_are_dirs = S_ISDIR(old_dentry->d_inode->i_mode);
if (!simple_empty(new_dentry))
return -ENOTEMPTY;
if (new_dentry->d_inode) {
simple_unlink(new_dir, new_dentry);
if (they_are_dirs)
old_dir->i_nlink--;
} else if (they_are_dirs) {
old_dir->i_nlink--;
new_dir->i_nlink++;
}
; 将目录old_dir内的目录项改名为new_dir目录中的new_dentry所描述的目录项
old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime =
new_dir->i_mtime = inode->i_ctime = CURRENT_TIME;
return 0;
}
struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
{
struct inode * inode = new_inode(sb);//创建新的inode
//初始化inode
if (inode) {
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_mapping->a_ops = &ramfs_aops; //底层操作接口
inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
default:
init_special_inode(inode, mode, dev); //与设备文件相联的inode函数
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) */
inode->i_nlink++;
break;
case S_IFLNK:
inode->i_op = &page_symlink_inode_operations; //连接操作接口
break;
}
}
return inode;
}
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
inode->i_mode = mode;
if (S_ISCHR(mode)) {如果为字符设备文件,提供字符设备的inode函数
inode->i_fop = &def_chr_fops;
inode->i_rdev = rdev;
} else if (S_ISBLK(mode)) {如果为块设备文件,提供块设备的inode函数
inode->i_fop = &def_blk_fops;指向块设备描述结构
inode->i_rdev = rdev;
} else if (S_ISFIFO(mode))如果为FIFO文件,提供FIFO的inode函数
inode->i_fop = &def_fifo_fops;
else if (S_ISSOCK(mode))如果为SOCK文件,提供SOCK的inode函数
inode->i_fop = &bad_sock_fops;
else
printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o)\n",
mode);
}