Linux字符设备驱动疑难问题--printf打印信息发到字符设备write函数中

usman 2010-09-07 02:34:06
我在开发中遇到一个奇怪的问题:
1、创建了一个字符设备驱动,为其注册了open、read、write、poll等函数;
2、创建了一个用户空间程序,用来打开1中的字符设备驱动,为的是传递命令到用户空间程序进行处理;
3、当PC端发送一个请求,我们受到后会将其放到请求列表ctrl_list中;
4、字符设备的read函数会循环检测ctrl_list中有没有控制请求,当有控制请求的时候,会通过copy_to_user发送到用户空间程序中;
5、用户空间程序解析4中的请求并执行处理,处理完成后发送结果,在用户空间调用write,我们的请求处理结果最大50字节;
6、在字符设备驱动的write函数中,会出现被写入4096或1024字节数据的情况(依平台不同有所变化),这个是一页的数据;
7、上述一页的数据是我们用户空间程序中所有printf语句的打印信息,并被发送到PC侧,可以从打印log看出;
8、我们通过在内核加panic和在用户空间加指针误操作进行追踪,发现上述4096字节的数据不是我们的用户空间程序调用的,从panic看是文件系统自己调用,并把printf的打印发过去,出现这种情况时,用户空间的打印不会在串口打印出来;


麻烦大家看下有没有遇到过这种问题,为什么会被莫名其妙调到;

不方便贴代码;

谢谢
...全文
491 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
usman 2010-09-11
  • 打赏
  • 举报
回复
这个问题确实是用的平台上0、1、2被关闭了;

谢谢大家;

另外 , 怎么给你们分?
thanks
iptvwwq 2010-09-09
  • 打赏
  • 举报
回复
是不是程序中,将stdin、stdout、stderr的fd关闭过了呢?导致0、1、2描述符被重用。
使用ps查看一下用户进程的进程号,比如3063。然后通过proc查看一下这个进程所有打开的文件句柄。
localhost:/ > ls -l /proc/3063/fd
total 0
lrwx------ 1 root root 64 Sep 8 04:29 0 -> /dev/pts/3
lrwx------ 1 root root 64 Sep 9 00:49 1 -> /dev/pts/3
lrwx------ 1 root root 64 Sep 9 00:49 2 -> /dev/pts/3
lrwx------ 1 root root 64 Sep 9 00:49 255 -> /dev/pts/3
usman 2010-09-09
  • 打赏
  • 举报
回复
重要补充信息:

我查了fd=open(filename,O_RDWR);的返回值,fd=1,这个应该是stdout;

为什么我调用open返回的是1?

很奇怪
usman 2010-09-09
  • 打赏
  • 举报
回复
继续补充:

今天对每个printf语句之后添加fflush(stdout)语句,现象有所改变:
1、每一个printf语句的内容都被发到了字符设备驱动注册的write函数中;
2、相对而言,就不会有4096出现,因为没有累积,是一次一次发送的;

为什么这个printf输出到了字符设备驱动中而不是stdout呢?与应用程序打开字符设备驱动有没有什么关系?我写的是fd=open(filename,O_RDWR);

感谢诸位的回复;


麻烦再帮忙分析一下;
slone 2010-09-09
  • 打赏
  • 举报
回复
fflush 一下
usman 2010-09-09
  • 打赏
  • 举报
回复
继续补充:

昨天测试发现,我只要从pc端下发3、4条处理请求,用户程序就会出现这种情况,而且前两条没有出现时的printf语句也不能打到串口里(串口看不到),从现象上看,好像printf先是没打印,然后调用多了被一次性发送到了字符设备驱动的write函数中了;

谢谢
usman 2010-09-09
  • 打赏
  • 举报
回复
很不好意思,代码在公司服务器上;

下面是我对应用程序进程执行ls -l /proc/1421/fd的结果
lr-x------ root root 1980-01-06 04:49 0 -> /dev/null
lrwx------ root root 1980-01-06 04:49 1 -> /dev/ndis_driver
其中 ndis_driver 是我们的使用的字符设备节点;


谢谢各位
slone 2010-09-09
  • 打赏
  • 举报
回复
很乱很奇怪, 该贴部分代码了..
slone 2010-09-08
  • 打赏
  • 举报
回复
copied值每次都是0 , 那这里就有问题呢
slone 2010-09-08
  • 打赏
  • 举报
回复
#include <linux/sched.h>

把调用这个write 的进程打印出来 current->pid

对比一下是哪个进程调用的, 是不是设备号分配冲突?
usman 2010-09-08
  • 打赏
  • 举报
回复
-----------------------------------------------------------------------
static ssize_t ***_write_***(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)

在这个write 里把count 打印出来看看.
copied = copy_from_user(dest, buf, sz);
再把这个 copied 值打印出来看看呢?
-----------------------------------------------------------------------

我看了我的串口log,我的copied值每次都是0,sz的值是正常的,当4096出现时就是4096
usman 2010-09-08
  • 打赏
  • 举报
回复
补充与回复:

