免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 7274 | 回复: 25
打印 上一主题 下一主题

[文件系统] 创建proc项,write函数调用copy_from_user读取换行符的疑问 [复制链接]

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2017-03-29 16:24 |只看该作者 |倒序浏览
请教各位

在/proc下创建了一个测试文件,并手动指定了write回调函数,write中调用copy_from_user,将输入在proc文件中的内容写入到内核空间
现在的问题是,如果proc文件中包含换行符时,copy_from_user会对内容分段写入多次

程序:proc_rw.c

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/proc_fs.h>
  4. #include<linux/sched.h>
  5. #include <asm/uaccess.h>
  6. #include <linux/slab.h>
  7. #include <linux/string.h>

  8. int len,temp;
  9. char *msg;

  10. int read_proc(struct file *filp,char *buf,size_t count,loff_t *offp)
  11. {
  12.         if(count>temp)
  13.         {
  14.                 count=temp;
  15.         }
  16.         temp=temp-count;
  17.         printk("read\n");
  18.         printk("count = %d\n", count);
  19.         printk("strlen(msg) = %d\n", strlen(msg));
  20.         copy_to_user(buf,msg, count);
  21.         if(count==0)
  22.                 temp=len;

  23.         return count;
  24. }

  25. int write_proc(struct file *filp,const char *buf,size_t count,loff_t *offp)
  26. {
  27.         if (copy_from_user(msg,buf,count))
  28.                 return -EFAULT;

  29.         len=count;
  30.         temp=len;
  31.         printk("write\n");
  32.         printk("count = %d\n", count);
  33.         printk("strlen(msg) = %d\n", strlen(msg));

  34.         return count;
  35. }

  36. struct file_operations proc_fops = {
  37.         read: read_proc,
  38.         write: write_proc
  39. };

  40. void create_new_proc_entry()
  41. {
  42.         proc_create("hello",0,NULL,&proc_fops);
  43.         msg=kmalloc(GFP_KERNEL,10*sizeof(char));
  44. }

  45. int proc_init (void) {
  46.         create_new_proc_entry();
  47.         return 0;
  48. }

  49. void proc_cleanup(void) {
  50.         remove_proc_entry("hello",NULL);
  51. }

  52. MODULE_LICENSE("GPL");
  53. module_init(proc_init);
  54. module_exit(proc_cleanup);
复制代码
Makefile

  1. obj-m += proc_rw.o
  2. KDIR := /lib/modules/$(shell uname -r)/build
  3. PWD := $(shell pwd)
  4.     EXTRA_CFLAGS = -g -O0 -std=gnu99 -Wno-declaration-after-statement
  5. all:
  6.     make -C $(KDIR) M=$(PWD) modules
  7.     rm -rf *.ko.unsigned *.mod.c *.mod.o *.symvers *.o
  8. .PHONY: clean
  9. clean:
  10.     make -C $(KDIR) M=$(PWD) clean
复制代码
make并insmod

写入后查看内容
  1. echo -ne "a b c" > /proc/hello
复制代码
  1. # cat /proc/hello
  2. a b c
复制代码
写入包含换行符的字符序列
  1. echo -ne "a b c\td \ne   f" > /proc/hello
复制代码
  1. # cat /proc/hello
  2. e   f
复制代码
请各位大神指点一下,怎样copy_from_user()一次读取包含换行符的字符序列

论坛徽章:
0
2 [报告]
发表于 2017-03-29 18:39 |只看该作者
这个不是 copy_from_user 的问题。你的count 会在遇到回车的时候 设置,cut 然后进入下一轮的write.

所以我建议想要达到你说的效果,请仿照 dmesg  使用的 ring buff  的数据结构 来 代替 msg。

两个指针一个负责写。一个负责读取就好了。。

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
3 [报告]
发表于 2017-03-30 10:09 |只看该作者
回复 2# nuclearxin

感谢楼上,请教几个问题

write回调函数的buffer是用户内存空间,但我在内核源码中并未找到分配该内存空间的代码
如果count参数以'\n'计数,那么怎样改变这种行为?

proc的read与write,buffer都是在对proc文件读取和写入时自动分配的,怎样使用手动指定的缓冲区?

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
4 [报告]
发表于 2017-03-30 10:19 |只看该作者
回复 2# nuclearxin

再次请教,

a个'\n'会把输入分割成a+1段,write随之被调用了a+1次,因而读取时,read也被调用a+1次
在write的起始部分,copy_from_user调用之前,打印一下user buffer的长度,会观察到这种行为
  1. int write_proc(struct file *filp,const char *buf,size_t count,loff_t *offp)
  2. {
  3.     printk("buf size: %d\n", strlen_user(buf));
  4.     if (copy_from_user(msg,buf,count))
  5.         return -EFAULT;

  6.     len=count;
  7.     temp=len;
  8.     printk("write\n");
  9.     printk("count = %d\n", count);
  10.     printk("strlen(msg) = %d\n", strlen(msg));

  11.     return count;
  12. }
