注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

转载:linux设备驱动模型一字符设备open系统调用流程2  

2012-12-27 10:44:50|  分类: LINUX内核驱动 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

谁想到博文发表还有字数限制,晕了。下面接着:

当内核要访问一个文件的时候,第一步要做的是找到这个文件,而查找文件的过程在vfs里面是由link_path_walk函数来完成的,在path_init的时候我们可以看到传进去的参数有一个LOOKUP_PARENT,它的含义是查找最后一个分量名所在的目录。也就是当这个函数返回的时候,我们得到了一个路径名中最后一个分量所在的目录。

接着调用do_last返回最后一个分量对应的file指针,我们关注一下这个函数

[cpp] view plaincopyprint?

1.  static struct file *do_last(struct nameidata *nd, struct path *path,  

2.                  int open_flag, int acc_mode,  

3.                  int mode, const char *pathname)  

4.  {  

5.      struct dentry *dir = nd->path.dentry;  

6.      struct file *filp;  

7.      int error = -EISDIR;  

8.    

9.      switch (nd->last_type) {// 检查最后一段文件或目录名的属性情况   

10.     case LAST_DOTDOT:  

11.         follow_dotdot(nd);  

12.         dir = nd->path.dentry;  

13.     case LAST_DOT:  

14.         if (nd->path.mnt->mnt_sb->s_type->fs_flags & FS_REVAL_DOT) {  

15.             if (!dir->d_op->d_revalidate(dir, nd)) {  

16.                 error = -ESTALE;  

17.                 goto exit;  

18.             }  

19.         }  

20.         /* fallthrough */  

21.     case LAST_ROOT:  

22.         if (open_flag & O_CREAT)  

23.             goto exit;  

24.         /* fallthrough */  

25.     case LAST_BIND:  

26.         audit_inode(pathname, dir);  

27.         goto ok;  

28.     }  

30.     /* trailing slashes? */  

31.     if (nd->last.name[nd->last.len]) {  

32.         if (open_flag & O_CREAT)  

33.             goto exit;  

34.         nd->flags |= LOOKUP_DIRECTORY | LOOKUP_FOLLOW;  

35.     }  

36.   

37.     /* just plain open? */  

38.     if (!(open_flag & O_CREAT)) {//没有创建标志,即文件存在   

39.         error = do_lookup(nd, &nd->last, path);//找到路径中最后一项对应的目录项   

40.         if (error)  

41.             goto exit;  

42.         error = -ENOENT;  

43.         if (!path->dentry->d_inode)  

44.             goto exit_dput;  

45.         if (path->dentry->d_inode->i_op->follow_link)  

46.             return NULL;  

47.         error = -ENOTDIR;  

48.         if (nd->flags & LOOKUP_DIRECTORY) {  

49.             if (!path->dentry->d_inode->i_op->lookup)  

50.                 goto exit_dput;  

51.         }  

52.         path_to_nameidata(path, nd);//赋值到nd结构   

53.         audit_inode(pathname, nd->path.dentry);  

54.         goto ok;  

55.     }  

56.   

57.     /* OK, it's O_CREAT */  

58.     //文件不存在,需要创建   

59.     mutex_lock(&dir->d_inode->i_mutex);  

60.   

61.     path->dentry = lookup_hash(nd);//获取最后路径名中最后一项对应的目录项   

62.     path->mnt = nd->path.mnt;  

63.   

64.     error = PTR_ERR(path->dentry);  

65.     if (IS_ERR(path->dentry)) {  

66.         mutex_unlock(&dir->d_inode->i_mutex);  

67.         goto exit;  

68.     }  

69.   

70.     if (IS_ERR(nd->intent.open.file)) {  

71.         error = PTR_ERR(nd->intent.open.file);  

72.         goto exit_mutex_unlock;  

73.     }  

74.   

75.     /* Negative dentry, just create the file */  

76.     if (!path->dentry->d_inode) {//没有索引节点与目录项关联   

77.         /* 

78.          * This write is needed to ensure that a 

79.          * ro->rw transition does not occur between 

80.          * the time when the file is created and when 

81.          * a permanent write count is taken through 

82.          * the 'struct file' in nameidata_to_filp(). 

83.          */  

84.         error = mnt_want_write(nd->path.mnt);  

85.         if (error)  

86.             goto exit_mutex_unlock;  

87.         error = __open_namei_create(nd, path, open_flag, mode);//创建相应的索引节点   

88.         if (error) {  

89.             mnt_drop_write(nd->path.mnt);  

90.             goto exit;  

91.         }  

92.         filp = nameidata_to_filp(nd);/*根据nameidata 得到相应的file结构*/  

93.         mnt_drop_write(nd->path.mnt);  

94.         if (!IS_ERR(filp)) {  

95.             error = ima_file_check(filp, acc_mode);  

96.             if (error) {  

97.                 fput(filp);  

98.                 filp = ERR_PTR(error);  

99.             }  

100.            }  

101.            return filp;  

102.        }     

104.        /* 

105.         * It already exists. 

106.         */  

107.        mutex_unlock(&dir->d_inode->i_mutex);  

108.        audit_inode(pathname, path->dentry);  

109.      

110.        error = -EEXIST;  

111.        if (open_flag & O_EXCL)  

112.            goto exit_dput;  

113.      

114.        if (__follow_mount(path)) {  

115.            error = -ELOOP;  

116.            if (open_flag & O_NOFOLLOW)  

117.                goto exit_dput;  

118.        }  

119.      

120.        error = -ENOENT;  

121.        if (!path->dentry->d_inode)  

122.            goto exit_dput;  

123.      

124.        if (path->dentry->d_inode->i_op->follow_link)  

125.            return NULL;  

126.      

127.        path_to_nameidata(path, nd);  

128.        error = -EISDIR;  

129.        if (S_ISDIR(path->dentry->d_inode->i_mode))  

130.            goto exit;  

131.    ok:  

132.        filp = finish_open(nd, open_flag, acc_mode);//完成文件打开操作   

133.        return filp;  

134.      

135.    exit_mutex_unlock:  

136.        mutex_unlock(&dir->d_inode->i_mutex);  

137.    exit_dput:  

138.        path_put_conditional(path, nd);  

139.    exit:  

140.        if (!IS_ERR(nd->intent.open.file))  

141.            release_open_intent(nd);  

142.        path_put(&nd->path);  

143.        return ERR_PTR(error);  

144.    }  

