转自:http://blog.csdn.net/yf210yf/article/details/8997007

有时候需要在Linux kernel--大多是在需要调试的驱动程序--中读写文件数据。在kernel中操作文件没有标准库可用,需要利用kernel的一些函数,这些函数主 要有: filp_open() filp_close(), vfs_read() vfs_write(),set_fs(),get_fs()等,这些函数在linux/fs.h和asm/uaccess.h头文件中声明。下面介绍主 要步骤
  1. 打开文件

  filp_open()在kernel中可以打开文件,其原形如下:

  strcut file* filp_open(const char* filename, int open_mode, int mode);

  该函数返回strcut file*结构指针,供后继函数操作使用,该返回值用IS_ERR()来检验其有效性。

  参数说明

  filename: 表明要打开或创建文件的名称(包括路径部分)。在内核中打开的文件时需要注意打开的时机,很容易出现需要打开文件的驱动很早就加载并打开文件,但需要打开的文件所在设备还不有挂载到文件系统中,而导致打开失败。

  open_mode: 文件的打开方式,其取值与标准库中的open相应参数类似,可以取O_CREAT,O_RDWR,O_RDONLY等。

  mode: 创建文件时使用,设置创建文件的读写权限,其它情况可以匆略设为0

  2. 读写文件

  kernel中文件的读写操作可以使用vfs_read()和vfs_write,在使用这两个函数前需要说明一下get_fs()和 set_fs()这两个函数。

  vfs_read() vfs_write()两函数的原形如下:

  ssize_t vfs_read(struct file* filp, char __user* buffer, size_t len, loff_t* pos);

  ssize_t vfs_write(struct file* filp, const char __user* buffer, size_t len, loff_t* pos);

  注意这两个函数的第二个参数buffer,前面都有__user修饰符,这就要求这两个buffer指针都应该指向用户空间的内存,如果对该参数传 递kernel空间的指针,这两个函数都会返回失败-EFAULT。但在Kernel中,我们一般不容易生成用户空间的指针,或者不方便独立使用用户空间 内存。要使这两个读写函数使用kernel空间的buffer指针也能正确工作,需要使用set_fs()函数或宏(set_fs()可能是宏定义),如 果为函数,其原形如下:

  void set_fs(mm_segment_t fs);

  该函数的作用是改变kernel对内存地址检查的处理方式,其实该函数的参数fs只有两个取值:USER_DS,KERNEL_DS,分别代表 用户空间和内核空间,默认情况下,kernel取值为USER_DS,即对用户空间地址检查并做变换。那么要在这种对内存地址做检查变换的函数中使用内核 空间地址,就需要使用set_fs(KERNEL_DS)进行设置。get_fs()一般也可能是宏定义,它的作用是取得当前的设置,这两个函数的一般用 法为:

  mm_segment_t old_fs;

  old_fs = get_fs();

  set_fs(KERNEL_DS);

  ...... //与内存有关的操作

  set_fs(old_fs);

  还有一些其它的内核函数也有用__user修饰的参数,在kernel中需要用kernel空间的内存代替时,都可以使用类似办法。

  使用vfs_read()和vfs_write()最后需要注意的一点是最后的参数loff_t * pos,pos所指向的值要初始化,表明从文件的什么地方开始读写。

  3. 关闭读写文件

  int filp_close(struct file*filp, fl_owner_t id);

  该函数的使用很简单,第二个参数一般传递NULL值,也有用current->files作为实参的。

  使用以上函数的其它注意点:

  1. 其实Linux Kernel组成员不赞成在kernel中独立的读写文件(这样做可能会影响到策略和安全问题),对内核需要的文件内容,最好由应用层配合完成。

  2. 在可加载的kernel module中使用这种方式读写文件可能使模块加载失败,原因是内核可能没有EXPORT你所需要的所有这些函数。

  3. 分析以上某些函数的参数可以看出,这些函数的正确运行需要依赖于进程环境,因此,有些函数不能在中断的handle或Kernel中不属于任可进程的代码 中执行,否则可能出现崩溃,要避免这种情况发生,可以在kernel中创建内核线程,将这些函数放在线程环境下执行(创建内核线程的方式请参数 kernel_thread()函数)。

=========================================================================================

转载于: http://blogold.chinaunix.net/u3/113927/showart_2495807.html

