文件系统如下:
-
cong@msi:/tmp/minix$ tree
-
.
-
├── bin
-
│ ├── init
-
│ ├── ls
-
│ ├── sh
-
│ └── sh_ok
-
├── dev
-
│ └── tty1
-
├── etc
-
├── usr
-
│ └── bin
-
└── var
-
-
6 directories, 5 files
-
cong@msi:/tmp/minix$ ls -l bin/
-
total 548
-
-rwxr-xr-x 1 root root 7293 Oct 5 00:13 init
-
-rwxr-xr-x 1 root root 46084 Jan 15 1992 ls
-
-rwx--x--x 1 root root 250880 Feb 28 2004 sh
-
-rwxr-xr-x 1 root root 250880 Oct 5 00:22 sh_ok
-
cong@msi:/tmp/minix$ ls -l dev/
-
total 0
-
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中
-
int sys_open(const char * filename,int flag,int mode)
-
{
-
struct m_inode * inode;
-
struct file * f;
-
int i,fd;
-
-
mode &= 0777 & ~current->umask;
-
//在fd表中选一个没有用的,现在一个都没有用,所以fd=0
-
for(fd=0 ; fd<NR_OPEN ; fd++)
-
if (!current->filp[fd])
-
break;
-
if (fd>=NR_OPEN)
-
return -EINVAL;
-
current->close_on_exec &= ~(1<<fd);
-
//在file_table中选一个没有使用的
-
f=0+file_table;
-
for (i=0 ; i<NR_FILE ; i++,f++)
-
if (!f->f_count) break;
-
if (i>=NR_FILE)
-
return -EINVAL;
-
//将fip[fd]与file_table中的项挂接
-
(current->filp[fd]=f)->f_count++;
-
//获取filename的inode,以后进行read write操作都是靠inode来的
-
if ((i=open_namei(filename,flag,mode,&inode))<0) {
-
current->filp[fd]=NULL;
-
f->f_count=0;
-
return i;
-
}
-
/* ttys are somewhat special (ttyxx major==4, tty major==5) */
-
if (S_ISCHR(inode->i_mode))
-
if (check_char_dev(inode,inode->i_zone[0],flag)) {
-
iput(inode);
-
current->filp[fd]=NULL;
-
f->f_count=0;
-
return -EAGAIN;
-
}
-
/* Likewise with block-devices: check for floppy_change */
-
if (S_ISBLK(inode->i_mode))
-
check_disk_change(inode->i_zone[0]);
-
f->f_mode = inode->i_mode;
-
f->f_flags = flag;
-
f->f_count = 1;
-
f->f_inode = inode; //保存这个filename指定的inode,以后read write就靠这个inode了
-
f->f_pos = 0;
-
return (fd);
-
}
2. 在fs/namei.c中
(pathname=0x226b0 "/dev/tty1", flag=2, mode=0, res_inode=0xffffb0) at namei.c:390
-
int open_namei(const char * pathname, int flag, int mode,
-
struct m_inode ** res_inode)
-
{
-
const char * basename;
-
int inr,dev,namelen;
-
struct m_inode * dir, *inode;
-
struct buffer_head * bh;
-
struct dir_entry * de;
-
-
if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
-
flag |= O_WRONLY;
-
mode &= 0777 & ~current->umask;
-
mode |= I_REGULAR;
-
if (!(dir = dir_namei(pathname,&namelen,&basename,NULL))) //d.有了dev的inode就可以读取dev的数据块
-
return -ENOENT;
-
if (!namelen) { /* special case: '/usr/' etc */
-
if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
-
*res_inode=dir;
-
return 0;
-
}
-
iput(dir);
-
return -EISDIR;
-
}
-
bh = find_entry(&dir,basename,namelen,&de); //因为dev是一个目录,再查找目录里面有没有跟tty1匹配的name,
-
if (!bh) { //若有则返回tty1的inode_nr,即dir_entry中的inode_nr
-
if (!(flag & O_CREAT)) {
-
iput(dir);
-
return -ENOENT;
-
}
-
if (!permission(dir,MAY_WRITE)) {
-
iput(dir);
-
return -EACCES;
-
}
-
inode = new_inode(dir->i_dev);
-
if (!inode) {
-
iput(dir);
-
return -ENOSPC;
-
}
-
inode->i_uid = current->euid;
-
inode->i_mode = mode;
-
inode->i_dirt = 1;
-
bh = add_entry(dir,basename,namelen,&de);
-
if (!bh) {
-
inode->i_nlinks--;
-
iput(inode);
-
iput(dir);
-
return -ENOSPC;
-
}
-
de->inode = inode->i_num;
-
bh->b_dirt = 1;
-
brelse(bh);
-
iput(dir);
-
*res_inode = inode;
-
return 0;
-
}
-
inr = de->inode;
-
dev = dir->i_dev;
-
brelse(bh);
-
if (flag & O_EXCL) {
-
iput(dir);
-
return -EEXIST;
-
}
-
if (!(inode = follow_link(dir,iget(dev,inr))))
-
return -EACCES;
-
if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
-
!permission(inode,ACC_MODE(flag))) {
-
iput(inode);
-
return -EPERM;
-
}
-
inode->i_atime = CURRENT_TIME;
-
if (flag & O_TRUNC)
-
truncate(inode);
-
*res_inode = inode;
-
return 0;
-
}
在fs/namei.c中
-
static struct m_inode * dir_namei(const char * pathname,
-
int * namelen, const char ** name, struct m_inode * base)
-
{
-
char c;
-
const char * basename;
-
struct m_inode * dir;
-
-
if (!(dir = get_dir(pathname,base)))
-
return NULL;
-
basename = pathname;
-
while (c=get_fs_byte(pathname++))
-
if (c=='/')
-
basename=pathname;
-
*namelen = pathname-basename-1;
-
*name = basename;
-
return dir;
-
}
在fs/namei.c中
-
static struct m_inode * get_dir(const char * pathname, struct m_inode * inode)
-
{
-
char c;
-
const char * thisname;
-
struct buffer_head * bh;
-
int namelen,inr;
-
struct dir_entry * de;
-
struct m_inode * dir;
-
//如果pathname第1个字符不是/则是相对路径从pwd开始找,如果第1个字符是/则是绝对路径从root开始找
-
if (!inode) {
-
inode = current->pwd; //默认是从pwd开始查找
-
inode->i_count++;
-
}
-
if ((c=get_fs_byte(pathname))=='/') {
-
iput(inode);
-
inode = current->root; //当知道第1个字符是/时,则从root开始查找
-
pathname++; //pathname="dev/tty1"
-
inode->i_count++;
-
}
-
while (1) {
-
thisname = pathname; //thisname = pathname="dev/tty1"
-
if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {
-
iput(inode);
-
return NULL;
-
}
-
for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)
-
/* nothing */ ; //for完后: pathname="tty1",thisname="dev/tty1"
-
if (!c)
-
return inode;
-
if (!(bh = find_entry(&inode,thisname,namelen,&de))) {
-
iput(inode);
-
return NULL;
-
}
-
inr = de->inode;
-
brelse(bh);
-
dir = inode;
-
if (!(inode = iget(dir->i_dev,inr))) { //读取dev的inode
-
iput(dir);
-
return NULL;
-
}
-
if (!(inode = follow_link(dir,inode)))
-
return NULL;
-
}
-
}
在fs/namei.c中
find_entry需要保证第1个参数的属性是目录
第1次进这个find_entry时,dir就是root的inode
搜索该目录inode的所有数据块,看有没有匹配名字的dir_entry,如果有则将结查保存在res_dir中
这个目的是为了得到name的inode_nr
-
static struct buffer_head * find_entry(struct m_inode ** dir,
-
const char * name, int namelen, struct dir_entry ** res_dir)
-
{
-
int entries;
-
int block,i;
-
struct buffer_head * bh;
-
struct dir_entry * de;
-
struct super_block * sb;
-
-
#ifdef NO_TRUNCATE
-
if (namelen > NAME_LEN)
-
return NULL;
-
#else
-
if (namelen > NAME_LEN)
-
namelen = NAME_LEN;
-
#endif
-
//在当前目录下有多少项
-
entries = (*dir)->i_size / (sizeof (struct dir_entry));
-
*res_dir = NULL;
-
/* check for '..', as we might have to do some "magic" for it */
-
if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
-
/* '..' in a pseudo-root results in a faked '.' (just change namelen) */
-
if ((*dir) == current->root)
-
namelen=1;
-
else if ((*dir)->i_num == ROOT_INO) {
-
/* '..' over a mount-point results in 'dir' being exchanged for the mounted
-
directory-inode. We set mounted, so that we can iput the new dir */
-
sb=get_super((*dir)->i_dev);
-
if (sb->s_imount) {
-
iput(*dir);
-
(*dir)=sb->s_imount;
-
(*dir)->i_count++;
-
}
-
}
-
}
-
//先读取该目录inode的第1个数据块
-
if (!(block = (*dir)->i_zone[0]))
-
return NULL;
-
if (!(bh = bread((*dir)->i_dev,block)))
-
return NULL;
-
i = 0;
-
de = (struct dir_entry *) bh->b_data;
-
//搜索该目录inode的所有数据块,去匹配要查找的name,找到之后就把inode_nr保存在res_dir中
-
while (i < entries) {
-
if ((char *)de >= BLOCK_SIZE+bh->b_data) { //如果第1个数据块中没有name,则读取并查找下一个数据块
-
brelse(bh);
-
bh = NULL;
-
if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) ||
-
!(bh = bread((*dir)->i_dev,block))) {
-
i += DIR_ENTRIES_PER_BLOCK;
-
continue;
-
}
-
de = (struct dir_entry *) bh->b_data;
-
}
-
if (match(namelen,name,de)) {
-
*res_dir = de; //如果找到了就将结果保存在res_dir中
-
return bh; //res_dir中最重要的是inode_nr
-
}
-
de++;
-
i++;
-
}
-
brelse(bh);
-
return NULL;
-
}
二.sys_read
2.1 在fs/read_write.c中
-
int sys_read(unsigned int fd,char * buf,int count)
-
{
-
struct file * file;
-
struct m_inode * inode;
-
-
if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd]))
-
return -EINVAL;
-
if (!count)
-
return 0;
-
verify_area(buf,count);
-
inode = file->f_inode;
-
if (inode->i_pipe)
-
return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO;
-
if (S_ISCHR(inode->i_mode))
-
return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
-
if (S_ISBLK(inode->i_mode))
-
return block_read(inode->i_zone[0],&file->f_pos,buf,count);
-
//如果是目录或者是普通文件的话
-
if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
-
if (count+file->f_pos > inode->i_size)
-
count = inode->i_size - file->f_pos;
-
if (count<=0)
-
return 0;
-
return file_read(inode,file,buf,count);
-
}
-
printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
-
return -EINVAL;
-
}
2.2 在fs/file_dev.c中
-
int file_read(struct m_inode * inode, struct file * filp, char * buf, int count)
-
{
-
int left,chars,nr;
-
struct buffer_head * bh;
-
-
if ((left=count)<=0)
-
return 0;
-
while (left) {
-
if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) { //通过i_zone[0-8]找出下一步要读取的block_nr
-
if (!(bh=bread(inode->i_dev,nr))) //将block_nr中的数据读取出来
-
break;
-
} else
-
bh = NULL;
-
nr = filp->f_pos % BLOCK_SIZE;
-
chars = MIN( BLOCK_SIZE-nr , left );
-
filp->f_pos += chars;
-
left -= chars;
-
if (bh) {
-
char * p = nr + bh->b_data;
-
while (chars-->0)
-
put_fs_byte(*(p++),buf++);
-
brelse(bh);
-
} else {
-
while (chars-->0)
-
put_fs_byte(0,buf++);
-
}
-
}
-
inode->i_atime = CURRENT_TIME;
-
return (count-left)?(count-left):-ERROR;
-
}
2.3
在fs/inode.c中
-
int bmap(struct m_inode * inode,int block)
-
{
-
return _bmap(inode,block,0);
-
}
2.4
在fs/inode.c中
block是filp->f_pos,即文件的偏移,例如: 文件长度是10K,读取从8K开始的字节,则block=8
-
static int _bmap(struct m_inode * inode,int block,int create)
-
{
-
struct buffer_head * bh;
-
int i;
-
//1个block是1K字节,先判断block是否大于一次间接块与二次间接块所能表示的最大长度
-
if (block<0)
-
panic("_bmap: block<0");
-
if (block >= 7+512+512*512) //一次间接块最大能表示512K,二次间接块512*512K
-
panic("_bmap: block>big");
-
//如果block<7,i_zone[0-6]就可以表示块号了
-
if (block<7) {
-
if (create && !inode->i_zone[block])
-
if (inode->i_zone[block]=new_block(inode->i_dev)) {
-
inode->i_ctime=CURRENT_TIME;
-
inode->i_dirt=1;
-
}
-
return inode->i_zone[block]; //不需要索引就找到了要读取的block_nr=i_zone[0-6]中就放着下一步要读取的块号
-
}
-
//如果block>7,先减去7,看剩下的用一次间接块能不能全部表示出来
-
block -= 7;
-
if (block<512) {
-
if (create && !inode->i_zone[7])
-
if (inode->i_zone[7]=new_block(inode->i_dev)) {
-
inode->i_dirt=1;
-
inode->i_ctime=CURRENT_TIME;
-
}
-
if (!inode->i_zone[7])
-
return 0;
-
if (!(bh = bread(inode->i_dev,inode->i_zone[7]))) //i_zone[7]中就放着一次间接块的块号
-
return 0;
-
i = ((unsigned short *) (bh->b_data))[block];
-
if (create && !i)
-
if (i=new_block(inode->i_dev)) {
-
((unsigned short *) (bh->b_data))[block]=i;
-
bh->b_dirt=1;
-
}
-
brelse(bh);
-
return i; //1次索引完后就找到了要读取的block_nr
-
}
-
//如果一次间接块搞不定,这就需要用到二次间接块
-
block -= 512;
-
if (create && !inode->i_zone[8])
-
if (inode->i_zone[8]=new_block(inode->i_dev)) {
-
inode->i_dirt=1;
-
inode->i_ctime=CURRENT_TIME;
-
}
-
if (!inode->i_zone[8])
-
return 0;
-
if (!(bh=bread(inode->i_dev,inode->i_zone[8]))) //i_zone[8]中就放着二次间接块的块号
-
return 0;
-
i = ((unsigned short *)bh->b_data)[block>>9]; //第1次索引
-
if (create && !i)
-
if (i=new_block(inode->i_dev)) {
-
((unsigned short *) (bh->b_data))[block>>9]=i;
-
bh->b_dirt=1;
-
}
-
brelse(bh);
-
if (!i)
-
return 0;
-
if (!(bh=bread(inode->i_dev,i)))
-
return 0;
-
i = ((unsigned short *)bh->b_data)[block&511]; //第2次索引
-
if (create && !i)
-
if (i=new_block(inode->i_dev)) {
-
((unsigned short *) (bh->b_data))[block&511]=i;
-
bh->b_dirt=1;
-
}
-
brelse(bh);
-
return i; //2次索引完后就找到了要读取的block_nr
-
}
阅读(1204) | 评论(0) | 转发(0) |