static struct file *do_last(struct nameidata *nd, struct path *path,

         int open_flag, int acc_mode,

         int mode, const char *pathname)

{

  struct dentry *dir = nd->path.dentry;

  struct file *filp;

  int error = -EISDIR;

 

  switch (nd->last_type) {// 检查最后一段文件或目录名的属性情况

  case LAST_DOTDOT:

   follow_dotdot(nd);

   dir = nd->path.dentry;

  case LAST_DOT:

   if (nd->path.mnt->mnt_sb->s_type->fs_flags & FS_REVAL_DOT) {

     if (!dir->d_op->d_revalidate(dir, nd)) {

      error = -ESTALE;

      goto exit;

     }

   }

   /* fallthrough */

  case LAST_ROOT:

   if (open_flag & O_CREAT)

     goto exit;

   /* fallthrough */

  case LAST_BIND:

   audit_inode(pathname, dir);

   goto ok;

  }

 

  /* trailing slashes? */

  if (nd->last.name[nd->last.len]) {

   if (open_flag & O_CREAT)

     goto exit;

   nd->flags |= LOOKUP_DIRECTORY | LOOKUP_FOLLOW;

  }

 

  /* just plain open? */

  if (!(open_flag & O_CREAT)) {//没有创建标志,即文件存在

   error = do_lookup(nd, &nd->last, path);//找到路径中最后一项对应的目录项

   if (error)

     goto exit;

   error = -ENOENT;

   if (!path->dentry->d_inode)

     goto exit_dput;

   if (path->dentry->d_inode->i_op->follow_link)

     return NULL;

   error = -ENOTDIR;

   if (nd->flags & LOOKUP_DIRECTORY) {

     if (!path->dentry->d_inode->i_op->lookup)

      goto exit_dput;

   }

   path_to_nameidata(path, nd);//赋值到nd结构

   audit_inode(pathname, nd->path.dentry);

   goto ok;

  }

  /* OK, it's O_CREAT */

  //文件不存在,需要创建

  mutex_lock(&dir->d_inode->i_mutex);

  path->dentry = lookup_hash(nd);//获取最后路径名中最后一项对应的目录项

  path->mnt = nd->path.mnt;

  error = PTR_ERR(path->dentry);

  if (IS_ERR(path->dentry)) {

   mutex_unlock(&dir->d_inode->i_mutex);

   goto exit;

  }

  if (IS_ERR(nd->intent.open.file)) {

   error = PTR_ERR(nd->intent.open.file);

   goto exit_mutex_unlock;

  }

 

  /* Negative dentry, just create the file */

  if (!path->dentry->d_inode) {//没有索引节点与目录项关联

   /*

    * This write is needed to ensure that a

    * ro->rw transition does not occur between

    * the time when the file is created and when

    * a permanent write count is taken through

    * the 'struct file' in nameidata_to_filp().

    */

   error = mnt_want_write(nd->path.mnt);

   if (error)

     goto exit_mutex_unlock;

   error = __open_namei_create(nd, path, open_flag, mode);//创建相应的索引节点

   if (error) {

     mnt_drop_write(nd->path.mnt);

     goto exit;

   }

   filp = nameidata_to_filp(nd);/*根据nameidata 得到相应的file结构*/

   mnt_drop_write(nd->path.mnt);

   if (!IS_ERR(filp)) {

     error = ima_file_check(filp, acc_mode);

     if (error) {

      fput(filp);

      filp = ERR_PTR(error);

     }

   }

   return filp;

  }

 

  /*

   * It already exists.

   */

  mutex_unlock(&dir->d_inode->i_mutex);

  audit_inode(pathname, path->dentry);

  error = -EEXIST;

  if (open_flag & O_EXCL)

   goto exit_dput;

  if (__follow_mount(path)) {

   error = -ELOOP;

   if (open_flag & O_NOFOLLOW)

     goto exit_dput;

  }

  error = -ENOENT;

  if (!path->dentry->d_inode)

   goto exit_dput;

  if (path->dentry->d_inode->i_op->follow_link)

   return NULL;

  path_to_nameidata(path, nd);

  error = -EISDIR;

  if (S_ISDIR(path->dentry->d_inode->i_mode))

   goto exit;

ok:

  filp = finish_open(nd, open_flag, acc_mode);//完成文件打开操作

  return filp;

 

exit_mutex_unlock:

  mutex_unlock(&dir->d_inode->i_mutex);

exit_dput:

  path_put_conditional(path, nd);

exit:

  if (!IS_ERR(nd->intent.open.file))

   release_open_intent(nd);

  path_put(&nd->path);

  return ERR_PTR(error);

}


首先进行一些判断,然后看是否需要创建文件,如果需要创建的,则创建文件。如果文件存在的话,直接调用finish_open完成文件打开,我们这里关注下打开文件的

[cpp] view plaincopyprint?

1.  static struct file *finish_open(struct nameidata *nd,  

2.                  int open_flag, int acc_mode)  

3.  {  

4.      struct file *filp;  

5.      int will_truncate;  

6.      int error;  

7.    

8.      /*检测是否截断文件标志*/  

9.      will_truncate = open_will_truncate(open_flag, nd->path.dentry->d_inode);  

10.     if (will_truncate) {/*要截断的话就要获取写权限*/  

11.         error = mnt_want_write(nd->path.mnt);  

12.         if (error)  

13.             goto exit;  

14.     }  

15.      //may_open执行权限检测、文件打开和truncate的操作   

16.     error = may_open(&nd->path, acc_mode, open_flag);  

17.     if (error) {  

18.         if (will_truncate)  

19.             mnt_drop_write(nd->path.mnt);  

20.         goto exit;  

21.     }  

22.     filp = nameidata_to_filp(nd);   /*根据nameidata 得到相应的file结构*/  

23.     if (!IS_ERR(filp)) {  

24.         error = ima_file_check(filp, acc_mode);  

25.         if (error) {  

26.             fput(filp);  

27.             filp = ERR_PTR(error);  

28.         }  

29.     }  

30.     if (!IS_ERR(filp)) {  

31.         if (will_truncate) {// //处理截断   

32.             error = handle_truncate(&nd->path);  

33.             if (error) {  

34.                 fput(filp);  

35.                 filp = ERR_PTR(error);  

36.             }  

37.         }  

38.     }  

39.     /* 

40.      * It is now safe to drop the mnt write 

41.      * because the filp has had a write taken 

42.      * on its behalf. 

43.      */  

44.     if (will_truncate)  //安全的放弃写权限   

45.         mnt_drop_write(nd->path.mnt);  

46.     return filp;  

47.   

48. exit:  

49.     if (!IS_ERR(nd->intent.open.file))  

50.         release_open_intent(nd);  

51.     path_put(&nd->path);  

52.     return ERR_PTR(error);  

53. }  

