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

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

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

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

  下载LOFTER 我的照片书  |

说明一下:虽然这篇文章分类到内核驱动里,但标签用内核USB的原因是在写USB驱动时查到的。 

 http://blog.csdn.net/new_abc/article/details/7607731

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

从前面 的例子可以看到,我们在操作一个调和时都 是通过open系统调用先去打开这个设备,不管是设备还是文件,我们要访问它都要称通过open函数来先打开, 这样才能调用其它的函数如read、write来操作它,即通知内核新建一个代表该文件的结构,并且返回该文件的描述符(一个整数),该描述符在进程内唯一。

在linux系统进程中,分为内核空间和用户空间,当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(内核态)。在内核态下,CPU可执行任何指令。当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。用户态不能访问内核空间,包括代码和数据。所有进程的内核空间(3G-4G)都是共享的。当我们在用户空间调用open之后,会产生一个软中断,然后通过系统调用进入内核空间。通过系统调用号,我们就可以跳转到该中断例程的入口地址。

这里分析一下open的调用流程.

open()的格式如下:

int open(const char * pathname,int oflag, mode_t mode )
pathname:代表需要打开的文件的文件名;
oflag:表示打开的标识,具体的内核支持如下标记位(include\asm-generic\fcntl.h):

[cpp] view plaincopyprint?

1.  #define O_ACCMODE   00000003   

2.  #define O_RDONLY    00000000  //只读打开   

3.  #define O_WRONLY    00000001  //只写打开   

4.  #define O_RDWR      00000002  //读写打开   

5.  #ifndef O_CREAT   

6.  #define O_CREAT     00000100    //文件不存在则创建,需要mode_t   

7.  #endif   

8.  #ifndef O_EXCL   

9.  #define O_EXCL      00000200    //如果同时指定了O_CREAT,而文件已经存在,则出错    

10. #endif   

11. #ifndef O_NOCTTY   

12. #define O_NOCTTY    00000400    //如果pathname代表终端设备,则不将此设备分配作为此进程的控制终端   

13. #endif   

14. #ifndef O_TRUNC   

15. #define O_TRUNC     00001000    //如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0    

16. #endif   

17. #ifndef O_APPEND   

18. #define O_APPEND    00002000    //每次写时都加到文件的尾端   

19. #endif   

20. #ifndef O_NONBLOCK   

21. #define O_NONBLOCK  00004000     //如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I / O操作设置非阻塞   

22. #endif   

23. #ifndef O_SYNC   

24. #define O_SYNC      00010000    //使每次write都等到物理I/O操作完成   

25. #endif   

26. #ifndef FASYNC   

27. #define FASYNC      00020000    //兼容BSD的fcntl同步操作   

28. #endif   

29. #ifndef O_DIRECT   

30. #define O_DIRECT    00040000    //直接磁盘操作标识,每次读写都不使用内核提供的缓存,直接读写磁盘设备   

31. #endif   

32. #ifndef O_LARGEFILE   

33. #define O_LARGEFILE 00100000    // 大文件标识   

34. #endif   

35. #ifndef O_DIRECTORY   

36. #define O_DIRECTORY 00200000    //必须是目录   

37. #endif   

38. #ifndef O_NOFOLLOW   

39. #define O_NOFOLLOW  00400000    //不获取连接文件   

40. #endif   

41. #ifndef O_NOATIME   

42. #define O_NOATIME   01000000   

43. #endif   

44. #ifndef O_CLOEXEC   

45. #define O_CLOEXEC   02000000    /* set close_on_exec */   

46. #endif   

47. #ifndef O_NDELAY   

48. #define O_NDELAY    O_NONBLOCK   

49. #endif  

#define O_ACCMODE  00000003

#define O_RDONLY  00000000  //只读打开

#define O_WRONLY  00000001  //只写打开

#define O_RDWR   00000002  //读写打开

#ifndef O_CREAT

#define O_CREAT   00000100  //文件不存在则创建,需要mode_t

#endif

#ifndef O_EXCL

#define O_EXCL   00000200  //如果同时指定了O_CREAT,而文件已经存在,则出错

#endif

#ifndef O_NOCTTY

#define O_NOCTTY  00000400  //如果pathname代表终端设备,则不将此设备分配作为此进程的控制终端

#endif

