在内核中创建文件 filp_open/sys_open

之前以为在内核中不能创建文件,其实不是这样子的,只要文件系统跑起来之后就可以像在用户空间一样操作文件.
 
用户空间                   内核
open()                    sys_open(), filp_open()
close()                   sys_close(), filp_close()
read()                    sys_read(), filp_read()
write()                   sys_write(), filp_write()
----------------------------------------------------
 
在内核模块中有时会用不了 sys_xxxx, 这时用 filp_xxxx 对应的函数就行了, 在模块中使用 sys_xxxx 还有问题, 还没有找到原因.
 
在 /tmp 中创建文件 aa
struct file *filep;
filep=filp_open("/tmp/aa",O_CREAT | O_RDWR,0);
if(IS_ERR(filep))
  return -1;
filp_close(filep,0);
return 0;
 
========================================
sys_open 的使用方法:
#include <linux/fs.h>
 
......
 u8  Buff[50];
 int fd;
 memset(Buff, 0x00, sizeof(Buff));
 mm_segment_t old_fs = get_fs();
 set_fs(KERNEL_DS);
 fd = sys_open("/etc/Info", O_RDONLY, 0);
 if(fd>=0)
 {
  sys_read(fd, Buff, 50);
  printk("string: %s/n", Buff);
  sys_close(fd);
 }
 set_fs(old_fs);
 
 
========================================
下面 open 使用的一些参数:
O_ACCMODE <0003>;: 读写文件操作时,用于取出flag的低2位。
O_RDONLY<00>;: 只读打开
O_WRONLY<01>;: 只写打开
O_RDWR<02>;: 读写打开
O_CREAT<0100>;: 文件不存在则创建,需要mode_t,not fcntl
O_EXCL<0200>;: 如果同时指定了O_CREAT,而文件已经存在,则出错, not fcntl
O_NOCTTY<0400>;: 如果pathname指终端设备,则不将此设备分配作为此进程的控制终端。not fcntl O_TRUNC<01000>;: 如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0。not fcntl
O_APPEND<02000>;: 每次写时都加到文件的尾端
O_NONBLOCK<04000>;: 如果p a t h n a m e指的是一个F I F O、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I / O操作设置非阻塞方式。
O_NDELAY;;
O_SYNC<010000>;: 使每次write都等到物理I/O操作完成。
FASYNC<020000>;: 兼容BSD的fcntl同步操作
O_DIRECT<040000>;: 直接磁盘操作标识
O_LARGEFILE<0100000>;: 大文件标识
O_DIRECTORY<0200000>;: 必须是目录
O_NOFOLLOW<0400000>;: 不获取连接文件
O_NOATIME<01000000>;: 暂无
当新创建一个文件时,需要指定mode 参数,以下说明的格式如宏定义名称<实际常数值>;: 描述。
S_IRWXU<00700>;:文件拥有者有读写执行权限
S_IRUSR (S_IREAD)<00400>;:文件拥有者仅有读权限
S_IWUSR (S_IWRITE)<00200>;:文件拥有者仅有写权限
S_IXUSR (S_IEXEC)<00100>;:文件拥有者仅有执行权限
S_IRWXG<00070>;:组用户有读写执行权限
S_IRGRP<00040>;:组用户仅有读权限
S_IWGRP<00020>;:组用户仅有写权限
S_IXGRP<00010>;:组用户仅有执行权限
S_IRWXO<00007>;:其他用户有读写执行权限
S_IROTH<00004>;:其他用户仅有读权限
S_IWOTH<00002>;:其他用户仅有写权限
S_IXOTH<00001>;:其他用户仅有执行权限
   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、付费专栏及课程。

余额充值