static struct file *finish_open(struct nameidata *nd,

       int open_flag, int acc_mode)

{

  struct file *filp;

  int will_truncate;

  int error;

 

  /*检测是否截断文件标志*/

  will_truncate = open_will_truncate(open_flag, nd->path.dentry->d_inode);

  if (will_truncate) {/*要截断的话就要获取写权限*/

    error = mnt_want_write(nd->path.mnt);

    if (error)

     goto exit;

  }

   //may_open执行权限检测、文件打开和truncate的操作

  error = may_open(&nd->path, acc_mode, open_flag);

  if (error) {

    if (will_truncate)

     mnt_drop_write(nd->path.mnt);

    goto exit;

  }

  filp = nameidata_to_filp(nd);   /*根据nameidata 得到相应的file结构*/

  if (!IS_ERR(filp)) {

    error = ima_file_check(filp, acc_mode);

    if (error) {

     fput(filp);

     filp = ERR_PTR(error);

    }

  }

  if (!IS_ERR(filp)) {

    if (will_truncate) {// //处理截断

     error = handle_truncate(&nd->path);

     if (error) {

       fput(filp);

       filp = ERR_PTR(error);

     }

    }

  }

  /*

   * It is now safe to drop the mnt write

   * because the filp has had a write taken

   * on its behalf.

   */

  if (will_truncate)  //安全的放弃写权限

    mnt_drop_write(nd->path.mnt);

  return filp;

 

exit:

  if (!IS_ERR(nd->intent.open.file))

    release_open_intent(nd);

  path_put(&nd->path);

  return ERR_PTR(error);

}

这里主要调用nameidata_to_filp得到相应的file结构

[cpp] view plaincopyprint?

1.  struct file *nameidata_to_filp(struct nameidata *nd)  

2.  {  

3.      const struct cred *cred = current_cred();  

4.      struct file *filp;  

5.    

6.      /* Pick up the filp from the open intent */  

7.      filp = nd->intent.open.file;/// 把相关 file结构的指针赋予 filp   

8.      /* Has the filesystem initialised the file for us? */  

9.      if (filp->f_path.dentry == NULL)  

10.         filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp,  

11.                      NULL, cred);  

12.     else  

13.         path_put(&nd->path);  

14.     return filp;  

15. }  

struct file *nameidata_to_filp(struct nameidata *nd)

{

  const struct cred *cred = current_cred();

  struct file *filp;

 

  /* Pick up the filp from the open intent */

  filp = nd->intent.open.file;/// 把相关 file结构的指针赋予 filp

  /* Has the filesystem initialised the file for us? */