复制代码
  1. echo -ne "a b c\td \ne   f" > /proc/hello
复制代码
  1. # dmesg
  2. [76143.461257] buf size: 1613
  3. [76143.461261] write
  4. [76143.461262] count = 9
  5. [76143.461262] strlen(msg) = 16
  6. [76143.461268] buf size: 1613
  7. [76143.461269] write
  8. [76143.461270] count = 5
  9. [76143.461270] strlen(msg) = 16
复制代码
  1. cat /proc/hello
  2. e   f
复制代码
  1. # dmesg
  2. [76143.461257] buf size: 1613
  3. [76143.461261] write
  4. [76143.461262] count = 9
  5. [76143.461262] strlen(msg) = 16
  6. [76143.461268] buf size: 1613
  7. [76143.461269] write
  8. [76143.461270] count = 5
  9. [76143.461270] strlen(msg) = 16
  10. [76157.239084] read
  11. [76157.239088] count = 5
  12. [76157.239090] strlen(msg) = 16
  13. [76157.239102] read
  14. [76157.239103] count = 0
  15. [76157.239104] strlen(msg) = 16
复制代码

论坛徽章:
0
5 [报告]
发表于 2017-03-30 10:25 |只看该作者
回复 3# superwujc

内核空间的内存 要额外小心分配。和用户空间内存随意分配不一样。
count的机制 我不建议你去修改。  工作方式很合理你改这里就是坑。会影响其他所有proc下的文件类的行为。

还是申请的 circular buff 环形链表  作为固定 大小 内存来使用吧。

等我有空写下



论坛徽章:
0
6 [报告]
发表于 2017-03-30 10:30 |只看该作者
superwujc 发表于 2017-03-30 10:19
回复 2# nuclearxin

再次请教,

没看懂你请教什么 了。

你的这个code 在 write的时候会执行很多次。 只保留最后一次的 len 和buff 的内容

然后你的读取只运行1次啊。 所以只打最后一次write进来的内容。

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
7 [报告]
发表于 2017-03-30 10:40 |只看该作者
回复 6# nuclearxin

read和write调用的次数是一样的,只不过最后一次read出来的内容把前面的覆盖掉了

  1. [76143.461257] buf size: 1613
  2. [76143.461261] write
  3. [76143.461262] count = 9
  4. [76143.461262] strlen(msg) = 16
  5. [76143.461268] buf size: 1613
  6. [76143.461269] write
  7. [76143.461270] count = 5
  8. [76143.461270] strlen(msg) = 16
  9. [76157.239084] read
  10. [76157.239088] count = 5
  11. [76157.239090] strlen(msg) = 16
  12. [76157.239102] read
  13. [76157.239103] count = 0
  14. [76157.239104] strlen(msg) = 16
复制代码
cat文件然后dmesg
  1.     printk("read\n");
  2.     printk("count = %d\n", count);
  3.     printk("strlen(msg) = %d\n", strlen(msg));
复制代码
这段read函数中的代码被执行了2次,因为打印了2次

write被执行多次是因为user buf中的'\n'把输入在proc文件中的内容分割成多段,所以copy_from_user复制了多次user buf到kernel buf
read被执行多次是因为write被执行了多次,因而copy_to_user向user buf复制了多次

论坛徽章:
0
8 [报告]
发表于 2017-03-30 10:50 |只看该作者
superwujc 发表于 2017-03-30 10:40
回复 6# nuclearxin

read和write调用的次数是一样的,只不过最后一次read出来的内容把前面的覆盖掉了

read 被执行量2次 是cat  读完一行会尝试在读一次。

你的write会不断的使用\n分割的内容  不断重复覆盖 buff  和len。

你自己测试下

你可以连续 echo 不带 \n的 字符 然后最后cat 下看看是不是只触发上面的2次 read。


论坛徽章:
0
9 [报告]
发表于 2017-03-30 10:51 |只看该作者
本帖最后由 nuclearxin 于 2017-03-30 13:07 编辑
superwujc 发表于 2017-03-30 10:40
回复 6# nuclearxin

read和write调用的次数是一样的,只不过最后一次read出来的内容把前面的覆盖掉了

确实 挺像 描述的行为。  太巧了

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
10 [报告]
发表于 2017-03-30 13:08 |只看该作者
回复 9# nuclearxin

so问题来了

如果proc的user buf包含换行符,write怎样一次性全部把这些内容写入到内核空间?

求教

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP