从用户空间的open到内核空间的open

提供一个从系统调用open到内核中该文件实际的open方法的调用流程分析,基本上列出来从open系统调用
到mem_pool_open过程中调用的函数。在这个过程中很多调用以及函数实现的细节还并不是很清楚。希望能够
起到抛砖引玉的作用,大家一起交流,把这个调用流程丰富起来。


i
nt open(const char *pathname, int flags, mode_t mode);  --系统调用
                            ||
                            \/
long sys_open(const char __user *filename, int flags, int mode)  -- fs/open.c
/*对应内核中的open接口函数*/
                            ||
                            \/
long do_sys_open(int dfd, const char __user *filename, int flags, int mode) --fs/open.c
/*用户空间的filename被拷贝到内核空间,获取当前可用的文件描述符*/
                            ||
                            \/
static struct file *do_filp_open(int dfd, const char *filename, int flags, int mode) --fs/open.c 
                            ||
                            \/
int open_namei(int dfd, const char *pathname, int flag,
  int mode, struct nameidata *nd)
/*获取该文件对应的nameidata结构.该函数执行完毕,接着调用下面函数。这两个函数是顺序被do_filp_open调用*/
                            ||
                            \/
struct file *nameidata_to_filp(struct nameidata *nd, int flags) --fs/open.c
/*将nameidata 结构转换为打开的struct file结构*/
                            ||
                            \/
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
     int flags, struct file *f,
     int (*open)(struct inode *, struct file *)) --fs/open.c
                            ||
                            \/
f->f_op = fops_get(inode->i_fop);  --fs/open.c
/*这里将系统调用中需要对应打开文件对应到内核中的file_operations结构体获取到,然后根据其函数
指针就可以找到该结构体中对该种文件操作的所有方法。mem_pool对应的结构体是在mem_pool_init的时候向内
核注册的。*/
                            ||
                            \/
open = f->f_op->open; 
open(inode, f);    --fs/open.c
/*以上两行代码分别完成了open系统调用时执行实际文件对应内核的open方法,即mem_pool_open */


来自:http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=2014732&extra=page%3D2%26filter%3Ddigest%26digest%3D1%26digest%3D1

内核空间使用`fip_open`函数读写字符设备,需要以下步骤: 1. 定义`file_operations`结构体: ```c static struct file_operations fops = { .owner = THIS_MODULE, .read = device_read, .write = device_write, .open = device_open, .release = device_release, }; ``` 2. 实现`device_open`函数: ```c static int device_open(struct inode *inode, struct file *file) { if (Device_Open) // 如果设备已经被打开则返回忙 return -EBUSY; Device_Open++; // 记录设备被打开的次数 try_module_get(THIS_MODULE); // 增加模块引用计数 return 0; } ``` 3. 实现`device_release`函数: ```c static int device_release(struct inode *inode, struct file *file) { Device_Open--; // 记录设备被关闭的次数 module_put(THIS_MODULE); // 减少模块引用计数 return 0; } ``` 4. 实现`device_read`函数: ```c static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset) { int bytes_read = 0; // 从设备中读取数据到缓冲区 bytes_read = read_from_device(buffer, length); return bytes_read; } ``` 5. 实现`device_write`函数: ```c static ssize_t device_write(struct file *filp, const char *buffer, size_t length, loff_t *offset) { int bytes_written = 0; // 将缓冲区中的数据写入设备 bytes_written = write_to_device(buffer, length); return bytes_written; } ``` 6. 注册字符设备: ```c int init_module(void) { int ret = 0; // 分配字符设备号 ret = alloc_chrdev_region(&dev, 0, 1, "my_device"); if (ret < 0) { printk(KERN_ERR "alloc_chrdev_region failed\n"); return ret; } // 初始化字符设备 cdev_init(&cdev, &fops); cdev.owner = THIS_MODULE; // 添加字符设备 ret = cdev_add(&cdev, dev, 1); if (ret < 0) { printk(KERN_ERR "cdev_add failed\n"); unregister_chrdev_region(dev, 1); return ret; } return 0; } ``` 7. 在需要读写设备的地方使用`filp_open`函数打开设备文件,然后进行读写操作: ```c struct file *filp; char buffer[1024]; ssize_t bytes_read = 0; // 打开设备文件 filp = filp_open("/dev/my_device", O_RDONLY, 0); if (!filp || IS_ERR(filp)) { printk(KERN_ERR "filp_open failed\n"); return -1; } // 读取数据 bytes_read = kernel_read(filp, buffer, sizeof(buffer), 0); if (bytes_read < 0) { printk(KERN_ERR "kernel_read failed\n"); filp_close(filp, NULL); return -1; } // 关闭设备文件 filp_close(filp, NULL); ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值