在VFS的支持下,用户态进程读写 任何类型的文件系统都可以使用read和write着两个系统调用,但是在linux内核中没有这样的系统调用我们如何操作文件呢?我们知道read和 write在进入内核态之后,实际执行的是sys_read和sys_write,但是查看内核源代码,发现这些操作文件的函数都没有导出(使用 EXPORT_SYMBOL导出),也就是说在内核模块中是不能使用的,那如何是好?

通过查看sys_open的源码我 们发现,其主要使用了do_filp_open()函数,该函数在fs/namei.c中,而在改文件中,filp_open函数也是调用了 do_filp_open函数,并且接口和sys_open函数极为相似,调用参数也和sys_open一样,并且使用EXPORT_SYMBOL导出 了,所以我们猜想该函数可以打开文件,功能和open一样。使用同样的查找方法,我们找出了一组在内核中操作文件的函数,如下:

功能 函数原型
打开文件 struct file *filp_open(const char *filename, int flags, int mode)
读取文件 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
写文件 ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
关闭文件 int filp_close(struct file *filp, fl_owner_t id)

我们注意到在vfs_read和vfs_write函数中,其参数buf指向的用户空间的内存地址,如果我们直接使用内核空间的指针,则会返回-EFALUT。所以我们需要使用
set_fs()和get_fs()宏来改变内核对内存地址检查的处理方式,所以在内核空间对文件的读写流程为:

mm_segment_t fs = get_fs();
set_fs(KERNEL_FS);
//vfs_write();
vfs_read();
set_fs(fs);
下面为一个在内核中对文件操作的例子:

[cpp] view plaincopy print?
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/fs.h>
  4. #include <linux/uaccess.h>
  5. static char buf[] = "你好";
  6. static char buf1[10];
  7. int __init hello_init(void)
  8. {
  9. struct file *fp;
  10. mm_segment_t fs;
  11. loff_t pos;
  12. printk("hello enter\n");
  13. fp = filp_open("/home/niutao/kernel_file", O_RDWR | O_CREAT, 0644);
  14. if (IS_ERR(fp)) {
  15. printk("create file error\n");
  16. return -1;
  17. }
  18. fs = get_fs();
  19. set_fs(KERNEL_DS);
  20. pos = 0;
  21. vfs_write(fp, buf, sizeof(buf), &pos);
  22. pos = 0;
  23. vfs_read(fp, buf1, sizeof(buf), &pos);
  24. printk("read: %s\n", buf1);
  25. filp_close(fp, NULL);
  26. set_fs(fs);
  27. return 0;
  28. }
  29. void __exit hello_exit(void)
  30. {
  31. printk("hello exit\n");
  32. }
  33. module_init(hello_init);
  34. module_exit(hello_exit);
  35. MODULE_LICENSE("GPL");

另:

inux内核态用不到c函数库的,所以写文件是一个比较费事的事情。
下面这段代码,接我上一篇,是重构linux语义用到的,功能为获取一些结构体元素的偏移。
写文件的主体代码如下

01 static void filewrite(char* filename, char* data)
02 {
03   struct file *filp;
04   mm_segment_t fs;
05   filp = filp_open(filename, O_RDWR| O_APPEND| O_CREAT, 0644);
06   if(IS_ERR(filp))
07   {
08       printk("open error...\n");
09       return;
10   }
11   fs=get_fs();
12   set_fs(KERNEL_DS);
13   filp->f_op->write(filp, data, strlen(data),&filp->f_pos);
14   set_fs(fs);
15   filp_close(filp,NULL);
16 }

转载于:https://www.cnblogs.com/sky-heaven/p/5549357.html

