Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2150801
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2016-10-09 15:54:02

文件系统如下:
  1. cong@msi:/tmp/minix$ tree
  2. .
  3. ├── bin
  4. │   ├── init
  5. │   ├── ls
  6. │   ├── sh
  7. │   └── sh_ok
  8. ├── dev
  9. │   └── tty1
  10. ├── etc
  11. ├── usr
  12. │   └── bin
  13. └── var

  14. 6 directories, 5 files
  15. cong@msi:/tmp/minix$ ls -l bin/
  16. total 548
  17. -rwxr-xr-x 1 root root 7293 Oct 5 00:13 init
  18. -rwxr-xr-x 1 root root 46084 Jan 15 1992 ls
  19. -rwx--x--x 1 root root 250880 Feb 28 2004 sh
  20. -rwxr-xr-x 1 root root 250880 Oct 5 00:22 sh_ok
  21. cong@msi:/tmp/minix$ ls -l dev/
  22. total 0
  23. crw-r--r-- 1 root root 4, 1 Oct 5 00:13 tty1
init --> (void) open("/dev/tty1",O_RDWR,0);
a.看路径的首字符是不是/,判断是相对路径还是绝对路径,绝对路径是从root的inode开始找
b. 通过读root的inode的数据块,里面是一堆dir_entry,看有没有跟dev这个nam匹配的,
   若有则返回dev的inode_nr,即dir_entry中的inode_nr
c.有了dev的inode_nr,读取dev的inode
d.有了dev的inode就可以读取dev的数据块,因为dev是一个目录,再查找目录里面有没有跟tty1匹配的name
  有则返回tty1的inode_nr,即dir_entry中的inode_nr
f. 有了tty1的inode_nr,就可以读取tty1中的数据,这儿是一个设备文件,只有一个设备号存在i_zone[0]中

1. 在fs/open.c中
  1. int sys_open(const char * filename,int flag,int mode)
  2. {
  3.     struct m_inode * inode;
  4.     struct file * f;
  5.     int i,fd;

  6.     mode &= 0777 & ~current->umask;
  7. //在fd表中选一个没有用的,现在一个都没有用,所以fd=0
  8.     for(fd=0 ; fd<NR_OPEN ; fd++)
  9.         if (!current->filp[fd])
  10.             break;
  11.     if (fd>=NR_OPEN)
  12.         return -EINVAL;
  13.     current->close_on_exec &= ~(1<<fd);
  14. //在file_table中选一个没有使用的
  15.     f=0+file_table;
  16.     for (i=0 ; i<NR_FILE ; i++,f++)
  17.         if (!f->f_count) break;
  18.     if (i>=NR_FILE)
  19.         return -EINVAL;
  20. //将fip[fd]与file_table中的项挂接
  21.     (current->filp[fd]=f)->f_count++;
  22. //获取filename的inode,以后进行read write操作都是靠inode来的
  23.     if ((i=open_namei(filename,flag,mode,&inode))<0) {
  24.         current->filp[fd]=NULL;
  25.         f->f_count=0;
  26.         return i;
  27.     }
  28. /* ttys are somewhat special (ttyxx major==4, tty major==5) */
  29.     if (S_ISCHR(inode->i_mode))
  30.         if (check_char_dev(inode,inode->i_zone[0],flag)) {
  31.             iput(inode);
  32.             current->filp[fd]=NULL;
  33.             f->f_count=0;
  34.             return -EAGAIN;
  35.         }
  36. /* Likewise with block-devices: check for floppy_change */
  37.     if (S_ISBLK(inode->i_mode))
  38.         check_disk_change(inode->i_zone[0]);
  39.     f->f_mode = inode->i_mode;
  40.     f->f_flags = flag;
  41.     f->f_count = 1;
  42.     f->f_inode = inode;       //保存这个filename指定的inode,以后read write就靠这个inode了
  43.     f->f_pos = 0;
  44.     return (fd);
  45. }

