最近写程序需要内核得到用户态的参数,比较苦逼幸福的是虽然ioctrl 用不了,可以用proc实现,proc文件系统提供了一种内核和用户态交互的方法。

proc文件系统的详细接口看<linux/proc_fs.h>

主要需要关注的是这几个函数:

struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent)
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent);
void remove_proc_entry(const char *name, struct proc_dir_entry *parent);

函数 proc_mkdir用于在proc文件系统下创建文件夹, proc_mkdir的第一个参数是要创建的目录的名字,第二个参数是指向父目录结构的指针。需要注意一下几点:

1. 创建过程没有对于名字的检查,完全可以调用proc_mkdir 创建出一堆同样名字的文件(检查一下会死啊!)

2. 其实名字可以包含路径,例如“dev/new_proc”, 如果存在dev目录,函数会在dev目录下创建new_proc目录。

3. 如果第二个参数是NULL,会在根目录也就是/proc/目录下创建目录

函数的返回值就是 新创建目录对应的proc_dir_entry, 保存这个就可以用来在此目录下创建文件啦,其实,即使不保存,利用上面介绍的第二点性质也可以在目录下创建文件,而且删除目录只用知道路径就可以了~

函数create_proc_entry用来创建文件,mode 参数如果为NULL的话默认的文件访问权限是 755,其他的参数与proc_mkdir 类似

函数remove_proc_entry用来删除创建的目录或者文件,有意思的是,这个函数只需要知道名字和父目录就可以删除了。

说了这么多,怎么交换数据尼?

需要了解下proc_dir_entry 的结构了

struct proc_dir_entry {unsigned int low_ino;unsigned short namelen;const char *name;mode_t mode;nlink_t nlink;uid_t uid;gid_t gid;loff_t size;struct inode_operations * proc_iops;const struct file_operations * proc_fops;get_info_t *get_info;struct module *owner;struct proc_dir_entry *next, *parent, *subdir;void *data;read_proc_t *read_proc;write_proc_t *write_proc;atomic_t count;      /* use count */int deleted;     /* delete flag */void *set;
};

其他的参数可以忽略,这里需要注意的是两个成员变量:

read_proc 和 write_proc

这两个变量的类型如下:

typedef int (read_proc_t)(char *page, char **start, off_t off, int count, int *eof, void *data);
typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data);

对proc文件的读写操作,最终将转化为对read_proc和write_proc的调用。

看到这里明白了吧,只要在内核里注册proc文件,实现read_proc 和write_proc函数,然后设置proc_dir_entry对应成员变量的值,在用户态进行读写就可以和内核交互了

解释这两个函数的参数:

对于read_proc_t

1. 第一个参数:为啥叫page?答案就是如果对proc文件调用读操作,内核会分配一个页大小的缓冲区。如何输出大于一个页的数据呢,这得依赖于第二个和第三个参数了。

为了理解第二三个参数,回忆下与文件操作相关的系统调用:

int open(const char *pathname, int flags);
off_t lseek(int fildes, off_t offset, int whence);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

对于proc文件,一次read操作最多只能读取一个page的数据,如果需要读取大于一个页的数据需要保存read的返回值,然后使用lseek设定offset,然后再次调用read。回到参数的说明:

2. start和off参数:off对应于lseek里面的offset(lseek whence为SEEK_END,offset为负 的情况下,传进来的off为零,具体原因待考古)。

如果不设置*start的值,off的取值只能在[0, count - 1]之间,且能够读取的数据大小为:count - off。可以理解系统拷贝了 [page + off, page+count - 1]之间的数据到用户的buffer里。如果off的取值超出范围,read将读不到数据。

如果设置了*start的值,系统认为*start指向的地址就是off指定的地址,off的值会被忽略,系统会拷贝[start, start+count-1]之间的数据到用户空间。当然我们在实现start地址的定位时,可能会需要off的值。

3. count 参数与read中的count一致

4. eof参数,设置了这个参数表明不想再提供数据了,神马意思呢?

如果不设置这个参数,对于上面说的start为空的情况,read_proc返回后,系统如果发现 (count - off) < count 会接着下发写请求,读取off大小的数据。

例如:有这样的读取操作:

lseek(fd, 2, SEEK_SET); read(fd, buff_r, 30)

第一次调用read_proc, off=2, count=30, 由于我们没有设置start的值,将读取28字节的数据,由于没有设置*eof, 系统会再次下发read_proc

第二次调用read_proc, off=30, count=2, 在参数start的说明里提到,对于这个调用,系统默认读不到数据(怨念啊,为啥要下发)

于是read返回28

如果设置了这个参数就不会有第二次的下发了。

5. data参数,这个是给驱动程序预留的参数。

对于write_proc函数,参数是很简单的,需要说明的只有一点,就是write_proc的第二个参数buffer是用户态的地址,需要用copy_from_user从用户态把数据拷到内核态的缓冲区里。