#ifndef O_TRUNC

#define O_TRUNC   00001000  //如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0

#endif

#ifndef O_APPEND

#define O_APPEND  00002000    //每次写时都加到文件的尾端

#endif

#ifndef O_NONBLOCK

#define O_NONBLOCK  00004000     //如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I / O操作设置非阻塞

#endif

#ifndef O_SYNC

#define O_SYNC   00010000   //使每次write都等到物理I/O操作完成

#endif

#ifndef FASYNC

#define FASYNC   00020000  //兼容BSD的fcntl同步操作

#endif

#ifndef O_DIRECT

#define O_DIRECT  00040000  //直接磁盘操作标识,每次读写都不使用内核提供的缓存,直接读写磁盘设备

#endif

#ifndef O_LARGEFILE

#define O_LARGEFILE  00100000  // 大文件标识

#endif

#ifndef O_DIRECTORY

#define O_DIRECTORY  00200000  //必须是目录

#endif

#ifndef O_NOFOLLOW

#define O_NOFOLLOW  00400000  //不获取连接文件

#endif

#ifndef O_NOATIME

#define O_NOATIME  01000000

#endif

#ifndef O_CLOEXEC

#define O_CLOEXEC  02000000  /* set close_on_exec */

#endif

#ifndef O_NDELAY

#define O_NDELAY  O_NONBLOCK

#endif

 

当新创建一个文件时,需要指定mode参数,以下说明的格式如宏定义名称<实际常数值>:
 描述如下(include\linux\stat.h):

[cpp] view plaincopyprint?

1.  #define S_IRWXU 00700   //文件拥有者有读写执行权限   

2.  #define S_IRUSR 00400   //文件拥有者仅有读权限       

3.  #define S_IWUSR 00200   //文件拥有者仅有写权限   

4.  #define S_IXUSR 00100   //文件拥有者仅有执行权限   

5.    

6.  #define S_IRWXG 00070   //组用户有读写执行权限   

7.  #define S_IRGRP 00040   //组用户仅有读权限   

8.  #define S_IWGRP 00020   //组用户仅有写权限   

9.  #define S_IXGRP 00010   //组用户仅有执行权限   

10.   

11. #define S_IRWXO 00007   //其他用户有读写执行权限   

12. #define S_IROTH 00004   //其他用户仅有读权限   

13. #define S_IWOTH 00002   //其他用户仅有写权限   

14. #define S_IXOTH 00001   //其他用户仅有执行权限  

#define S_IRWXU 00700  //文件拥有者有读写执行权限

#define S_IRUSR 00400  //文件拥有者仅有读权限 

#define S_IWUSR 00200  //文件拥有者仅有写权限

#define S_IXUSR 00100  //文件拥有者仅有执行权限

 

#define S_IRWXG 00070  //组用户有读写执行权限

#define S_IRGRP 00040  //组用户仅有读权限

#define S_IWGRP 00020  //组用户仅有写权限

#define S_IXGRP 00010  //组用户仅有执行权限

 

#define S_IRWXO 00007  //其他用户有读写执行权限

#define S_IROTH 00004  //其他用户仅有读权限

#define S_IWOTH 00002  //其他用户仅有写权限

#define S_IXOTH 00001  //其他用户仅有执行权限

系统调用号定义在arch/x86/include/asm/unistd_32.h中:

[cpp] view plaincopyprint?

1.  #define __NR_restart_syscall      0   

2.  #define __NR_exit         1   

3.  #define __NR_fork         2   

4.  #define __NR_read         3   

5.  #define __NR_write        4   

6.  #define __NR_open         5   

7.  #define __NR_close        6   

8.  #define __NR_waitpid          7   

9.  #define __NR_creat        8   

10. #define __NR_link         9   

11. #define __NR_unlink      10   

12. #define __NR_execve      11   

13. #define __NR_chdir       12   

14. #define __NR_time        13   

15. #define __NR_mknod       14   

16. #define __NR_chmod       15  

#define __NR_restart_syscall      0

#define __NR_exit      1

#define __NR_fork      2

#define __NR_read      3

#define __NR_write      4

#define __NR_open      5

#define __NR_close      6

#define __NR_waitpid      7

#define __NR_creat      8

#define __NR_link      9

#define __NR_unlink    10

#define __NR_execve    11