  if (filp->f_path.dentry == NULL)

   filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp,

           NULL, cred);

  else

   path_put(&nd->path);

  return filp;

}


调用__dentry_open

[cpp] view plaincopyprint?

1.  static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,  

2.                      struct file *f,  

3.                      int (*open)(struct inode *, struct file *),  

4.                      const struct cred *cred)  

5.  {  

6.      struct inode *inode;  

7.      int error;  

8.    

9.      f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |//初始化f_mode   

10.                 FMODE_PREAD | FMODE_PWRITE;  

11.     inode = dentry->d_inode;  

12.     if (f->f_mode & FMODE_WRITE) {  

13.         error = __get_file_write_access(inode, mnt);  

14.         if (error)  

15.             goto cleanup_file;  

16.         if (!special_file(inode->i_mode))  

17.             file_take_write(f);  

18.     }  

19.   

20.     f->f_mapping = inode->i_mapping;  

21.     f->f_path.dentry = dentry;//初始化目录项对象   

22.     f->f_path.mnt = mnt;//初始化文件系统对象   

23.     f->f_pos = 0;  

24.     f->f_op = fops_get(inode->i_fop);//为文件操作建立起所有方法   

25.     file_move(f, &inode->i_sb->s_files);//把文件对象插入到文件系统超级块的s_files字段所指向的打开文件的链表。   

26.   

27.     error = security_dentry_open(f, cred);  

28.     if (error)  

29.         goto cleanup_all;  

30.   

31.     if (!open && f->f_op)//传进来的open为NULL   

32.         open = f->f_op->open;  

33.     if (open) {  

34.         error = open(inode, f);  

35.         if (error)  

36.             goto cleanup_all;  

37.     }  

38.     ima_counts_get(f);  

39.   

40.     f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);//初始化f_f_flags   

41.   

42.     file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);//初始化预读的数据结构   

43.   

44.     /* NB: we're sure to have correct a_ops only after f_op->open */  

45.     if (f->f_flags & O_DIRECT) {//检查直接IO操作是否可以作用于文件   

46.         if (!f->f_mapping->a_ops ||  

47.             ((!f->f_mapping->a_ops->direct_IO) &&  

48.             (!f->f_mapping->a_ops->get_xip_mem))) {  

49.             fput(f);  

50.             f = ERR_PTR(-EINVAL);  

51.         }  

52.     }  

53.   

54.     return f;  

55.   

56. cleanup_all:  

57.     fops_put(f->f_op);  

58.     if (f->f_mode & FMODE_WRITE) {  

59.         put_write_access(inode);  

60.         if (!special_file(inode->i_mode)) {  

61.             /* 

62.              * We don't consider this a real 

63.              * mnt_want/drop_write() pair 

64.              * because it all happenend right 

65.              * here, so just reset the state. 

66.              */  

67.             file_reset_write(f);  

68.             mnt_drop_write(mnt);  

69.         }  

70.     }  

71.     file_kill(f);  

72.     f->f_path.dentry = NULL;  

73.     f->f_path.mnt = NULL;  

74. cleanup_file:  

75.     put_filp(f);  

76.     dput(dentry);  

77.     mntput(mnt);  

78.     return ERR_PTR(error);  

79. }  

static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,

         struct file *f,

         int (*open)(struct inode *, struct file *),

         const struct cred *cred)

