Chinaunix首页 | 论坛 | 博客
  • 博客访问: 162132
  • 博文数量: 22
  • 博客积分: 126
  • 博客等级: 入伍新兵
  • 技术积分: 459
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-26 21:14
文章分类
文章存档

2013年(22)

我的朋友

分类: LINUX

2013-01-03 12:29:25

Q:ext2的磁盘inode结构体为什么不存放文件inode号?
A:用户态程序查找文件都是通过文件路径来完成的,文件的inode号都是存储在父目录的数据块中,在查找过程中,根据文件名,可以很快的从目录的数据块中找到ext2_dir_entry_2,继而拿到inode号,拿到inode号后,从inode表就可以很快的找到磁盘inode结构.换言之,磁盘inode即使存储了inode号,除了用于校验,没什么其他用处.

Q:新创建的VFS inode为什么要置位I_LOCK?
A:VFS inode创建的过程:
ext2_iget()
 iget_locked()
  //由超级块和inode号生成哈希值
  struct hlist_head *head = inode_hashtable + hash(sb, ino);
  if((inode = ifind_fast()) != NULL){
   inode = find_inode_fast(sb, head, ino);
   __iget(inode);
   //等待I_LOCK标志清除,表示inode的成员赋值完毕
   wait_on_inode(inode);
   return inode;//从inode缓存中找到inode
  }
  else//inode不在icache中,需要读取磁盘inode并创建VFS inode
   get_new_inode_fast()
    inode = alloc_inode(sb);
    inode->i_ino = ino;
    hlist_add_head(&inode->i_hash, head);
 raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);//读取磁盘inode
 //将磁盘inode的信息赋值给VFS inode
进程1创建好VFS inode后会立即将inode加入到icache中,但此时inode的成员还未赋值,inode还不能被其他进程直接使用,通过置I_LOCK标志,inode的成员赋值完毕后,清除I_LOCK标志的方式,当其他进程从icache中如果找到I_LOCK置位的inode时需等待,直到inode的成员赋值完毕后,等待的进程被唤醒,安全的使用赋值完毕的inode.

Q:多个进程调用sys_open()打开同一个文件后是否会增加VFS inode的引用计数?
A:不会,系统调用路径中看到的VFS inode是通过dentry看到的,inode的用户是dentry而不是系统调用路径,dentry的用户才是系统调用路径,因此,多个进程打开相同的文件时,只会增加dentry的引用计数,不会增加inode的引用计数.


函数调用过程:
do_sys_open()
    fd = get_unused_fd_flags(flags);
    struct file *f = do_filp_open(dfd, tmp, flags, mode);
        path_lookup_open()
            do_path_lookup()
                path_walk()
                    link_path_walk()    
                        do_lookup()=>
    fd_install()//将fd和file关联,fd返回给用户态程序

do_lookup()
    if(dentry = __d_lookup() == NULL){
        dentry = real_lookup()    //dcache中找不到,到文件系统找
            dentry = d_alloc(parent, name);//无论是否能找到,先分配dentry
                atomic_set(&dentry->d_count, 1);//引用计数为1
            dir->i_op->lookup()
            ext2_lookup()
                //由文件名从目录的数据块中找到dentry的inode号
                ino = ext2_inode_by_name(dir, dentry);
                //根据inode号找到并创建相应的inode
                inode = ext2_iget(dir->i_sb, ino)=>
                d_splice_alias()
                    d_add(dentry, inode);
                        //将dentry和inode关联,此后dentry不再是负状态
                        d_instantiate(entry, inode);
                            if (inode)
                                list_add(&entry->d_alias, &inode->i_dentry);
                            entry->d_inode = inode;    
                        //将dentry加入到dcache
                        d_rehash(entry);
                            _d_rehash(entry);
                                entry->d_flags &= ~DCACHE_UNHASHED;
                                list = d_hash(entry->d_parent, entry->d_name.hash)
                                hlist_add_head_rcu(&entry->d_hash, list);
    }
    path->mnt = mnt;
    path->dentry = dentry;
    __follow_mount(path);
        while (d_mountpoint(path->dentry)) {
            struct vfsmount *mounted = lookup_mnt(path->mnt, path->dentry);
            //进入到新文件系统,如果新文件系统的根目录还挂载了文件系统,继续循环
            //直到进入最新挂载的文件系统.很自然,新文件系统会将挂载点下所有
            //的文件和目录都隐藏
            path->mnt = mounted;    
            path->dentry = dget(mounted->mnt_root);
        }

ext2_iget()
    inode *inode = iget_locked(sb, ino);    //vfs inode
        //由超级块和inode号生成哈希值
        struct hlist_head *head = inode_hashtable hash(sb, ino);
        if((inode = ifind_fast()) != NULL){
            return inode;//从inode缓存中找到inode
        }
        get_new_inode_fast()
            inode = alloc_inode(sb);
                ext2_alloc_inode()
                struct address_space * mapping = &inode->i_data;
                mapping->assoc_mapping = NULL;
                inode->i_mapping =  &inode->i_data;
            inode->i_ino = ino;        
            list_add(&inode->i_list, &inode_in_use);
            list_add(&inode->i_sb_list, &sb->s_inodes);
            hlist_add_head(&inode->i_hash, head);
            inode->i_state = I_LOCK|I_NEW;
    ext2_inode_info *ei = EXT2_I(inode);    //内存inode
    ext2_inode *raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);//根据inode号读取磁盘inode
        //每个块组中inode数目是固定的,根据inode号可以计算出inode在表中的偏移
        offset = ((ino - 1) % EXT2_INODES_PER_GROUP(sb)) * EXT2_INODE_SIZE(sb);
        block = le32_to_cpu(gdp->bg_inode_table)
            (offset >> EXT2_BLOCK_SIZE_BITS(sb));//计算inode所在的磁盘逻辑块号
        if (!(bh = sb_bread(sb, block)))
            goto Eio;
        *p = bh;
        offset &= (EXT2_BLOCK_SIZE(sb) - 1);//找到在块内的偏移
        return (struct ext2_inode *) (bh->b_data offset);        

    //由磁盘inode初始化vfs inode
    inode->i_mode = le16_to_cpu(raw_inode->i_mode);
    ...

    //由磁盘inode初始化内存inode
    ext2_inode_info->i_flags = le32_to_cpu(raw_inode->i_flags);
    //根据inode号计算出inode所在的块组
    ext2_inode_info->i_block_group = (ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb);
    ...
    inode->i_mapping->a_ops = &ext2_aops;
    return inode;


阅读(2333) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:对dentry的理解

给主人留下些什么吧!~~