#define __NR_chdir    12

#define __NR_time    13

#define __NR_mknod    14

#define __NR_chmod    15

当open系统调用产生时,就会进入下面这个函数():

[cpp] view plaincopyprint?

1.  SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)  

2.  {  

3.      long ret;  

4.    

5.      /*检查是否应该不考虑用户层传递的标志、总是强行设置  

6.      O_LARGEFILE标志。如果底层处理器的字长不是32位,就是这种  

7.      情况*/   

8.      if (force_o_largefile())  

9.          flags |= O_LARGEFILE;  

10.      /*实际工作*/   

11.     ret = do_sys_open(AT_FDCWD, filename, flags, mode);  

12.     /* avoid REGPARM breakage on x86: */  

13.     asmlinkage_protect(3, ret, filename, flags, mode);  

14.     return ret;  

15. }  

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)

{

  long ret;

 

  /*检查是否应该不考虑用户层传递的标志、总是强行设置

    O_LARGEFILE标志。如果底层处理器的字长不是32位,就是这种

    情况*/

  if (force_o_largefile())

   flags |= O_LARGEFILE;

   /*实际工作*/

  ret = do_sys_open(AT_FDCWD, filename, flags, mode);

  /* avoid REGPARM breakage on x86: */

  asmlinkage_protect(3, ret, filename, flags, mode);

  return ret;

}

我们看下SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode) 展开是怎么样的

首先看下宏SYSCALL_DEFINE3

[cpp] view plaincopyprint?

1.  #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)  

#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)

再看下SYSCALL_DEFINEx

[cpp] view plaincopyprint?

1.  #define SYSCALL_DEFINEx(x, sname, ...)              \   

2.      __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)  

#define SYSCALL_DEFINEx(x, sname, ...)       \

  __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

再看下__SYSCALL_DEFINEx   

[cpp] view plaincopyprint?

1.  #define __SYSCALL_DEFINEx(x, name, ...)                 \   

2.      asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))  

#define __SYSCALL_DEFINEx(x, name, ...)         \

  asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))

这里对对应__SC_DECL3

[cpp] view plaincopyprint?

1.  #define __SC_DECL1(t1, a1)  t1 a1   

2.  #define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__)   

3.  #define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__)  

#define __SC_DECL1(t1, a1)  t1 a1

#define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__)

#define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__)

这们一步步展开SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)代替进去,可以得到 

[cpp] view plaincopyprint?

1.  SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)  

2.   = SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)   

3.  =asmlinkage long sys_open(__SC_DECL3(__VA_ARGS__))  

4.  =asmlinkage long sys_open(const char __user* filename, int flags, int mode)  

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)

 = SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)

=asmlinkage long sys_open(__SC_DECL3(__VA_ARGS__))

=asmlinkage long sys_open(const char __user* filename, int flags, int mode)

这个才是真正的函数原型

在sys_open里面继续调用do_sys_open完成 open操作

[cpp] view plaincopyprint?

1.  long do_sys_open(int dfd, const char __user *filename, int flags, int mode)  

2.  {  

3.       /*从进程地址空间读取该文件的路径名*/    

4.      char *tmp = getname(filename);  

5.      int fd = PTR_ERR(tmp);  

6.    

7.      if (!IS_ERR(tmp)) {  

8.           /*在内核中,每个打开的文件由一个文件描述符表示  

9.          该描述符在特定于进程的数组中充当位置索引(数组是  

10.         task_struct->files->fd_arry),该数组的元素包含了file结构,其中  

11.         包括每个打开文件的所有必要信息。因此,调用下面  

12.         函数查找一个未使用的文件描述符,返回的是上面  

13.         说的数组的下标*/    

14.         fd = get_unused_fd_flags(flags);  

15.         if (fd >= 0) {  

16.             /*fd获取成功则开始打开文件,此函数是主要完成打开功能的函数*/  

17.             //如果分配fd成功,则创建一个file对象   

18.             struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);  

19.             if (IS_ERR(f)) {  

20.                 put_unused_fd(fd);  

21.                 fd = PTR_ERR(f);  

22.             } else {  

23.                 /*文件如果打开成功,调用fsnotify_open()函数,根据inode所指定的信息进行打开 

24.             函数(参数为f)将该文件加入到文件监控的系统中。该系统是用来监控文件被打开,创建, 

25.             读写,关闭,修改等操作的*/   

26.                 fsnotify_open(f->f_path.dentry);  

27.                 /*将文件指针安装在fd数组中 

28.             将struct file *f加入到fd索引位置处的数组中。如果后续过程中,有对该文件描述符的 

29.             操作的话,就会通过查找该数组得到对应的文件结构,而后在进行相关操作。*/  

30.                 fd_install(fd, f);  

31.             }  

32.         }  

33.         putname(tmp);  

34.     }  

