Chinaunix首页 | 论坛 | 博客
  • 博客访问: 252963
  • 博文数量: 38
  • 博客积分: 2093
  • 博客等级: 大尉
  • 技术积分: 432
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-01 10:29
文章分类

全部博文(38)

文章存档

2011年(10)

2010年(28)

我的朋友

分类: LINUX

2010-09-16 15:49:41

linux内核之文件系统(二)
通过open,close与read系统调用,让我们深入内核级。
用户进程通过函数open(char_user *filename,flags,mode)进行系统调用。系统调用表调用sys_open(filename,flas,mode)系统调用。主要完成的功能就是找到inode和dentry,然后创建file结构,从进程的文件描述符数组中找出空闲的文件描述符指向这个file结构。
具体流程:
    1.tmp=getname(filename)这个是调用strncpy_from_user()将用户空间复制到内核空间。
    2.fd=get_unused_fd()从进程自己的文件描述符数组中获得一个空闲的文件描述符,并将其标记为忙。遵循最小可用原则,也就是说取最小下标的空闲文件描述符。
    3.f=filp_open(tmp,flags,mode)这是主要的步骤。完成了open系统调用的主要功能。返回file结构体的指针,也就是说创建了一个file结构。
    4.fd_install(fd,f)将fd指向了f。也就是说让文件描述符指向了file结构。
    5.putname(tmp)释放存放文件名的tmp的内核空间。
    6.return fd;系统调用sys_open返回fd.
总的说来,就是获取文件描述符fd,创建file结构,将fd指向file结构,释放为文件名建立的内核空间tmp,返回文件描述符fd。
其中第三步f=filp_open(tmp,flags,mode)的步骤为:找到inode,创建file结构,返回文件结构指针f。具体如下:
    1)open_namei(filename,namei_flags,mode,&nd)完成路径名的查找,生成nameidata结构,并获得相应的inode,将inode信息放入nd中。
    2)如果inode存在,那么return dentry_open(nd.dentry,nd.mnt,flags)创建并初始化file结构f,并返回。文件结构中有一项为f_dentry指向dentry,dentry中也有一项指向inode结点。

对于close系统调用,对于C程序来说,一般是程序终止时隐式调用的。
系统调用sys_close(fd)的主要功能为先判断fd是否合法,如果合法,则释放文件描述符数组中的该文件描述符,置为闲置,然后销毁file结构体。
具体步骤如下:
    1.spin_lock(&files->file_lock)这是对进程的文件描述符数组上锁。此处files是current->files。
    2.判断fd是否大于files->max_fds,也就是判断fd有没有超过数组中的已分配的文件描述符的最大值,如果超过了,说明不合法。
    3.如果第2步判断fd是有效的,则保存filp=files->fd[fd]。
    4.接着files->fd[fd]=NULL释放文件描述符数组中的指向file结构的指针。
    5.清除files->close_on_exec中的fd。这是因为files->close_on_exec记录了哪些fd需要在关闭时清除,已经清除了,自然要从这个标记需要清除的地方消去了。
    6._put_unused_fd(files,fd)再将文件描述符数组的该位置置为可用。并判断一下这个fd是不是小于原本要分配的fd,如果小于,则将next->fd置为刚刚释放的fd。
    7.spin_unlock()对文件描述符数组解锁。
    8.return filp_close(filp,files).释放file结构本身。这是close系统调用的核心部分,完成主要的工作。



read()调用系统调用sys_read(fd,buf,count)
sys_read具体步骤如下:
    1.file *file=fget_light(fd,&fput_needed)从文件描述符获取file结构指针。并将file结构中的count加1.其实具体有没有加1,是反应在fput_needed中的。因为有些是同一个进程多次读,这里就是没有加1的。后面与其成对出现的fput_light(file,fput_needed)通过从fget_light获取的fput_needed可以看出原来有没有加1,如果加了1,那么读完成后的fput_light就应该减1,如果当时没有加1,那么结束时也不用减1。
    2. ret=vfs_read(file,buf,count,&file->f_pos)这里调用了vfs接口,新加入的参数&file->f_pos是文件结构中记录进程对当前文件操作到的位置。
    3. fput_light(file,fput_needed).用于对文件结构的count减1,如果必要的话。
    4. return.
其中第2步的vfs调用是核心部分,完成读取的功能。具体如下:
    1)inode *inode=file->f_dentry->d_inode.将文件的inode指针保存下来。
        2)检查file->f_op->read或者file->f_op->aio_read是否被赋值了,如果没有赋值,则返回错误,表明文件描述符指向的这个文件结构是不支持读操作的,也就是不能读这个文件。
        3)检查要读的区域是否上锁,文件是否被授权了读。如果否,则通知父目录。
        4)如果file->f_op->read存在,那么
        file->f_op->read(file,buf,count,pos)
       否则
                do_sync_read(file,buf,count,pos)
           如果没有成功,则通知父目录。
       file->f_op->read是一个指针,指向了具体文件系统提供的读操作的内容,但是有些,比如ext2的读操作是接受linux默认值的,所以这里file->f_op->read调用的是generic_file_read()。其他的某些操作,如果不接受linux默认,则在file_operations表中的对应指针指向自己特定的操作即可。
阅读(2146) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~