文件系统和设备之间的联系

原创 2007年10月12日 16:22:00

 如果写过设备驱动,就知道我们写驱动主要是为了实现一个设备驱动接口,一组
对设备操作的方法,我这里想简单地分析一下文件系统与设备驱动之间的接口。
先来看打开操作,我自己对文件系统也不是很了解,只知道在用户空间调用了open函数,
就会在内核中调用sys_open这个系统调用,原来的0.11内核都是通过int80x系统调用门
来实现的,不过这里似乎是直接调用的嘛,在include/asm-arm/unistd.h中
static inline long open(const char *file, int flag, int mode)
{
 extern long sys_open(const char *, int, int);
 return sys_open(file, flag, mode);
}
再来看fs/open.c中的sys_open函数
asmlinkage long sys_open(const char * filename, int flags, int mode)
{
 char * tmp;
 int fd, error;

#if BITS_PER_LONG != 32
 flags |= O_LARGEFILE;
#endif
 tmp = getname(filename);
 fd = PTR_ERR(tmp);
 if (!IS_ERR(tmp)) {
  fd = get_unused_fd(); //获取一个未用的文件指示符
  if (fd >= 0) {
   struct file *f = filp_open(tmp, flags, mode);
   //打开文件,建立file类型的结构并返回其指针
   error = PTR_ERR(f);
   if (IS_ERR(f))
    goto out_error;
   fd_install(fd, f);//把文件指示符和文件指针相关联
  }
out:
  putname(tmp);
 }
 return fd;
out_error:
 put_unused_fd(fd);
 fd = error;
 goto out;
}

这样主要是在filp_open中实现了打开操作。
struct file *filp_open(const char * filename, int flags, int mode)
{
 int namei_flags, error;
 struct nameidata nd;

 namei_flags = flags;
 if ((namei_flags+1) & O_ACCMODE)
  namei_flags++;
 if (namei_flags & O_TRUNC)
  namei_flags |= 2;

 error = open_namei(filename, namei_flags, mode, &nd);
 if (!error)
  return dentry_open(nd.dentry, nd.mnt, flags);

 return ERR_PTR(error);
}
关键是要知道是怎样得到file结构体的,首先当然是要读取设备文件对应的inode结构体
这是由函数open_namei实现的,然后dentry_open来建立file结构体。
struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
{
 struct file * f;
 struct inode *inode;
 static LIST_HEAD(kill_list);
 int error;

 error = -ENFILE;
 f = get_empty_filp(); //获取空的file结构体
 if (!f)
  goto cleanup_dentry;
 f->f_flags = flags;
 f->f_mode = (flags+1) & O_ACCMODE;
 inode = dentry->d_inode;
 if (f->f_mode & FMODE_WRITE) {
  error = get_write_access(inode);
  if (error)
   goto cleanup_file;
 }

 f->f_dentry = dentry;
 f->f_vfsmnt = mnt;
 f->f_pos = 0;
 f->f_reada = 0;
 f->f_op = fops_get(inode->i_fop); //获取设备的file_operations结构
 file_move(f, &inode->i_sb->s_files);

 /* preallocate kiobuf for O_DIRECT */
 f->f_iobuf = NULL;
 f->f_iobuf_lock = 0;
 if (f->f_flags & O_DIRECT) {
  error = alloc_kiovec(1, &f->f_iobuf);
  if (error)
   goto cleanup_all;
 }

 if (f->f_op && f->f_op->open) { //执行设备驱动中的open操作
  error = f->f_op->open(inode,f);
  if (error)
   goto cleanup_all;
 }
 f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

 return f;

cleanup_all:
 if (f->f_iobuf)
  free_kiovec(1, &f->f_iobuf);
 fops_put(f->f_op);
 if (f->f_mode & FMODE_WRITE)
  put_write_access(inode);
 file_move(f, &kill_list); /* out of the way.. */
 f->f_dentry = NULL;
 f->f_vfsmnt = NULL;
cleanup_file:
 put_filp(f);
cleanup_dentry:
 dput(dentry);
 mntput(mnt);
 return ERR_PTR(error);
}
不同的文件系统会使用不同的函数取获取inode结构,对于设备文件系统,我猜想在注册设备
建立节点的时候,其inode结构中的struct file_operations *i_fop成员变量就已经被赋值
为设备驱动的file_operations了。还是以/dev/console为例,其驱动注册的file_operations
是tty_fops,于是file结构中的f_op指向的就是tty_fops结构。于是代开操作就会调用到tty_fops
中的open函数。而对于普通文件,会有默认的file_operations结构,其open函数什么也不做。
对于用register_chrdev注册的设备,显然注册的时候驱动的file_operations结构的指针并没有
传给inode结构,因为其节点是可以在注册之前就建立的,其实对于字符设备在用mknod建立imode
时赋给的file_operations也是默认的def_chr_fops,在fs/devices.c中定义
static struct file_operations def_chr_fops = {
 open:  chrdev_open,
};
于是打开字符设备的时候都会执行chrdev_open
int chrdev_open(struct inode * inode, struct file * filp)
{
 int ret = -ENODEV;

 filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
 if (filp->f_op) {
  ret = 0;
  if (filp->f_op->open != NULL) {
   lock_kernel();
   ret = filp->f_op->open(inode,filp);
   unlock_kernel();
  }
 }
 return ret;
}
ok,在chrdev_open中又用filp->f_op重新赋值,这一次赋给的是真正的设备的file_operations指针于是下此使用read,write系统调用的时候,通过filp->f_op调用的函数就是真正设备的read,write函数了。