35.     return fd;  

36. }  

long do_sys_open(int dfd, const char __user *filename, int flags, int mode)

{

   /*从进程地址空间读取该文件的路径名*/ 

  char *tmp = getname(filename);

  int fd = PTR_ERR(tmp);

  if (!IS_ERR(tmp)) {

    /*在内核中,每个打开的文件由一个文件描述符表示

        该描述符在特定于进程的数组中充当位置索引(数组是

        task_struct->files->fd_arry),该数组的元素包含了file结构,其中

        包括每个打开文件的所有必要信息。因此,调用下面

        函数查找一个未使用的文件描述符,返回的是上面

        说的数组的下标*/ 

   fd = get_unused_fd_flags(flags);

   if (fd >= 0) {

     /*fd获取成功则开始打开文件,此函数是主要完成打开功能的函数*/

     //如果分配fd成功,则创建一个file对象

     struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);

     if (IS_ERR(f)) {

      put_unused_fd(fd);

      fd = PTR_ERR(f);

     } else {

      /*文件如果打开成功,调用fsnotify_open()函数,根据inode所指定的信息进行打开

     函数(参数为f)将该文件加入到文件监控的系统中。该系统是用来监控文件被打开,创建,

     读写,关闭,修改等操作的*/

      fsnotify_open(f->f_path.dentry);

      /*将文件指针安装在fd数组中

     将struct file *f加入到fd索引位置处的数组中。如果后续过程中,有对该文件描述符的

     操作的话,就会通过查找该数组得到对应的文件结构,而后在进行相关操作。*/

      fd_install(fd, f);

     }

   }

   putname(tmp);

  }

  return fd;

该函数主要分为如下几个步骤来完成打开文件的操作:
1.将文件名参数从用户态拷贝至内核,调用函数get_name();
2.从进程的文件表中找到一个空闲的文件表指针,调用了函数get_unused_fd_flgas();
3.完成真正的打开操作,调用函数do_filp_open();
4.将打开的文件添加到进程的文件表数组中,调用函数fd_install();

getname函数主要的任务是将文件名filename从用户态拷贝至内核态

[cpp] view plaincopyprint?

1.  char * getname(const char __user * filename)  

2.  {  

3.      char *tmp, *result;  

4.    

5.      result = ERR_PTR(-ENOMEM);  

6.      tmp = __getname(); //从内核缓存中分配空间;     

7.      if (tmp)  {  

8.          //将文件名从用户态拷贝至内核态;    

9.          int retval = do_getname(filename, tmp);  

10.   

11.         result = tmp;  

12.         if (retval < 0) {//如果拷贝失败,则调用__putname()释放__getname()中申请的空间;    

13.             __putname(tmp);  

14.             result = ERR_PTR(retval);  

15.         }  

16.     }  

17.     audit_getname(result);  

18.     return result;  

19. }  

char * getname(const char __user * filename)