作者:ziziwu 发表于2011-10-20 14:40:08 原文链接
阅读:7 评论:0 查看评论

转载于:https://www.cnblogs.com/ziziwu/archive/2011/10/20/2218975.html

利用proc 实现内核和用户态交换数据相关推荐

  1. linux收发包内核进程名称,Linux内核IP Queue机制的分析(一)——用户态接收数据包...

    序 笔者将会通过包括本文在内的三篇文章,对IP Queue机制从用户态的应用到内核态的模块程序设计进行分析.三篇文章的题目分别是: Linux内核IP Queue机制的分析(一)­--用户态接收数据包 ...

  2. 操作系统4小时速成:操作系统发展和分类,运行环境:运行机制和内核,用户态非特权,核心态特权,中断技术,访管指令

    操作系统4小时速成:操作系统发展和分类,运行环境:运行机制和内核,用户态非特权,核心态特权,中断技术,访管指令 2022找工作是学历.能力和运气的超强结合体,遇到寒冬,大厂不招人,可能很多算法学生都得 ...

  3. 利用Hadoop和Spark处理用户心跳周期数据

    数据源:可穿戴设备的实时数据分析.1.txt记录的是某一个用户的心跳周期数据,每一个数值表示一次心跳的周期,单位是秒.例如,0.8表示用户当时的心跳间隙是0.8秒.心跳间期按照顺序存储 MapRedu ...

  4. Java程序员需要掌握的计算机底层知识(二):操作系统、内核、用户态与内核态、系统调用的执行过程

    操作系统 启动过程 通电 -> bios uefi 工作 -> 自检 -> 到硬盘固定位置加载bootloader -> 读取可配置信息 -> CMOS CMOS 用来存 ...

  5. Linux(内核和用户态的)动态内存管理

    http://www.ibm.com/developerworks/cn/linux/l-cn-slub/ 内核对象缓冲区管理 Linux 内核在运行过程中,常常会需要经常使用一些内核的数据结构(对象 ...

  6. [转]内核和用户空间数据交换

    转自 https://www.ibm.com/developerworks/cn/linux/l-kerns-usrs/index.html 转载于:https://www.cnblogs.com/y ...

  7. Linux用户态与内核态通信的几种方式(待完善)

    文章目录 1. 内核启动参数 2.模块参数与sysfs 3.sysctl 4.系统调用 5.netlink 6. procfs(/proc) 7.seq_file 8.debugfs 9.relayf ...

  8. netlink实现与使用方法详解(用户态/内核态)

    一.什么是netlink Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口. 在Linux 内核中,使用netlink ...

  9. Linux 内核态与用户态通信 netlink

    参考资料: https://blog.csdn.net/zqixiao_09/article/details/77131283 https://www.cnblogs.com/lopnor/p/615 ...

最新文章

  1. ASP.NET重用代码技术 - 代码绑定技术
  2. 【bzoj4881】[Lydsy2017年5月月赛]线段游戏 树状数组+STL-set
  3. 嵌入式系统中系统时间显示
  4. springboot+mongodb
  5. 偏心率e用于描述某一轨道与圆轨道的区别
  6. java eclipse 内存_java – Eclipse 3.5.1使用大量内存
  7. 机器学习(九)——EM算法
  8. 现代软件工程 结对编程 (II) 电梯调度 算法和测试框架
  9. 让UILabel的文字顶部对齐
  10. nginx基于tcp负载均衡
  11. Extjs4.0 视频教程
  12. 金万维异速联再出大杀器 掀移动应用普及化年终热浪
  13. Flash CS6 新功能
  14. excel 多行 取消隐藏_取消隐藏Excel行和列的问题
  15. java html 导出 pdf文件,Java HTML导出PDF (一)
  16. 富途牛牛A股数据API使用基础教程
  17. 基于51单片机远近光灯切换电路设计方案
  18. Excel中SEARCH函数的使用方法
  19. 【Latex 格式】Markdown或者LaTeX在单个字母上加一横、一点、两点、三角
  20. 公众号滑动图代码_微信公众号图文排版之图片滑动的新玩法

热门文章

  1. ffmpeg利用libav库把yuv视频流转换为TS串流
  2. 关于继承方式和访问权限
  3. S6 文件备份与压缩命令
  4. python从字典里搜索_Python:在字典中搜索字典的函数
  5. java中循环语句_Java语法基础之循环结构语句详解
  6. python编写界面遍历_python和pywin32实现窗口查找、遍历和点击
  7. 编译安装_Unbound编译安装
  8. win10怎么共享打印机_共享打印机添加不上怎么办?建议收藏备用
  9. BFS(入门题--迷宫)
  10. 双11特刊 | 全面云原生化,数据库实例独共享混部 最高降低30%成本