2. 在fs/namei.c中
(pathname=0x226b0 "/dev/tty1", flag=2, mode=0, res_inode=0xffffb0) at namei.c:390
  1. int open_namei(const char * pathname, int flag, int mode,
  2.     struct m_inode ** res_inode)
  3. {
  4.     const char * basename;
  5.     int inr,dev,namelen;
  6.     struct m_inode * dir, *inode;
  7.     struct buffer_head * bh;
  8.     struct dir_entry * de;

  9.     if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
  10.         flag |= O_WRONLY;
  11.     mode &= 0777 & ~current->umask;
  12.     mode |= I_REGULAR;
  13.     if (!(dir = dir_namei(pathname,&namelen,&basename,NULL)))  //d.有了dev的inode就可以读取dev的数据块
  14.         return -ENOENT;
  15.     if (!namelen) {            /* special case: '/usr/' etc */
  16.         if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
  17.             *res_inode=dir;
  18.             return 0;
  19.         }
  20.         iput(dir);
  21.         return -EISDIR;
  22.     }
  23.     bh = find_entry(&dir,basename,namelen,&de);                 //因为dev是一个目录,再查找目录里面有没有跟tty1匹配的name,
  24.     if (!bh) {                                                   //有则返回tty1的inode_nr,即dir_entry中的inode_nr
  25.         if (!(flag & O_CREAT)) {
  26.             iput(dir);
  27.             return -ENOENT;
  28.         }
  29.         if (!permission(dir,MAY_WRITE)) {
  30.             iput(dir);
  31.             return -EACCES;
  32.         }
  33.         inode = new_inode(dir->i_dev);
  34.         if (!inode) {
  35.             iput(dir);
  36.             return -ENOSPC;
  37.         }
  38.         inode->i_uid = current->euid;
  39.         inode->i_mode = mode;
  40.         inode->i_dirt = 1;
  41.         bh = add_entry(dir,basename,namelen,&de);
  42.         if (!bh) {
  43.             inode->i_nlinks--;
  44.             iput(inode);
  45.             iput(dir);
  46.             return -ENOSPC;
  47.         }
  48.         de->inode = inode->i_num;
  49.         bh->b_dirt = 1;
  50.         brelse(bh);
  51.         iput(dir);
  52.         *res_inode = inode;
  53.         return 0;
  54.     }
  55.     inr = de->inode;
  56.     dev = dir->i_dev;
  57.     brelse(bh);
  58.     if (flag & O_EXCL) {
  59.         iput(dir);
  60.         return -EEXIST;
  61.     }
  62.     if (!(inode = follow_link(dir,iget(dev,inr))))
  63.         return -EACCES;
  64.     if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
  65.      !permission(inode,ACC_MODE(flag))) {
  66.         iput(inode);
  67.         return -EPERM;
  68.     }
  69.     inode->i_atime = CURRENT_TIME;
  70.     if (flag & O_TRUNC)
  71.         truncate(inode);
  72.     *res_inode = inode;
  73.     return 0;
  74. }

在fs/namei.c中
  1. static struct m_inode * dir_namei(const char * pathname,
  2.     int * namelen, const char ** name, struct m_inode * base)
  3. {
  4.     char c;
  5.     const char * basename;
  6.     struct m_inode * dir;

  7.     if (!(dir = get_dir(pathname,base)))
  8.         return NULL;
  9.     basename = pathname;
  10.     while (c=get_fs_byte(pathname++))
  11.         if (c=='/')
  12.             basename=pathname;
  13.     *namelen = pathname-basename-1;
  14.     *name = basename;
  15.     return dir;
  16. }


在fs/namei.c中
  1. static struct m_inode * get_dir(const char * pathname, struct m_inode * inode)
  2. {
  3.     char c;
  4.     const char * thisname;
  5.     struct buffer_head * bh;
  6.     int namelen,inr;
  7.     struct dir_entry * de;
  8.     struct m_inode * dir;
  9. //如果pathname第1个字符不是/则是相对路径从pwd开始找,如果第1个字符是/则是绝对路径从root开始找
  10.     if (!inode) {
  11.         inode = current->pwd;                   //默认是从pwd开始查找
  12.         inode->i_count++;
  13.     }
  14.     if ((c=get_fs_byte(pathname))=='/') {
  15.         iput(inode);
  16.         inode = current->root;                 //当知道第1个字符是/时,则从root开始查找
  17.         pathname++;                            //pathname="dev/tty1"
  18.         inode->i_count++;
  19.     }
  20.     while (1) {
  21.         thisname = pathname;                   //thisname = pathname="dev/tty1"
  22.         if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {
  23.             iput(inode);
  24.             return NULL;
  25.         }
  26.         for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)
  27.             /* nothing */ ;                        //for完后: pathname="tty1",thisname="dev/tty1"
  28.         if (!c)
  29.             return inode;
  30.         if (!(bh = find_entry(&inode,thisname,namelen,&de))) {
  31.             iput(inode);
  32.             return NULL;
  33.         }
  34.         inr = de->inode;
  35.         brelse(bh);
  36.         dir = inode;
  37.         if (!(inode = iget(dir->i_dev,inr))) {     //读取dev的inode
  38.             iput(dir);
  39.             return NULL;
  40.         }
  41.         if (!(inode = follow_link(dir,inode)))
  42.             return NULL;
  43.     }
  44. }