{

  struct inode *inode;

  int error;

 

  f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |//初始化f_mode

       FMODE_PREAD | FMODE_PWRITE;

  inode = dentry->d_inode;

  if (f->f_mode & FMODE_WRITE) {

    error = __get_file_write_access(inode, mnt);

    if (error)

     goto cleanup_file;

    if (!special_file(inode->i_mode))

     file_take_write(f);

  }

 

  f->f_mapping = inode->i_mapping;

  f->f_path.dentry = dentry;//初始化目录项对象

  f->f_path.mnt = mnt;//初始化文件系统对象

  f->f_pos = 0;

  f->f_op = fops_get(inode->i_fop);//为文件操作建立起所有方法

  file_move(f, &inode->i_sb->s_files);//把文件对象插入到文件系统超级块的s_files字段所指向的打开文件的链表。

 

  error = security_dentry_open(f, cred);

  if (error)

    goto cleanup_all;

 

  if (!open && f->f_op)//传进来的open为NULL

    open = f->f_op->open;

  if (open) {

    error = open(inode, f);

    if (error)

     goto cleanup_all;

  }

  ima_counts_get(f);

 

  f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);//初始化f_f_flags

 

  file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);//初始化预读的数据结构

 

  /* NB: we're sure to have correct a_ops only after f_op->open */

  if (f->f_flags & O_DIRECT) {//检查直接IO操作是否可以作用于文件

    if (!f->f_mapping->a_ops ||

        ((!f->f_mapping->a_ops->direct_IO) &&

        (!f->f_mapping->a_ops->get_xip_mem))) {

     fput(f);

     f = ERR_PTR(-EINVAL);

    }

  }

 

  return f;

 

cleanup_all:

  fops_put(f->f_op);

  if (f->f_mode & FMODE_WRITE) {

    put_write_access(inode);

    if (!special_file(inode->i_mode)) {

     /*

      * We don't consider this a real

      * mnt_want/drop_write() pair

      * because it all happenend right

      * here, so just reset the state.

      */

     file_reset_write(f);

     mnt_drop_write(mnt);

    }

  }

  file_kill(f);

  f->f_path.dentry = NULL;

  f->f_path.mnt = NULL;

cleanup_file:

  put_filp(f);

  dput(dentry);

  mntput(mnt);

  return ERR_PTR(error);

}

这里主要是进行一些赋值操作

对应于这里,传进来的open指针为NULL, 如果相应file_operations结构存在的话就调用它的open函数

对于每个文件在创建 的时候会赋值对其进行操作的file_operations结构,这个结构对于一类文件是一样的,例如 对应于字符设备是chrdev_open

[cpp] view plaincopyprint?

1.  const struct file_operations def_chr_fops = {  

2.      .open = chrdev_open,  

3.  };  

const struct file_operations def_chr_fops = {

  .open = chrdev_open,

};
但打开之后,我们可以重新获取它们的file_operations结构,这个是在注册设备驱动的时候为该类设备赋予的,也就是我们在驱动里面实现的,而前面的缺省file_operations就是为了完成这个转换的,def_chr_fops只起过渡作用,它的open方法要去寻找硬件驱动的支撑。

 

[cpp] view plaincopyprint?

1.  static int chrdev_open(struct inode *inode, struct file *filp)  

2.  {  

3.      struct cdev *p;  

4.      struct cdev *new = NULL;  

5.      int ret = 0;  

6.    

7.      spin_lock(&cdev_lock);  

8.      p = inode->i_cdev;  

9.      if (!p) { /* 很显然,第一次打开的时候是NULL */  

10.         struct kobject *kobj;  

11.         int idx;  

12.         spin_unlock(&cdev_lock);  

13.         kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);/* 找到和设备号i_rdev对应的kobj,其实就是cdev了,因为cdev中包含kobj;idx保存的是次设备号,后面会分析kobj_lookup()函数 */  

14.         if (!kobj)  

15.             return -ENXIO;  

16.         new = container_of(kobj, struct cdev, kobj);//得到cdev   

17.         spin_lock(&cdev_lock);  

18.         /* Check i_cdev again in case somebody beat us to it while 

19.            we dropped the lock. */  

20.         p = inode->i_cdev;  

21.         if (!p) {  

22.             inode->i_cdev = p = new;/* 把找到的cdev保存到inode的icdev中 */  

23.             list_add(&inode->i_devices, &p->list); /* inode加入到cdev的链表中 */  

24.             new = NULL;  

25.         } else if (!cdev_get(p))  

26.             ret = -ENXIO;  

27.     } else if (!cdev_get(p))  

28.         ret = -ENXIO;  

