fcntl跟踪

发布于 2022-09-23 14:11:43 字数 10244 浏览 14 评论 0

scull_p.ko驱动开发"异步通知"测试程序中:
1:fcntl(FILENO,F_SETOWN,getpid());----------------指定一个进程作为文件的属主,以便将来通知哪个进程
2:oldflags=fcntl(FILENO,F_GETFL);-----------------取得旧flags
3:fcntl(FILENO,F_SETFL,oldflags | FASYNC);---------加上了FASYNC
第三步fcntl调用时就会调用FILENO对应的驱动程序的file_operatrions的fasync方法,当有数据可供应用层处理时,驱动程序就会以SIGIO信号通知第一步中所指定的进程.

从GLIBC库开始,我就很难一步一步跟踪,然后反过来从kernel来跟踪:
fs/fcntl.c:

  1. asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
  2. {       
  3.          do_fcntl(fd, cmd, arg, filp);
  4. }
  5. static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
  6.                 struct file *filp)
  7. {
  8.         long err = -EINVAL;
  9.         switch (cmd) {
  10.         case F_DUPFD:
  11.                 get_file(filp);
  12.                 err = dupfd(filp, arg);
  13.                 break;
  14.         case F_GETFD:
  15.                 err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
  16.                 break;
  17.         case F_SETFD:
  18.                 err = 0;
  19.                 set_close_on_exec(fd, arg & FD_CLOEXEC);
  20.                 break;
  21.         case F_GETFL:
  22.                 err = filp->f_flags;
  23.                 break;
  24.         case F_SETFL:
  25.                 err = setfl(fd, filp, arg);
  26.                 break;
  27.         case F_GETLK:
  28.                 err = fcntl_getlk(filp, (struct flock __user *) arg);
  29.                 break;
  30.         case F_SETLK:
  31.         case F_SETLKW:
  32.                 err = fcntl_setlk(filp, cmd, (struct flock __user *) arg);
  33.                 break;
  34.         case F_GETOWN:
  35.                 /*
  36.                  * XXX If f_owner is a process group, the
  37.                  * negative return value will get converted
  38.                  * into an error.  Oops.  If we keep the
  39.                  * current syscall conventions, the only way
  40.                  * to fix this will be in libc.
  41.                  */
  42.                 err = filp->f_owner.pid;
  43.                 force_successful_syscall_return();
  44.                 break;
  45.         case F_SETOWN:
  46.                 err = f_setown(filp, arg, 1);
  47.                 break;
  48.         case F_GETSIG:
  49.                 err = filp->f_owner.signum;
  50.                 break;
  51.         case F_SETSIG:
  52.                 /* arg == 0 restores default behaviour. */
  53.                 if (arg < 0 || arg > _NSIG) {
  54.                         break;
  55.                 }
  56.                 err = 0;
  57.                 filp->f_owner.signum = arg;
  58.                 break;
  59.         case F_GETLEASE:
  60.                 err = fcntl_getlease(filp);
  61.                 break;
  62.         case F_SETLEASE:
  63.                 err = fcntl_setlease(fd, filp, arg);
  64.                 break;
  65.         case F_NOTIFY:
  66.                 err = fcntl_dirnotify(fd, filp, arg);
  67.                 break;
  68.         default:
  69.                 break;
  70.         }
  71.         return err;
  72. }
  73. int f_setown(struct file *filp, unsigned long arg, int force)
  74. {
  75.         int err;
  76.        
  77.         err = security_file_set_fowner(filp);
  78.         if (err)
  79.                 return err;
  80.         f_modown(filp, arg, current->uid, current->euid, force);
  81.         return 0;
  82. }
  83. EXPORT_SYMBOL(f_setown);
  84. static int setfl(int fd, struct file * filp, unsigned long arg)
  85. {
  86.         struct inode * inode = filp->f_dentry->d_inode;
  87.         int error = 0;
  88.         /* O_APPEND cannot be cleared if the file is marked as append-only */
  89.         if (!(arg & O_APPEND) && IS_APPEND(inode))
  90.                 return -EPERM;
  91.         /* O_NOATIME can only be set by the owner or superuser */
  92.         if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME))
  93.                 if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
  94.                         return -EPERM;
  95.         /* required for strict SunOS emulation */
  96.         if (O_NONBLOCK != O_NDELAY)
  97.                if (arg & O_NDELAY)
  98.                    arg |= O_NONBLOCK;
  99.         if (arg & O_DIRECT) {
  100.                 if (!filp->f_mapping || !filp->f_mapping->a_ops ||
  101.                         !filp->f_mapping->a_ops->direct_IO)
  102.                                 return -EINVAL;
  103.         }
  104.         if (filp->f_op && filp->f_op->check_flags)
  105.                 error = filp->f_op->check_flags(arg);
  106.         if (error)
  107.                 return error;
  108.         lock_kernel();
  109.         if ((arg ^ filp->f_flags) & FASYNC) {
  110.                 if (filp->f_op && filp->f_op->fasync) {
  111.                         error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);---/*就会调用scull_p.ko里面的fasync函数*/
  112.                         if (error < 0)
  113.                                 goto out;
  114.                 }
  115.         }
  116.         filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
  117. out:
  118.         unlock_kernel();
  119.         return error;
  120. }

复制代码
再来看glibc中流程:
global _start(C库的汇编启动点)--->__libc_init----->__libc_start_main(初始化环境变量,堆栈,看是动态还是静态连接C库(当然也会相应初始处理),线程初始化---->调用我们的main(此时就进入了我们的测试程序)--->fcntl-->__libc_fcntl-->INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);这样,当LIBC发现是F_SETOWN等命令时就会调用kernel提供的系统调用.当然,如果是动态库应用,这个流程又会改变,只不过核心思想不变.

以上就是我今天下午2小时跟踪的结果,请给位指点,也请更详细解说.dreamice,这个贴要给我加分才好!我用snavigator分析得好辛苦,为此,我还专门到GNU去下载glibc-2.3的源代码,GNU的网站出奇的慢.

[ 本帖最后由 dreamice 于 2009-1-8 15:47 编辑 ]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

以酷 2022-09-30 14:11:44

dreamice:重点部分怎么打颜色都不成功

萌逼全场 2022-09-30 14:11:44

原帖由 whoisliang 于 2009-1-8 14:49 发表
dreamice:重点部分怎么打颜色都不成功

辛苦了,该奖励的

code里面不能再加颜色了。另外,贴代码的时候,最好使用工具栏里面的“插入程序代码”,看起来就好看了
感谢分享哈

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文