阅读:4647回复:2
ramfs文件系统分析
RAMFS是一个非常巧妙的,利用VFS自身结构而形成的内存文件系统.
RAMFS没有自已的文件存储结构,它的文件存储于page cache中, 目录结构由dentry链表本身描述,文件则由VFS的inode结构本身描述. 从RAMFS可看出,VFS本质上可看成一种内存文件系统, 它统一了文件在内核中的表示方式并对磁盘文件系统进行缓冲. 代码摘录分析如下: /* ramfs文件系统类型 */ tatic struct file_system_type ramfs_fs_type = { .name = "ramfs", .get_sb = ramfs_get_sb, 读取超级块接口 .kill_sb = kill_litter_super, }; /* rootfs文件系统(根文件系统) 该模块应该是放到cpio文件*/ static struct file_system_type rootfs_fs_type = { .name = "rootfs", .get_sb = rootfs_get_sb, .kill_sb = kill_litter_super, }; 注册ramfs文件系统 static int __init init_ramfs_fs(void) { return register_filesystem(&ramfs_fs_type); } static void __exit exit_ramfs_fs(void) { unregister_filesystem(&ramfs_fs_type); } 注册rootfs文件系统 int __init init_rootfs(void) { return register_filesystem(&rootfs_fs_type); } 根文件系统和ramfs文件系统读取超级快是同一接口: static int ramfs_fill_super(struct super_block * sb, void * data, int silent) { struct inode * inode; struct dentry * root; sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = RAMFS_MAGIC; sb->s_op = &ramfs_ops; sb->s_time_gran = 1; inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0); if (!inode) return -ENOMEM; root = d_alloc_root(inode); if (!root) { iput(inode); return -ENOMEM; } sb->s_root = root; return 0; } 再分配超级快时有一个小小的技巧: static struct super_block *alloc_super(void) { 分配空间 struct super_block *s = kzalloc(sizeof(struct super_block), GFP_USER); 静态变量,超级块访问接口 static struct super_operations default_op; if (s) { 。。。。 //初始化超级块 超级快访问接口,这里用的就是前面的静态变量 s->s_op = &default_op; s->s_time_gran = 1000000000; } out: return s; } /* 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, }; /* ramfs文件系统的目录操作接口 */ static struct super_operations ramfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, }; 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); } |
|
|
沙发#
发布于:2007-04-13 19:29
支持一下,现在玩深的人少了
|
|
板凳#
发布于:2007-05-04 09:48
顶一下! |
|