29.     spin_unlock(&cdev_lock);  

30.     cdev_put(new);  

31.     if (ret)  

32.         return ret;  

33.   

34.     ret = -ENXIO;  

35.     /*  

36.     保存用户的fops,以后你再调用read, write, ioctl系统调用的时候就直接使用了,你懂的  

37.     */  

38.     filp->f_op = fops_get(p->ops);  

39.     if (!filp->f_op) // 如果你没有注册fops   

40.         goto out_cdev_put;  

41.   

42.     if (filp->f_op->open) {//判断open函数是否存在   

43.         ret = filp->f_op->open(inode,filp);//* 调用用户的open函数,我们前面写的驱动   

44.         if (ret)  

45.             goto out_cdev_put;  

46.     }  

47.   

48.     return 0;  

49.   

50.  out_cdev_put:  

51.     cdev_put(p);  

52.     return ret;  

53. }  

static int chrdev_open(struct inode *inode, struct file *filp)

{

  struct cdev *p;

  struct cdev *new = NULL;

  int ret = 0;

 

  spin_lock(&cdev_lock);

  p = inode->i_cdev;

  if (!p) { /* 很显然,第一次打开的时候是NULL */

    struct kobject *kobj;

    int idx;

    spin_unlock(&cdev_lock);

    kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);/* 找到和设备号i_rdev对应的kobj,其实就是cdev了,因为cdev中包含kobj;idx保存的是次设备号,后面会分析kobj_lookup()函数 */

    if (!kobj)

     return -ENXIO;

    new = container_of(kobj, struct cdev, kobj);//得到cdev

    spin_lock(&cdev_lock);

    /* Check i_cdev again in case somebody beat us to it while

       we dropped the lock. */

    p = inode->i_cdev;

    if (!p) {

     inode->i_cdev = p = new;/* 把找到的cdev保存到inode的icdev中 */

     list_add(&inode->i_devices, &p->list); /* inode加入到cdev的链表中 */

     new = NULL;

    } else if (!cdev_get(p))

     ret = -ENXIO;

  } else if (!cdev_get(p))

    ret = -ENXIO;

  spin_unlock(&cdev_lock);

  cdev_put(new);

  if (ret)

    return ret;

  ret = -ENXIO;

  /*

  保存用户的fops,以后你再调用read, write, ioctl系统调用的时候就直接使用了,你懂的

  */

  filp->f_op = fops_get(p->ops);

  if (!filp->f_op) // 如果你没有注册fops

    goto out_cdev_put;

 

  if (filp->f_op->open) {//判断open函数是否存在

    ret = filp->f_op->open(inode,filp);//* 调用用户的open函数,我们前面写的驱动

    if (ret)

     goto out_cdev_put;

  } 

  return 0;

 out_cdev_put:

  cdev_put(p);

  return ret;

}

在这个函数里,我们重新 对f_op赋值了,这里的f_op就是我们在写驱动时写的系统调用函数了。后面还调用了open方法

这里调用 kobj_lookup找到前面我们在注册驱动添加设备时添加的相应的kobj

[cpp] view plaincopyprint?

1.  struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)  