{ char *tmp, *result;

  result = ERR_PTR(-ENOMEM);

  tmp = __getname(); //从内核缓存中分配空间; 

  if (tmp)  {

   //将文件名从用户态拷贝至内核态;

   int retval = do_getname(filename, tmp); 

   result = tmp;

   if (retval < 0) {//如果拷贝失败,则调用__putname()释放__getname()中申请的空间;

     __putname(tmp);

     result = ERR_PTR(retval);

   }

  }

  audit_getname(result);

  return result;

get_unused_fd_flags实际调用的是alloc_fd

[cpp] view plaincopyprint?

1.  #define get_unused_fd_flags(flags) alloc_fd(0, (flags))  

#define get_unused_fd_flags(flags) alloc_fd(0, (flags))

[cpp] view plaincopyprint?

1.  /* 

2.   * allocate a file descriptor, mark it busy. 

3.   */  

4.  int alloc_fd(unsigned start, unsigned flags)  

5.  {  

6.      struct files_struct *files = current->files;//获得当前进程的files_struct 结构   

7.      unsigned int fd;  

8.      int error;  

9.      struct fdtable *fdt;  

10.   

11.     spin_lock(&files->file_lock);  

12. repeat:  

13.     fdt = files_fdtable(files);  

14.     fd = start;  

15.     if (fd < files->next_fd) //从上一次打开的fd的下一个fd开始搜索空闲的fd     

16.         fd = files->next_fd;  

17.   

18.     if (fd < fdt->max_fds)//寻找空闲的fd,返回值为空闲的fd     

19.         fd = find_next_zero_bit(fdt->open_fds->fds_bits,  

20.                        fdt->max_fds, fd);  

21.     //如果有必要,即打开的fd超过max_fds,则需要expand当前进程的fd表;     

22.     //返回值error<0表示出错,error=0表示无需expand,error=1表示进行了expand;   

23.     error = expand_files(files, fd);  

24.     if (error < 0)  

25.         goto out;  

27.     /* 

28.      * If we needed to expand the fs array we 

29.      * might have blocked - try again. 

30.      */  

31.      //error=1表示进行了expand,那么此时需要重新去查找空闲的fd;     

32.     if (error)  

33.         goto repeat;  

34.   

35.     //设置下一次查找的起始fd,即本次找到的空闲的fd的下一个fd,记录在files->next_fd中;     

36.     if (start <= files->next_fd)  

37.         files->next_fd = fd + 1;  

38.   

39.     FD_SET(fd, fdt->open_fds);  

40.     if (flags & O_CLOEXEC)  

41.         FD_SET(fd, fdt->close_on_exec);  

42.     else  

43.         FD_CLR(fd, fdt->close_on_exec);  

44.     error = fd;  

45. #if 1   

46.     /* Sanity check */  

47.     if (rcu_dereference(fdt->fd[fd]) != NULL) {  

48.         printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd);  

49.         rcu_assign_pointer(fdt->fd[fd], NULL);  

50.     }  

51. #endif   

52.   

53. out:  

54.     spin_unlock(&files->file_lock);  

55.     return error;  

56. }  

/*

 * allocate a file descriptor, mark it busy.

 */

int alloc_fd(unsigned start, unsigned flags)

{

  struct files_struct *files = current->files;//获得当前进程的files_struct 结构

  unsigned int fd;

  int error;

  struct fdtable *fdt; 

  spin_lock(&files->file_lock);

repeat:

  fdt = files_fdtable(files);

  fd = start;

  if (fd < files->next_fd) //从上一次打开的fd的下一个fd开始搜索空闲的fd 

    fd = files->next_fd; 

  if (fd < fdt->max_fds)//寻找空闲的fd,返回值为空闲的fd 

    fd = find_next_zero_bit(fdt->open_fds->fds_bits,

            fdt->max_fds, fd);

  //如果有必要,即打开的fd超过max_fds,则需要expand当前进程的fd表; 

    //返回值error<0表示出错,error=0表示无需expand,error=1表示进行了expand;

  error = expand_files(files, fd);

  if (error < 0)

    goto out; 

  /*

   * If we needed to expand the fs array we

   * might have blocked - try again.

   */

   //error=1表示进行了expand,那么此时需要重新去查找空闲的fd; 

  if (error)

    goto repeat;

  //设置下一次查找的起始fd,即本次找到的空闲的fd的下一个fd,记录在files->next_fd中; 

  if (start <= files->next_fd)

    files->next_fd = fd + 1;

  FD_SET(fd, fdt->open_fds);

  if (flags & O_CLOEXEC)

    FD_SET(fd, fdt->close_on_exec);

  else

    FD_CLR(fd, fdt->close_on_exec);

  error = fd;

#if 1

  /* Sanity check */

  if (rcu_dereference(fdt->fd[fd]) != NULL) {

    printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd);

    rcu_assign_pointer(fdt->fd[fd], NULL);

  }

#endif 

out:

  spin_unlock(&files->file_lock);

  return error;

}

该函数为需要打开的文件在当前进程内分配一个空闲的文件描述符fd,该fd就是open()系统调用的返回值

