fcntl跟踪
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:
- asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
- {
- do_fcntl(fd, cmd, arg, filp);
- }
- static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
- struct file *filp)
- {
- long err = -EINVAL;
- switch (cmd) {
- case F_DUPFD:
- get_file(filp);
- err = dupfd(filp, arg);
- break;
- case F_GETFD:
- err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
- break;
- case F_SETFD:
- err = 0;
- set_close_on_exec(fd, arg & FD_CLOEXEC);
- break;
- case F_GETFL:
- err = filp->f_flags;
- break;
- case F_SETFL:
- err = setfl(fd, filp, arg);
- break;
- case F_GETLK:
- err = fcntl_getlk(filp, (struct flock __user *) arg);
- break;
- case F_SETLK:
- case F_SETLKW:
- err = fcntl_setlk(filp, cmd, (struct flock __user *) arg);
- break;
- case F_GETOWN:
- /*
- * XXX If f_owner is a process group, the
- * negative return value will get converted
- * into an error. Oops. If we keep the
- * current syscall conventions, the only way
- * to fix this will be in libc.
- */
- err = filp->f_owner.pid;
- force_successful_syscall_return();
- break;
- case F_SETOWN:
- err = f_setown(filp, arg, 1);
- break;
- case F_GETSIG:
- err = filp->f_owner.signum;
- break;
- case F_SETSIG:
- /* arg == 0 restores default behaviour. */
- if (arg < 0 || arg > _NSIG) {
- break;
- }
- err = 0;
- filp->f_owner.signum = arg;
- break;
- case F_GETLEASE:
- err = fcntl_getlease(filp);
- break;
- case F_SETLEASE:
- err = fcntl_setlease(fd, filp, arg);
- break;
- case F_NOTIFY:
- err = fcntl_dirnotify(fd, filp, arg);
- break;
- default:
- break;
- }
- return err;
- }
- int f_setown(struct file *filp, unsigned long arg, int force)
- {
- int err;
- err = security_file_set_fowner(filp);
- if (err)
- return err;
- f_modown(filp, arg, current->uid, current->euid, force);
- return 0;
- }
- EXPORT_SYMBOL(f_setown);
- static int setfl(int fd, struct file * filp, unsigned long arg)
- {
- struct inode * inode = filp->f_dentry->d_inode;
- int error = 0;
- /* O_APPEND cannot be cleared if the file is marked as append-only */
- if (!(arg & O_APPEND) && IS_APPEND(inode))
- return -EPERM;
- /* O_NOATIME can only be set by the owner or superuser */
- if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME))
- if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
- return -EPERM;
- /* required for strict SunOS emulation */
- if (O_NONBLOCK != O_NDELAY)
- if (arg & O_NDELAY)
- arg |= O_NONBLOCK;
- if (arg & O_DIRECT) {
- if (!filp->f_mapping || !filp->f_mapping->a_ops ||
- !filp->f_mapping->a_ops->direct_IO)
- return -EINVAL;
- }
- if (filp->f_op && filp->f_op->check_flags)
- error = filp->f_op->check_flags(arg);
- if (error)
- return error;
- lock_kernel();
- if ((arg ^ filp->f_flags) & FASYNC) {
- if (filp->f_op && filp->f_op->fasync) {
- error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);---/*就会调用scull_p.ko里面的fasync函数*/
- if (error < 0)
- goto out;
- }
- }
- filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
- out:
- unlock_kernel();
- return error;
- }
复制代码
再来看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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
dreamice:重点部分怎么打颜色都不成功
辛苦了,该奖励的
code里面不能再加颜色了。另外,贴代码的时候,最好使用工具栏里面的“插入程序代码”,看起来就好看了
感谢分享哈