zoukankan      html  css  js  c++  java
  • ramfs 文件系统分析

    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);
    }

  • 相关阅读:
    ThinkPHP框架知识(比较全的知识)
    利用smarty模板(登录、有关信息操作等功能)
    从零开始学习Node.js例子七 发送HTTP客户端请求并显示响应结果
    从零开始学习Node.js例子六 EventEmitter发送和接收事件
    从零开始学习Node.js例子五 服务器监听
    从零开始学习Node.js例子四 多页面实现数学运算 续二(client端和server端)
    从零开始学习Node.js例子四 多页面实现数学运算 续一(使用connect和express框架)
    从零开始学习Node.js例子四 多页面实现数学运算
    从零开始学习Node.js例子三 图片上传和显示
    从零开始学习Node.js例子二 文本提交与显示
  • 原文地址:https://www.cnblogs.com/linengier/p/2990323.html
Copyright © 2011-2022 走看看