Linux 文件系统与设备文件系统 (一)—— udev 设备文件系统

一、什么是Linux设备文件系统       首先我们不看定义,定义总是太抽象很难理解,我们先看现象。当我们往开发板上移植了一个新的文件系统之后(假如各种设备驱动也移植好了),启动开发板,我们用串口工...
  • zqixiao_09
  • zqixiao_09
  • 2016年03月12日 10:55
  • 4224

Linux 文件系统与设备文件系统 (二)—— sysfs 文件系统与Linux设备模型

提到 sysfs 文件系统 ,必须先需要了解的是Linux设备模型,什么事Linux设备模型呢? 一、Linux 设备模型 1、设备模型概述      从2.6版本开始,Linux开发团队便为内核建立...
  • zqixiao_09
  • zqixiao_09
  • 2016年03月12日 12:19
  • 2622

内核、设备、驱动、文件系统、内核空间、用户空间

学习驱动过程中有一些疑问,记录下来,并希望能在2015-6-30之前能够有一个明确的答案。 一、当设备插上的时候,内核怎么发现设备并更新/sys、/dev、/proc文件系统、怎么通知给用户空间?更具...
  • faxiang1230
  • faxiang1230
  • 2015年05月30日 21:04
  • 1049

数据库存储类型:文件系统和裸设备

1、DMS类型的表空间容器可以是裸设备或者文件系统。数据库通常会在内存中开辟一片区域,成为buffer pool,应该尽可能让数据库的读写发生在这部分内存中。 同样文件系统中也开辟了一块buffer用...
  • dba_monkey
  • dba_monkey
  • 2017年03月09日 16:51
  • 556

Linux块设备/文件系统/分区查看

自己理解的作图,不知正确不正确,还请指正 ================================================================= 我系统是分配了16G的...
  • zhengshifeng123
  • zhengshifeng123
  • 2016年09月09日 13:40
  • 1425

Linux 字符设备驱动开发基础(六)—— VFS 虚拟文件系统解析

一、VFS 虚拟文件系统基础概念         Linux 允许众多不同的文件系统共存,并支持跨文件系统的文件操作,这是因为有虚拟文件系统的存在。虚拟文件系统,即VFS(Virtual File S...
  • zqixiao_09
  • zqixiao_09
  • 2016年03月11日 23:39
  • 2435

数与量的区别

平日里,我们经常是把“数”和“量”联系在一起使用的。这两个概念之间有什么不同呢?儿童是怎样认识量的?让我们一一来讨论。 我们知道,数可以表示事物的多少或事物的次序。而说到对“量”的认识,却似...
  • paxhujing
  • paxhujing
  • 2017年06月09日 11:24
  • 364

三大框架各自之间的作用

简单的说: struts 控制用的 hibernate 操作数据库的 spring用解耦的 详细的说: STRUTS 在 SSH 框架中起控制的作用 , 其核心是 Contr...
  • u012162153
  • u012162153
  • 2014年11月27日 09:53
  • 850

Linux 的虚拟文件系统--各结构之间的联系

http://scudong.blogbus.com/logs/11599350.htmlLinux 允许众多不同的文件系统共存,并支持跨文件系统的文件操作,这是因为有虚拟文件系统的存在。虚拟文件...
  • ztguang
  • ztguang
  • 2016年03月30日 10:29
  • 195

mac 登陆app store时提示:无法验证您的设备或电脑,请联系技术支持寻求帮助。

解决办法: 1.打开系统偏好设置: 2.选择网络: 3.先解锁左下角按钮: 4.然后点“向导”按钮 5....
  • dongtinghong
  • dongtinghong
  • 2016年06月21日 16:19
  • 7426
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:文件系统和设备之间的联系
举报原因:
原因补充:

(最多只允许输入30个字)