2.  {  

3.      struct kobject *kobj;  

4.      struct probe *p;  

5.      unsigned long best = ~0UL;  

6.    

7.  retry:  

8.      mutex_lock(domain->lock);  

9.       /* 根据主设备号和设备号查找它的一亩三分地。因为要支持2^12次方也就是4096个主设备号, 

10.      但只使用了前255个主设备号索引,所以这255个索引对应的probe结构都有一个单向 

11.      链表保存着大于255的主设备号(被255整除后的索引相等)  */  

12.     for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {  

13.         struct kobject *(*probe)(dev_t, int *, void *);  

14.         struct module *owner;  

15.         void *data;  

16.         // 比较,看是否真找到了,因为有链表存在   

17.         if (p->dev > dev || p->dev + p->range - 1 < dev)  

18.             continue;  

19.         if (p->range - 1 >= best)  

20.             break;  

21.         if (!try_module_get(p->owner))  

22.             continue;  

23.         owner = p->owner;  

24.         data = p->data;//data就是cdev   

25.         probe = p->get;  

26.         best = p->range - 1;  

27.         *index = dev - p->dev;//得到次设备号   

28.           /* 调用的lock就是exact_lock()函数,增加对该字符设备驱动的引用,防止被卸载什么的 */  

29.         if (p->lock && p->lock(dev, data) < 0) {  

30.             module_put(owner);  

31.             continue;  

32.         }  

33.         mutex_unlock(domain->lock);  

34.          /*调用的probe就是exact_match()函数,获取cdev的kobj指针 */  

35.         kobj = probe(dev, index, data);  

36.         /* Currently ->owner protects _only_ ->probe() itself. */  

37.         module_put(owner);  

38.         if (kobj)  

39.             return kobj;  

40.         goto retry;  

41.     }  

42.     mutex_unlock(domain->lock);  

43.     return NULL;  

44. }  

struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)

{

  struct kobject *kobj;

  struct probe *p;

  unsigned long best = ~0UL; 

retry:

  mutex_lock(domain->lock);

   /* 根据主设备号和设备号查找它的一亩三分地。因为要支持2^12次方也就是4096个主设备号,

   但只使用了前255个主设备号索引,所以这255个索引对应的probe结构都有一个单向

   链表保存着大于255的主设备号(被255整除后的索引相等)  */

  for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {

   struct kobject *(*probe)(dev_t, int *, void *);

   struct module *owner;

   void *data;

   // 比较,看是否真找到了,因为有链表存在

   if (p->dev > dev || p->dev + p->range - 1 < dev)

     continue;

   if (p->range - 1 >= best)

     break;

   if (!try_module_get(p->owner))

     continue;

   owner = p->owner;

   data = p->data;//data就是cdev

   probe = p->get;

   best = p->range - 1;

   *index = dev - p->dev;//得到次设备号

     /* 调用的lock就是exact_lock()函数,增加对该字符设备驱动的引用,防止被卸载什么的 */

   if (p->lock && p->lock(dev, data) < 0) {

     module_put(owner);

     continue;

   }

   mutex_unlock(domain->lock);

    /*调用的probe就是exact_match()函数,获取cdev的kobj指针 */

   kobj = probe(dev, index, data);

   /* Currently ->owner protects _only_ ->probe() itself. */

   module_put(owner);

   if (kobj)

     return kobj;

   goto retry;

  }

  mutex_unlock(domain->lock);

  return NULL;

}
到这里do_filp_open的流程就基本完成了,即返回了一个file结构

[cpp] view plaincopyprint?

1.  void fd_install(unsigned int fd, struct file *file)  

2.  {  

3.      struct files_struct *files = current->files;  

4.      struct fdtable *fdt;  

5.      spin_lock(&files->file_lock);  

6.      fdt = files_fdtable(files);//获取fdtbale   

7.      BUG_ON(fdt->fd[fd] != NULL);  

8.      rcu_assign_pointer(fdt->fd[fd], file);//fd和file关系到fdtbale   

9.      spin_unlock(&files->file_lock);  

10. }  

void fd_install(unsigned int fd, struct file *file)

{

  struct files_struct *files = current->files;

  struct fdtable *fdt;

  spin_lock(&files->file_lock);

  fdt = files_fdtable(files);//获取fdtbale

  BUG_ON(fdt->fd[fd] != NULL);

  rcu_assign_pointer(fdt->fd[fd], file);//fd和file关系到fdtbale

  spin_unlock(&files->file_lock);

这样,我们的open系统调用就基本上完成了,我们得到一个fd,这个fd关联着一个file结构,这样以后,我们就可以通过这个fd结构操作相应的文件了

最后还是一样看下整个简略的流程图 

转载:linux设备驱动模型一字符设备open系统调用流程2 - 还东国 - 还东国的博客 
  评论这张
 
阅读(1282)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017