在fs/namei.c中
find_entry需要保证第1个参数的属性是目录
第1次进这个find_entry时,dir就是root的inode
搜索该目录inode的所有数据块,看有没有匹配名字的dir_entry,如果有则将结查保存在res_dir中
这个目的是为了得到name的inode_nr
  1. static struct buffer_head * find_entry(struct m_inode ** dir,
  2.     const char * name, int namelen, struct dir_entry ** res_dir)
  3. {
  4.     int entries;
  5.     int block,i;
  6.     struct buffer_head * bh;
  7.     struct dir_entry * de;
  8.     struct super_block * sb;

  9. #ifdef NO_TRUNCATE
  10.     if (namelen > NAME_LEN)
  11.         return NULL;
  12. #else
  13.     if (namelen > NAME_LEN)
  14.         namelen = NAME_LEN;
  15. #endif
  16. //在当前目录下有多少项
  17.     entries = (*dir)->i_size / (sizeof (struct dir_entry));
  18.     *res_dir = NULL;
  19. /* check for '..', as we might have to do some "magic" for it */
  20.     if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
  21. /* '..' in a pseudo-root results in a faked '.' (just change namelen) */
  22.         if ((*dir) == current->root)
  23.             namelen=1;
  24.         else if ((*dir)->i_num == ROOT_INO) {
  25. /* '..' over a mount-point results in 'dir' being exchanged for the mounted
  26.    directory-inode. We set mounted, so that we can iput the new dir */
  27.             sb=get_super((*dir)->i_dev);
  28.             if (sb->s_imount) {
  29.                 iput(*dir);
  30.                 (*dir)=sb->s_imount;
  31.                 (*dir)->i_count++;
  32.             }
  33.         }
  34.     }
  35. //先读取该目录inode的第1个数据块
  36.     if (!(block = (*dir)->i_zone[0]))
  37.         return NULL;
  38.     if (!(bh = bread((*dir)->i_dev,block)))
  39.         return NULL;
  40.     i = 0;
  41.     de = (struct dir_entry *) bh->b_data;
  42. //搜索该目录inode的所有数据块,去匹配要查找的name,找到之后就把inode_nr保存在res_dir中
  43.     while (i < entries) {
  44.         if ((char *)de >= BLOCK_SIZE+bh->b_data) {   //如果第1个数据块中没有name,则读取并查找下一个数据块
  45.             brelse(bh);
  46.             bh = NULL;
  47.             if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) ||
  48.              !(bh = bread((*dir)->i_dev,block))) {
  49.                 i += DIR_ENTRIES_PER_BLOCK;
  50.                 continue;
  51.             }
  52.             de = (struct dir_entry *) bh->b_data;
  53.         }
  54.         if (match(namelen,name,de)) {
  55.             *res_dir = de;              //如果找到了就将结果保存在res_dir中
  56.             return bh;                  //res_dir中最重要的是inode_nr
  57.         }
  58.         de++;
  59.         i++;
  60.     }
  61.     brelse(bh);
  62.     return NULL;
  63. }
二.sys_read
2.1 在fs/read_write.c中
  1. int sys_read(unsigned int fd,char * buf,int count)
  2. {
  3.     struct file * file;
  4.     struct m_inode * inode;

  5.     if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd]))
  6.         return -EINVAL;
  7.     if (!count)
  8.         return 0;
  9.     verify_area(buf,count);
  10.     inode = file->f_inode;
  11.     if (inode->i_pipe)
  12.         return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO;
  13.     if (S_ISCHR(inode->i_mode))
  14.         return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
  15.     if (S_ISBLK(inode->i_mode))
  16.         return block_read(inode->i_zone[0],&file->f_pos,buf,count);
  17. //如果是目录或者是普通文件的话
  18.     if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {      
  19.         if (count+file->f_pos > inode->i_size)
  20.             count = inode->i_size - file->f_pos;
  21.         if (count<=0)
  22.             return 0;
  23.         return file_read(inode,file,buf,count);
  24.     }
  25.     printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
  26.     return -EINVAL;
  27. }