do_filp_open函数的一个重要作用就是根据传递近来的权限进行分析,并且分析传递近来的路径名字,根据路径名逐个解析成dentry,并且通过dentry找到inode,inode就是记录着该文件相关的信息, 包括文件的创建时间和文件属性所有者等等信息,根据这些信息就可以找到对应的文件操作方法。在这个过程当中有一个临时的结构体用于保存在查找过程中的相关信息,就是

[cpp] view plaincopyprint?

1.  struct nameidata {  

2.      struct path path;//当前目录的dentry数据结构   

3.      struct qstr last;//这个结构体也是临时性的,主要用来保存当前目录的名称,杂凑值。   

4.      unsigned int    flags;  

5.      int     last_type;  

6.      unsigned    depth;//连接文件的深度(可能一个连接文件跟到最后还是一个了连接文件)   

7.      //用来保存连接文件的一些信息,下标表示连接文件的深度   

8.      char *saved_names[MAX_NESTED_LINKS + 1];  

10.     /* Intent data */  

11.     union {  

12.         struct open_intent open;  

13.     } intent;  

14. };  

struct nameidata {

  struct path  path;//当前目录的dentry数据结构

  struct qstr  last;//这个结构体也是临时性的,主要用来保存当前目录的名称,杂凑值。

  unsigned int  flags;

  int   last_type;

  unsigned  depth;//连接文件的深度(可能一个连接文件跟到最后还是一个了连接文件)

  //用来保存连接文件的一些信息,下标表示连接文件的深度

  char *saved_names[MAX_NESTED_LINKS + 1];

  /* Intent data */

  union {

   struct open_intent open;

  } intent;

};

[cpp] view plaincopyprint?

1.  struct file *do_filp_open(int dfd, const char *pathname,  

2.          int open_flag, int mode, int acc_mode)  

3.  {  

4.      struct file *filp;  

5.      struct nameidata nd;  

6.      int error;  

7.      struct path path;  

8.      int count = 0;  

9.      int flag = open_to_namei_flags(open_flag); /*改变参数flag的值,具体做法是flag+1*/   

10.     int force_reval = 0;  

11.   

12.     if (!(open_flag & O_CREAT))  

13.         mode = 0;  

14.   

15.     /* 

16.      * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only 

17.      * check for O_DSYNC if the need any syncing at all we enforce it's 

18.      * always set instead of having to deal with possibly weird behaviour 

19.      * for malicious applications setting only __O_SYNC. 

20.      */  

21.     if (open_flag & __O_SYNC)/*根据__O_SYNC标志来设置O_DSYNC 标志,用以防止恶意破坏程序*/   

22.         open_flag |= O_DSYNC;  

24.     if (!acc_mode)/*设置访问权限*/   

25.         acc_mode = MAY_OPEN | ACC_MODE(open_flag);  

27.     /* O_TRUNC implies we need access checks for write permissions */  

28.     if (open_flag & O_TRUNC)/*根据 O_TRUNC标志设置写权限 */   

29.         acc_mode |= MAY_WRITE;  

31.     /* Allow the LSM permission hook to distinguish append  

32.        access from general write access. */  

33.     if (open_flag & O_APPEND)/* 设置O_APPEND 标志*/    

34.         acc_mode |= MAY_APPEND;  

36.     /* find the parent */  

37. reval:  

38.     error = path_init(dfd, pathname, LOOKUP_PARENT, &nd);//初始化nd   

39.     if (error)  

40.         return ERR_PTR(error);  

41.     if (force_reval)  

42.         nd.flags |= LOOKUP_REVAL;  

43.   

44.     current->total_link_count = 0;  

45.     error = link_path_walk(pathname, &nd);//路径名解析函数,将一个路径名最终转化为一个dentry   

46.     if (error) {  

47.         filp = ERR_PTR(error);  

48.         goto out;  

49.     }  

50.     if (unlikely(!audit_dummy_context()) && (open_flag & O_CREAT))  

51.         audit_inode(pathname, nd.path.dentry);  

53.     /* 

54.      * We have the parent and last component. 

55.      */   

57.     error = -ENFILE;  

58.     filp = get_empty_filp();// 从进程文件表中获取一个未使用的文件结构指针,空则出错返回   

59.     if (filp == NULL)  

60.         goto exit_parent;  

61.     nd.intent.open.file = filp;  

62.     filp->f_flags = open_flag;  

63.     nd.intent.open.flags = flag;  

64.     nd.intent.open.create_mode = mode;  

65.     nd.flags &= ~LOOKUP_PARENT;  

66.     nd.flags |= LOOKUP_OPEN;  

67.     if (open_flag & O_CREAT) {  

68.         nd.flags |= LOOKUP_CREATE;  

69.         if (open_flag & O_EXCL)  

70.             nd.flags |= LOOKUP_EXCL;  

71.     }  

72.     if (open_flag & O_DIRECTORY)  

73.         nd.flags |= LOOKUP_DIRECTORY;  

74.     if (!(open_flag & O_NOFOLLOW))  

75.         nd.flags |= LOOKUP_FOLLOW;  

76.     filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);//返回一个file结构   

