内核态下的设备文件操作(filp_open)

本文分享了一个在内核态下访问设备文件的Linux驱动编程实例,包括模块调用驱动程序的方法及关键代码实现,旨在帮助初学者理解内核态驱动编程的基本流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载地址:http://blog.chinaunix.net/uid-22237530-id-1781801.html

Linux驱动编程书籍大多数都是介绍怎样用户态下怎么访问硬件设备,由于项目的需要,本人做了内核态下访问设备文件的方法,现在把程序拿出来和大家分享一下,希望对刚入门的朋友有所帮助。
在我的《内核模块调用驱动》中给出了简单的字符设备文件程序,可以作为本文的驱动对象,在此,我就不多介绍了。调用驱动程序的模块如下:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/fs.h>
#include <asm/unistd.h>
#include <asm/uaccess.h>
#include <linux/types.h>
#include <linux/ioctl.h>
#include "chardev.h"
MODULE_LICENSE("GPL");
//#define __KERNEL_SYSCALLS__
#define bao "/dev/baovar"
static char buf1[20];
static char buf2[20];
static int __init testmod_init(void)
{
mm_segment_t old_fs;
ssize_t result;
ssize_t ret;
sprintf(buf1,"%s","baoqunmin");
struct file *file=NULL;
file=filp_open(bao,O_RDWR,0);
if(IS_ERR(file)) goto fail0;
old_fs=get_fs();
set_fs(get_ds());
ret=file->f_op->write(file,buf1,sizeof(buf1),&file->f_pos);
result=file->f_op->read(file,buf2,sizeof(buf2),&file->f_pos);
if(result>=0){buf2[20]='\n';printk("buf2-->%s\n",buf2);}
else printk("failed\n");
result=file->f_op->ioctl(file,buf2,sizeof(buf2),&file->f_pos);
result=file->f_op->read(file,buf2,sizeof(buf2),&file->f_pos);
set_fs(old_fs);
filp_close(file,NULL);
printk("file loaded\n");
return 0;
fail0:{filp_close(file,NULL);printk("load failed\n");}
return 1;
}
static void __exit testmod_cleanup(void)
{

printk("module exit......................................................\n");
}
module_init(testmod_init);
module_exit(testmod_cleanup);
以上是完整的程序,直接可以编译运行。
#include "chardev.h"头文件定义如下,此头文件也必须在驱动中包含!
#include <linux/ioctl.h>
#define BAO_IOCTL 't'
#define IOCTL_READ _IOR(BAO_IOCTL, 0, int)
#define IOCTL_WRITE _IOW(BAO_IOCTL, 1, int)
#define BAO_IOCTL_MAXNR 1
以下给出了我的Makefile文件:
CC=gcc
MODCFLAGS := -Wall -DMODULE -D__KERNEL__ -DLINUX -I/usr/src/linux-2.4.20-8/include
test.o :test.c
$(CC) $(MODCFLAGS) -c test.c
echo insmod test.o to turn it on
echo rmmod test to turn it off
echo
1.先加载设备驱动,我的设备文件为bao,
2.再make以上文件
3./sbin/insmod test.o加载模块
4.dmesg 查看运行结果
5./sbin/rmmod test
6.卸载加载的驱动
我在Linux red hat 9.0下成功运行
我实现的只是在模块间对驱动程序的调用,可以说是这是一个最简单的例子。
希望大家能有所收获!

 