2.2 在fs/file_dev.c中
  1. int file_read(struct m_inode * inode, struct file * filp, char * buf, int count)
  2. {
  3.     int left,chars,nr;
  4.     struct buffer_head * bh;

  5.     if ((left=count)<=0)
  6.         return 0;
  7.     while (left) {
  8.         if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) {    //通过i_zone[0-8]找出下一步要读取的block_nr
  9.             if (!(bh=bread(inode->i_dev,nr)))               //将block_nr中的数据读取出来
  10.                 break;
  11.         } else
  12.             bh = NULL;
  13.         nr = filp->f_pos % BLOCK_SIZE;
  14.         chars = MIN( BLOCK_SIZE-nr , left );
  15.         filp->f_pos += chars;
  16.         left -= chars;
  17.         if (bh) {
  18.             char * p = nr + bh->b_data;
  19.             while (chars-->0)
  20.                 put_fs_byte(*(p++),buf++);
  21.             brelse(bh);
  22.         } else {
  23.             while (chars-->0)
  24.                 put_fs_byte(0,buf++);
  25.         }
  26.     }
  27.     inode->i_atime = CURRENT_TIME;
  28.     return (count-left)?(count-left):-ERROR;
  29. }
2.3  在fs/inode.c中
  1. int bmap(struct m_inode * inode,int block)
  2. {
  3.     return _bmap(inode,block,0);
  4. }
2.4  在fs/inode.c中
block是filp->f_pos,即文件的偏移,例如: 文件长度是10K,读取从8K开始的字节,则block=8
  1. static int _bmap(struct m_inode * inode,int block,int create)
  2. {
  3.     struct buffer_head * bh;
  4.     int i;
  5. //1个block是1K字节,先判断block是否大于一次间接块与二次间接块所能表示的最大长度
  6.     if (block<0)
  7.         panic("_bmap: block<0");
  8.     if (block >= 7+512+512*512)      //一次间接块最大能表示512K,二次间接块512*512K
  9.         panic("_bmap: block>big");
  10. //如果block<7,i_zone[0-6]就可以表示块号了
  11.     if (block<7) {
  12.         if (create && !inode->i_zone[block])
  13.             if (inode->i_zone[block]=new_block(inode->i_dev)) {
  14.                 inode->i_ctime=CURRENT_TIME;
  15.                 inode->i_dirt=1;
  16.             }
  17.         return inode->i_zone[block];     //不需要索引就找到了要读取的block_nr=i_zone[0-6]中就放着下一步要读取的块号
  18.     }
  19. //如果block>7,先减去7,看剩下的用一次间接块能不能全部表示出来
  20.     block -= 7;
  21.     if (block<512) {
  22.         if (create && !inode->i_zone[7])
  23.             if (inode->i_zone[7]=new_block(inode->i_dev)) {
  24.                 inode->i_dirt=1;
  25.                 inode->i_ctime=CURRENT_TIME;
  26.             }
  27.         if (!inode->i_zone[7])
  28.             return 0;
  29.         if (!(bh = bread(inode->i_dev,inode->i_zone[7])))   //i_zone[7]中就放着一次间接块的块号
  30.             return 0;
  31.         i = ((unsigned short *) (bh->b_data))[block];       
  32.         if (create && !i)
  33.             if (i=new_block(inode->i_dev)) {
  34.                 ((unsigned short *) (bh->b_data))[block]=i;
  35.                 bh->b_dirt=1;
  36.             }
  37.         brelse(bh);
  38.         return i;                                          //1次索引完后就找到了要读取的block_nr
  39.     }
  40. //如果一次间接块搞不定,这就需要用到二次间接块
  41.     block -= 512;
  42.     if (create && !inode->i_zone[8])
  43.         if (inode->i_zone[8]=new_block(inode->i_dev)) {
  44.             inode->i_dirt=1;
  45.             inode->i_ctime=CURRENT_TIME;
  46.         }
  47.     if (!inode->i_zone[8])
  48.         return 0;
  49.     if (!(bh=bread(inode->i_dev,inode->i_zone[8])))       //i_zone[8]中就放着二次间接块的块号
  50.         return 0;
  51.     i = ((unsigned short *)bh->b_data)[block>>9];         //第1次索引
  52.     if (create && !i)
  53.         if (i=new_block(inode->i_dev)) {
  54.             ((unsigned short *) (bh->b_data))[block>>9]=i;
  55.             bh->b_dirt=1;
  56.         }
  57.     brelse(bh);
  58.     if (!i)
  59.         return 0;
  60.     if (!(bh=bread(inode->i_dev,i)))
  61.         return 0;
  62.     i = ((unsigned short *)bh->b_data)[block&511];       //第2次索引
  63.     if (create && !i)
  64.         if (i=new_block(inode->i_dev)) {
  65.             ((unsigned short *) (bh->b_data))[block&511]=i;
  66.             bh->b_dirt=1;
  67.         }
  68.     brelse(bh);
  69.     return i;                                           //2次索引完后就找到了要读取的block_nr
  70. }

阅读(1204) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~