Chinaunix首页 | 论坛 | 博客
  • 博客访问: 595526
  • 博文数量: 229
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2183
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

just for fun

文章分类

全部博文(229)

文章存档

2021年(1)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友

分类: LINUX

2020-12-07 09:38:33

本文摘自http://www.embedu.org/Column/Column249.htm
在我们目前的Linux系统中,我们大概共约300左右个系统调用,其中syscall_table.S列出了所有的系统调用表。

在本文件中记录了所有当前平台系统中所提供的系统调用表,其中第五项就包括:

.long sys_open /* 5 */

-----------------------------
        查看sys_open() 函数,我们看到里面所完成的工作为:
        1、查看打开的是否是大文件,如果是的话,置大文件标志位:O_LARGEFILE
        2、做do_sys_open()函数调用。
        3、检查2的调用返回值ret是否有效。
        -----------------------------

-----------------------------
        查看do_sys_open()函数所完成的工作为:
        调用getname() ,getname函数主要功能是在使用文件名之前将其拷贝到内核数据区,正常结束时返回内核分配的空间首地址,出错时返回错误代码。
        取得系统中可用的文件描述符fd。
        调用do_filp_open()函数,此函数使用了一个数据结构nameidata来描述与文件相关的文件操作。

struct nameidata {
                struct dentry                *dentry;        // 目录数据
                struct vfsmount        *mnt;        // 虚拟文件挂载点数据
                struct qstr        last;        // hash值
                unsigned int        flags;        // 文件操作标识
                int last_type;        // 类型
                unsigned                depth;
                char                        *saved_names[MAX_NESTED_LINKS + 1];
                union {
                struct open_intent open;
                } intent; // 专用数据
        };
        -----------------------------

-----------------------------
        struct file *do_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++;        // 如果flags有O_WRONLY,则增加O_RDONLY

                error = open_namei(filename, namei_flags, mode, &nd);
                                // open_namei函数主要执行文件操作的inode部分的打开等操作。
                if (!error)
                        return nameidata_to_filp (nd, flags);
                                // 把文件的inod相关信息转换成文件结构。
                return ERR_PTR(error);        // 返回错误代码
        }
        -----------------------------

-----------------------------
        我们下面来看这个比较关键的函数:nameidata_to_filp():
        struct file *(struct nameidata *nd, int flags)
        821 {
        822        struct file *filp;
        823
        824        /* Pick up the filp from the open intent */
        825        filp = nd->intent.open.file;
                                                // 把相关 file结构的指针赋予 filp。
        826        /* Has the filesystem initialised the file for us? */
        827        if (filp->f_path.dentry == NULL)
        828                filp = __dentry_open(nd->dentry, nd->mnt, flags, filp, NULL);
                                                // ***** 关键函数 ***** //
        829        else
        830                path_release(nd);
        831        return filp;
        832 }
        -----------------------------

-----------------------------
        关键函数:__dentry_open():
        static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
                                                int flags, struct file *f,
                                                int (*open)(struct inode *, struct file *))
        {
                        ......
        695        f->f_pos = 0;
        696        f->f_op = fops_get(inode->i_fop);
                                                // 在这里进行赋值,f->f_op = &def_chr_fops,注意上文inode->i_fop中的赋值。
        697        file_move(f, &inode->i_sb->s_files);
        698
        699        if (!open && f->f_op)
                                                // 在调用__dentry_open时open赋值为空,所以!open为真。
        700                        open = f->f_op->open;
                                                // 在这里将open赋为chrdev_open。
        701        if (open) {
        702                        error = open(inode, f);
                                                // 这里调用chrdev_open, 参照下文。
        703                        if (error)
        704                                goto cleanup_all;
                        ......
        }
        -----------------------------

-----------------------------
        在函数chrdev_open中(/fs/char_dev.v):
        int chrdev_open(struct inode * inode, struct file * filp)
        {
                ......
                kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
                                                // 执行kobj_lookup函数,在cdev_map里寻找相应的inode->i_rdev设备。
                                                // cdev_map是一个256个probe结构组成的数组,用于查找具有相应设备号的设备。
                                                // inode->i_rdev为设备号。

        new = container_of(kobj, struct cdev, kobj);
                                                //从kobj的位置倒算出cdev的内存地址,获得包含相应kobj的cdev。

        inode->i_cdev = p = new;
                                                // 到这里p已经为我们要的设备cdev了。

        filp->f_op = fops_get(p->ops);
                                                / /拿到 cdev操作集。
                                                // 至此以后read,write操作都通过file->f_op直接与我们要的设备操作集挂钩了。
                ......
        }
        -----------------------------

到此,系统通过file->f_op 就与我们在设备驱动里面的定义的相关操作联系起来了,我们之前在写驱动实现的功能操作就被系统通过应用层的open 一步一步的调用到我们自己的open跟相关其他的操作了。

阅读(5511) | 评论(0) | 转发(0) |
1

上一篇:linux kernel之在驱动中增加异步通知的例子

下一篇:没有了

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