77.     while (unlikely(!filp)) { /* trailing symlink *///符号链接  

78.         struct path holder;  

79.         struct inode *inode = path.dentry->d_inode;  

80.         void *cookie;  

81.         error = -ELOOP;  

82.         /* S_ISDIR part is a temporary automount kludge */  

83.         if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(inode->i_mode))  

84.             goto exit_dput;  

85.         if (count++ == 32)  

86.             goto exit_dput;  

87.         /* 

88.          * This is subtle. Instead of calling do_follow_link() we do 

89.          * the thing by hands. The reason is that this way we have zero 

90.          * link_count and path_walk() (called from ->follow_link) 

91.          * honoring LOOKUP_PARENT.  After that we have the parent and 

92.          * last component, i.e. we are in the same situation as after 

93.          * the first path_walk().  Well, almost - if the last component 

94.          * is normal we get its copy stored in nd->last.name and we will 

95.          * have to putname() it when we are done. Procfs-like symlinks 

96.          * just set LAST_BIND. 

97.          */  

98.         nd.flags |= LOOKUP_PARENT;  

99.         error = security_inode_follow_link(path.dentry, &nd);  

100.            if (error)  

101.                goto exit_dput;  

102.            error = __do_follow_link(&path, &nd, &cookie);//查找符号链接对应的目录中的最后一项   

103.            if (unlikely(error)) {  

104.                /* nd.path had been dropped */  

105.                if (!IS_ERR(cookie) && inode->i_op->put_link)  

106.                    inode->i_op->put_link(path.dentry, &nd, cookie);  

107.                path_put(&path);  

108.                release_open_intent(&nd);  

109.                filp = ERR_PTR(error);  

110.                goto out;  

111.            }  

112.            holder = path;  

113.            nd.flags &= ~LOOKUP_PARENT;  

114.            filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);  

115.            if (inode->i_op->put_link)  

116.                inode->i_op->put_link(holder.dentry, &nd, cookie);  

117.            path_put(&holder);  

118.        }  

119.    out:  

120.        if (nd.root.mnt)  

121.            path_put(&nd.root);  

122.        if (filp == ERR_PTR(-ESTALE) && !force_reval) {  

123.            force_reval = 1;  

124.            goto reval;  

125.        }  

126.        return filp;//成功,返回   

127.      

128.    exit_dput:  

129.        path_put_conditional(&path, &nd);  

130.        if (!IS_ERR(nd.intent.open.file))  

131.            release_open_intent(&nd);  

132.    exit_parent:  

133.        path_put(&nd.path);  

134.        filp = ERR_PTR(error);  

135.        goto out;  

136.    }  

struct file *do_filp_open(int dfd, const char *pathname,

   int open_flag, int mode, int acc_mode)

