cyliu
论坛版主
论坛版主
  • 注册日期2003-06-13
  • 最后登录2014-04-11
  • 粉丝5
  • 关注0
  • 积分1238分
  • 威望2531点
  • 贡献值0点
  • 好评度577点
  • 原创分14分
  • 专家分10分
阅读:4594回复:2

ramfs文件系统分析

楼主#
更多 发布于:2007-03-23 20:08
  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);
}
走走看看开源好 Solaris vs Linux
88li
驱动牛犊
驱动牛犊
  • 注册日期2005-10-11
  • 最后登录2006-05-05
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望6点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2007-04-13 19:29
支持一下,现在玩深的人少了
lijianfei77
驱动牛犊
驱动牛犊
  • 注册日期2005-03-26
  • 最后登录2007-09-11
  • 粉丝0
  • 关注0
  • 积分100分
  • 威望10点
  • 贡献值0点
  • 好评度10点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2007-05-04 09:48

顶一下!
游客

返回顶部