内核态文件操作【转】相关推荐

  1. 用户态与内核态 文件流与文件描述符 简介【转】

    转自:https://www.cnblogs.com/Jimmy1988/p/7479856.html 用户态和内核态 程序代码的依赖和调用关系如下图所示: Lib:标准ASCI C函数,几乎所有的平 ...

  2. Linux 的内核态与用户态

    我们常说的 Linux 严格来说指代的是 Linux Kernel,泛指使用或裁剪标准 Linux Kernel 并在此基础之上实现各种应用程序解决方案的操作系统发行版本(e.g. RHEL.SUSE ...

  3. 用户态和内核态之间的切换

    用户态和内核态之间的切换 切换方式 从用户态到内核态切换可以通过三种方式,或者说会导致从用户态切换到内核态的操作: 系统调用,这个上面已经讲解过了,在我公众号之前的文章也有讲解过.其实系统调用本身就是 ...

  4. 理解用户态切换到内核态——内核态下有一个特殊的进程

    现在想想,从用户态进入到内核态,相当于一次进程切换--这就好像内核态下有一个特殊的进程. 我就把进入内核态后,理解为进入了一个特殊的进程,一切都忽然合理了,恍然大悟--所以所有用户态的task(称之为 ...

  5. ioctrl原形 linux_Linux常见的几种用户态与内核态交互方式优缺点

    背景 由于Linux 系统分为了用户态和内核态,用户态在设计初衷就是运行与硬件无关的应用程序,与硬件相关的操作大部分都集中在内核态处理.所以用户态如果需要获取硬件信息,或者操作硬件,必须要通过某种方式 ...

  6. 「操作系统」什么是用户态和内核态?为什么要区分

    「操作系统」什么是用户态和内核态?为什么要区分 参考&鸣谢 从根上理解用户态与内核态 程序员阿星 并发编程(二十六)内核态和用户态 Lovely小猫 操作系统之内核态与用户态 fimm 文章目 ...

  7. 用户态和内核态的简单理解

    文章目录 linux基础 系统调用和库函数的区别 为什么要区分用户态和内核态? 用户态和内核态的切换耗费时间的原因 哪些情况会出出现用户态和内核态的切换 用户态切换到内核态的三种方式 linux基础 ...

  8. 从根上理解用户态与内核态

    欢迎来到操作系统系列,采用图解 + 大白话的形式来讲解,让小白也能看懂,帮助大家快速科普入门. 本篇文章开始探秘用户态与内核态,虽然一般面试不会问这个,但搞清楚这块,对我们理解整个计算机系统是及其有意 ...

  9. 计算机内核态和用户态,用户态和内核态的区别是什么

    用户态和内核态的区别是,内核态运行操作系统程序,操作硬件,用户态运行用户程序:当程序运行在3级特权级上时,可以称之为运行在用户态,当程序运行在0级特权级上时,称之为运行在内核态. 本文操作环境:win ...

最新文章

  1. SQL 时间类型转字符串格式列表
  2. 怎样将项目上传到github上
  3. matlab apfc,APFC-Boost 带APFC的Boost升压变换器在Matlab中的仿真实现 - 下载 - 搜珍网...
  4. 2020-11-15(getinstance)
  5. 利用poi进行数据的excel导出
  6. http的302,303和307
  7. 一个配件、一块面料,制造企业流水线因为AI变了新模样(人工智能应用案例)
  8. 局域网只能看到一部分电脑_win10 网上邻居看不到其它电脑、共享不了文件
  9. 前端学习(172):格式化文本
  10. Linux基础提高_系统性能相关命令
  11. 自适应网页设计(Responsive Web Design)响应式设计
  12. python函数介绍
  13. 红橙Darren视频笔记 缓存方案 缓存到数据库(数据库操作) 上
  14. tcp关闭连接:挥手讨论
  15. 阿里云oss权限控制,上传下载测试
  16. 深度学习中常用优化器算法Optimizer详解(BGD、SGD、MBGD、Momentum、NAG、Adagrad、Adadelta、RMSprop、Adam)
  17. sqlserver 2008完整安装教程
  18. 线性代数之 实对称矩阵,正交对角化,二次型与正定矩阵
  19. 百度地图Android开发清除上一次驾车导航路线
  20. java模拟人生世界冒险_《模拟人生3世界冒险》的冒险心得与注意点

热门文章

  1. SQL定时自动备份,并将备份文件加密压缩并自动下载的实现
  2. 时态数据库的应用介绍(1)
  3. 可视化管理一目了然 锐捷RG-UAC承载荔湾教育局“御网”之道
  4. 《Android开发秘籍(第2版)》——第1.4节Android设备间的硬件差异
  5. HA集群--corosync+pacemaker
  6. C++与tolua++的完整调用流程,超级详解解决交互疑难
  7. 【c++模板实现】二叉查找树
  8. CS 客户端不引用AE
  9. sql 包含某个字符_「17」MySQL中正则表达式查询的SQL语句集锦
  10. java 快排_秋招|字节跳动Java后台已上岸,发个面经回馈牛油