<think>好的,用户想了解Linux内核中filp_open函数的使用方法。首先,我需要回忆一下filp_open的作用和在内核中的位置。记得filp_open是内核中用来打开文件的函数,类似于用户空间的open,但用于内核模块开发。用户可能是在编写内核模块时需要访问文件,比如读取配置或写入日志。 接下来,我应该考虑用户的使用场景。他们可能需要在模块中打开一个文件,进行读写操作,然后关闭。需要详细说明函数原型、参数含义以及必要的错误处理。比如,filp_open需要文件路径、打开标志和模式,返回struct file*指针。同时,要提醒用户内核中文件操作的限制,比如路径是相对于当前进程的,可能需要绝对路径。 然后,需要注意内核版本差异。不同内核版本的函数参数可能有变化,比如早期的版本可能没有mode参数,或者flags的类型不同。用户可能遇到兼容性问题,需要根据他们使用的内核版本来调整代码。 另外,用户可能不了解内核中文件操作的风险,比如休眠问题。filp_open可能会引起调度,所以不能在原子上下文中使用。这点需要强调,避免用户在不合适的上下文调用导致问题。 还要考虑示例代码的正确性。比如,正确使用filp_open后,需要用IS_ERR检查错误,而不是NULL。读写操作需要使用kernel_read和kernel_write,而不是vfs_read/vfs_write,因为后者参数不同。关闭文件时使用filp_close,并处理可能的错误。 用户可能忽略权限问题,比如需要CAP_SYS_ADMIN能力,或者文件系统的挂载状态。这些也需要提及,帮助他们排查问题。 最后,总结使用步骤和注意事项,确保用户能安全正确地使用filp_open。同时,提醒他们尽量使用其他内核机制替代直接文件操作,以符合内核最佳实践。</think>Linux内核中的`filp_open()`函数是用于在内核空间打开文件的核心接口,其功能类似于用户空间的`open()`系统调用。以下是详细的使用说明: --- ### 一、函数原型 ```c struct file *filp_open(const char *filename, int flags, umode_t mode); ``` - **filename**: 文件路径(需注意内核路径表示方式) - **flags**: 打开标志(如`O_RDONLY`, `O_WRONLY`, `O_CREAT`等) - **mode**: 文件创建时的权限(仅在`O_CREAT`时生效) --- ### 二、使用步骤 #### 1. 包含头文件 ```c #include <linux/fs.h> #include <linux/file.h> ``` #### 2. 打开文件 ```c struct file *fp = filp_open("/path/to/file", O_RDWR | O_CREAT, 0644); if (IS_ERR(fp)) { printk(KERN_ERR "Open failed: %ld\n", PTR_ERR(fp)); return PTR_ERR(fp); } ``` #### 3. 文件读写操作 ```c // 写入数据 char buf[] = "kernel data"; loff_t pos = 0; ssize_t ret = kernel_write(fp, buf, sizeof(buf), &pos); // 读取数据 char rbuf[100]; loff_t pos = 0; ssize_t ret = kernel_read(fp, rbuf, sizeof(rbuf), &pos); ``` #### 4. 关闭文件 ```c filp_close(fp, NULL); // 第二个参数为fl_owner_t,通常填NULL ``` --- ### 三、关键注意事项 1. **路径格式**: - 使用**绝对路径**(如`/etc/config`) - 路径基于调用进程的根目录(通常为系统根目录`/`) 2. **上下文限制**: - 不能在原子上下文(如中断处理程序)中使用 - 可能引发进程调度(函数内部可能休眠) 3. **权限问题**: - 需要`CAP_SYS_ADMIN`能力 - 文件系统必须已挂载且可访问 4. **错误处理**: - 返回值需用`IS_ERR()`检查 - 错误码通过`PTR_ERR()`获取 --- ### 四、典型应用场景 1. 内核模块需要读取配置文件 2. 驱动程序记录调试日志 3. 实现特殊文件系统功能 --- ### 五、内核版本差异 | 内核版本 | 行为变化 | |---------------|----------------------------------| | < 4.14 | 无`mode`参数 | | ≥ 4.14 | 增加`mode`参数 | | ≥ 5.10 | 类型安全改进 | --- ### 六、替代方案建议 - 优先考虑通过`sysfs`或`procfs`暴露配置 - 对于日志记录建议使用`printk`系列函数 - 需要频繁文件操作时考虑实现到用户空间的接口 > **注意**:内核中直接操作文件属于高风险行为,需严格评估必要性。建议在开发阶段增加异常处理,生产环境中慎用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值