{

  struct file *filp;

  struct nameidata nd;

  int error;

  struct path path;

  int count = 0;

  int flag = open_to_namei_flags(open_flag); /*改变参数flag的值,具体做法是flag+1*/

  int force_reval = 0;

 

  if (!(open_flag & O_CREAT))

   mode = 0;

  /*

   * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only

   * check for O_DSYNC if the need any syncing at all we enforce it's

   * always set instead of having to deal with possibly weird behaviour

   * for malicious applications setting only __O_SYNC.

   */

  if (open_flag & __O_SYNC)/*根据__O_SYNC标志来设置O_DSYNC 标志,用以防止恶意破坏程序*/

   open_flag |= O_DSYNC; 

  if (!acc_mode)/*设置访问权限*/

   acc_mode = MAY_OPEN | ACC_MODE(open_flag); 

  /* O_TRUNC implies we need access checks for write permissions */

  if (open_flag & O_TRUNC)/*根据 O_TRUNC标志设置写权限 */

   acc_mode |= MAY_WRITE; 

  /* Allow the LSM permission hook to distinguish append

     access from general write access. */

  if (open_flag & O_APPEND)/* 设置O_APPEND 标志*/ 

   acc_mode |= MAY_APPEND;

 

  /* find the parent */

reval:

  error = path_init(dfd, pathname, LOOKUP_PARENT, &nd);//初始化nd

  if (error)

   return ERR_PTR(error);

  if (force_reval)

   nd.flags |= LOOKUP_REVAL;

  current->total_link_count = 0;

  error = link_path_walk(pathname, &nd);//路径名解析函数,将一个路径名最终转化为一个dentry

  if (error) {

   filp = ERR_PTR(error);

   goto out;

  }

  if (unlikely(!audit_dummy_context()) && (open_flag & O_CREAT))

   audit_inode(pathname, nd.path.dentry);

  /*

   * We have the parent and last component.

   */

  error = -ENFILE;

  filp = get_empty_filp();// 从进程文件表中获取一个未使用的文件结构指针,空则出错返回

  if (filp == NULL)

   goto exit_parent;

  nd.intent.open.file = filp;

  filp->f_flags = open_flag;

  nd.intent.open.flags = flag;

  nd.intent.open.create_mode = mode;

  nd.flags &= ~LOOKUP_PARENT;

  nd.flags |= LOOKUP_OPEN;

  if (open_flag & O_CREAT) {

   nd.flags |= LOOKUP_CREATE;

   if (open_flag & O_EXCL)

     nd.flags |= LOOKUP_EXCL;

  }

  if (open_flag & O_DIRECTORY)

   nd.flags |= LOOKUP_DIRECTORY;

  if (!(open_flag & O_NOFOLLOW))

   nd.flags |= LOOKUP_FOLLOW;

  filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);//返回一个file结构

  while (unlikely(!filp)) { /* trailing symlink *///符号链接

   struct path holder;

   struct inode *inode = path.dentry->d_inode;

   void *cookie;

   error = -ELOOP;

   /* S_ISDIR part is a temporary automount kludge */

   if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(inode->i_mode))

     goto exit_dput;

   if (count++ == 32)

     goto exit_dput;

   /*

    * This is subtle. Instead of calling do_follow_link() we do

    * the thing by hands. The reason is that this way we have zero

    * link_count and path_walk() (called from ->follow_link)

    * honoring LOOKUP_PARENT.  After that we have the parent and

    * last component, i.e. we are in the same situation as after

    * the first path_walk().  Well, almost - if the last component

    * is normal we get its copy stored in nd->last.name and we will

    * have to putname() it when we are done. Procfs-like symlinks

    * just set LAST_BIND.

    */

   nd.flags |= LOOKUP_PARENT;

   error = security_inode_follow_link(path.dentry, &nd);

   if (error)

     goto exit_dput;

   error = __do_follow_link(&path, &nd, &cookie);//查找符号链接对应的目录中的最后一项

   if (unlikely(error)) {

     /* nd.path had been dropped */

     if (!IS_ERR(cookie) && inode->i_op->put_link)

      inode->i_op->put_link(path.dentry, &nd, cookie);

     path_put(&path);

     release_open_intent(&nd);

     filp = ERR_PTR(error);

     goto out;

   }

   holder = path;

   nd.flags &= ~LOOKUP_PARENT;

   filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);

   if (inode->i_op->put_link)

     inode->i_op->put_link(holder.dentry, &nd, cookie);

   path_put(&holder);

  }

out:

  if (nd.root.mnt)

   path_put(&nd.root);

  if (filp == ERR_PTR(-ESTALE) && !force_reval) {

   force_reval = 1;

   goto reval;

  }

  return filp;//成功,返回 

exit_dput:

  path_put_conditional(&path, &nd);

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

   release_open_intent(&nd);

exit_parent:

  path_put(&nd.path);

  filp = ERR_PTR(error);

  goto out;

}

  评论这张
 
阅读(1647)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

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

页脚

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