1、关于是否重定向:
我没有用过lvyinghong说的,如果重定向应该每次都是,但有概率,同时,有的版本是好的;
2、 楼上slone说的,我说的50字节是如果我自己调用的话,结果最多50字节;现在4096也是能打印出来的;
3、楼上iptvwwq说的,打印函数调用栈,在上面我的补充中就是用panic打印的函数调用栈; 内核有没有其它更有效的打印方法?


麻烦再请大家分析分析;
谢谢
iptvwwq 2010-09-07
  • 打赏
  • 举报
回复
如果确定是驱动里面write被调用导致的话,可以在write函数中打印出调用的堆栈信息,并可以打印出调用write函数的进程名称.
slone 2010-09-07
  • 打赏
  • 举报
回复
static ssize_t ***_write_***(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)

在这个write 里把count 打印出来看看.
copied = copy_from_user(dest, buf, sz);
再把这个 copied 值打印出来看看呢?
如果处理数据最多50字节, 即便是缓存在内存里, 也需要好几十次才会分页 .

lvyinghong 2010-09-07
  • 打赏
  • 举报
回复
你把标准输出 定向的这个字符设备了吧。

比如启动时用 program > /dev/char

usman 2010-09-07
  • 打赏
  • 举报
回复
继续补充:

此问题会概率性出现,同样的用户空间程序,我把printf语句用宏屏蔽掉,下载测试问题好了,重新打开屏蔽,问题也不出现,实际上没做修改又好了,但是之前的版本还是一样;
usman 2010-09-07
  • 打赏
  • 举报
回复
补充:

下面是我在字符设备驱动加了出现4096字节时候让其执行 *((int*)0) = 0后的调用栈:

[ 30.398238] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[ 30.400714] pgd = 8c7e8000
[ 30.403401] [00000000] *pgd=0c8bb031, *pte=00000000, *ppte=00000000
[ 30.409658] Internal error: Oops: 817 [#1] PREEMPT
[ 30.414424] Modules linked in: ar6000 msm_sdcc
[ 30.418859] CPU: 0 Not tainted (2.6.29-perf #36)
[ 30.423818] PC is at ecm_chrdev_write+0x30/0x20c
[ 30.428413] LR is at schedule+0x314/0x390
[ 30.432403] pc : [<80234914>] lr : [<80357974>] psr: 20000013
[ 30.432414] sp : 8be39f20 ip : 00000000 fp : 8be39f44
[ 30.443854] r10: 00000000 r9 : 8be38000 r8 : 0000c2c0
[ 30.449063] r7 : 00001000 r6 : 8be39f70 r5 : 0000c2c0 r4 : 0000c2c0
[ 30.455573] r3 : 0000c2c0 r2 : 00000000 r1 : 00000000 r0 : 0000005d
[ 30.462086] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
[ 30.469204] Control: 00c5387d Table: 0c9e8008 DAC: 00000015
[ 30.474933] Process sh_drivers_qmi (pid: 1407, stack limit = 0x8be38260)
[ 30.481703] Stack: (0x8be39f20 to 0x8be3a000)
[ 30.486039] 9f20: 8cf0cdd8 8cba70a8 8c80ac40 0000c2c0 8be39f70 00001000 8be39f6c 8be39f48
[ 30.494284] 9f40: 800d9fc8 802348f0 00000000 00000400 00000000 00000000 8c80ac40 00001000
[ 30.502529] 9f60: 8be39fa4 8be39f70 800da560 800d9f1c 00000000 00000000 800e73bc 00000000
[ 30.510776] 9f80: 00000000 6fe39f3c 0000c2c0 00001000 00000004 800316c4 00000000 8be39fa8
[ 30.519024] 9fa0: 80031540 800da528 6fe39f3c 0000c2c0 00000001 0000c2c0 00001000 00000888
[ 30.527269] 9fc0: 6fe39f3c 0000c2c0 00001000 00000004 00000000 00000000 00000000 00000000
[ 30.535516] 9fe0: c0000000 7eff6968 6fe14a03 6fe0c2bc 00000010 00000001 00676e69 30367261
[ 30.543763] Backtrace:
[ 30.546196] [<802348e4>] (ecm_chrdev_write+0x0/0x20c) from [<800d9fc8>] (vfs_write+0xb8/0x148)
[ 30.554793] r7:00001000 r6:8be39f70 r5:0000c2c0 r4:8c80ac40
[ 30.560431] [<800d9f10>] (vfs_write+0x0/0x148) from [<800da560>] (sys_write+0x44/0x70)
[ 30.568331] r7:00001000 r6:8c80ac40 r5:00000000 r4:00000000
[ 30.573971] [<800da51c>] (sys_write+0x0/0x70) from [<80031540>] (ret_fast_syscall+0x0/0x2c)
[ 30.582306] r8:800316c4 r7:00000004 r6:00001000 r5:0000c2c0 r4:6fe39f3c
[ 30.588989] Code: e3570c02 9a000007 e3a0c000 e1a03004 (e58cc000)
[ 30.789744] Kernel panic - not syncing: Fatal exception

4,436

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 内核源代码研究区
社区管理员
  • 内核源代码研究区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