您的位置:首页 > 大数据 > 人工智能

linux驱动---file_operations异步读写aio_read、aio_write

2017-02-06 13:49 447 查看
简述:

file_operations中read,write是同步读写,异步读写用接口是aio_read、aio_wirte(在4.5版本中发现已经把名字改成read_iter、write_iter)。

异步读写对应的系统调用API:

int aio_read(struct aiocb *__aiocbp);
int aio_write(struct aiocb *__aiocbp);


定义在头文件中(如ubuntu,/usr/include/aio.h):

#include <aio.h>


详细的关于异步读写应用程序编程,参考下面博客:

慢慢聊Linux AIO

场景考虑:

同步读写:应用程序发起读写后,等到读写函数完成返回,才能继续跑后面的代码。

异步读写:应用程序发起读写后,将读写注册到队列,然后立马返回,应用程序继续跑后面的代码,速度非常快,当读写动作完成后,系统发消息通知应用程序,然后应用程序接收读写结果。

根据场景选择,驱动可以同时都实现同步和异步的接口。

file_operations结构体定义(在include/linux/fs.h):

struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
int (*show_fdinfo)(struct seq_file *m, struct file *f);
};


其中异步读写:

ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);


在linux 4.5版本中已经变成:

ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);


驱动如果已经实现了同步的读写,异步的实现还需要用到include/linux/aio.h中的数据结构和函数以及工作队列。

异步结构体struct kiocb;

函数:bool is_sync_kiocb(struct kiocb *kiocb),判断此处aio_read或aio_write是否指定为同步,是同步返回true,不是同步返回false。

函数:void aio_complete(struct kiocb *iocb, long res, long res2),通知系统异步完成,res为读取字节数,res2一般为0.

驱动接口实现例子:

struct kiocb *aki;
struct iovec *aiov;
loff_t aio_off = 0;
struct workqueue *aiowq;

void data_a(struct work_struct *work);
DECLARE_DELAYED_WORK(aio_delaywork,data_a);

ssize_t d_read(struct file *f, char __user *buf, size_t n, loff_t *off)
{
}
void data_a(struct work_struct *work)
{
int ret = 0;
ret = d_read(aki->ki_filp,aiov->iov->iov_base,n,&off);
aio_complete(aki,ret ,0);
}
ssize_t d_aio_read(struct kiocb *ki, const struct iovec *iovs, unsigned long n, loff_t off)
{
if(is_sync_kiocb(ki))
return d_read(ki->ki_filp,iovs->iov->iov_base,n,&off);
else
{
aki = ki;
aiov = iovs;
aio_off = off;
queue_delayed_work(aiowq,aio_delaywork,100);
return -EIOCBQUEUED;//一般都返回这个,
}
}
void init_aio()
{
aiowq= create_workqueue("aiowq");
}


新版本的用法如下:

ssize_t d_read_iter(struct kiocb *ki, struct iov_iter *iovs)
{
if(is_sync_kiocb(ki))
return d_read(ki->ki_filp,iovs->iov->iov_base,n,&off);
else
{
aki = ki;
aiov = iovs;
aio_off = off;
queue_delayed_work(aiowq,aio_delaywork,100);
return -EIOCBQUEUED;
}
}


这样,如果本次异步系统调用指定为同步,就和一般的read一样,如果是异步,就加入到一个workqueue,等到work(这个work,最好用延时版本)完成后,再通知系统。(个人理解,没有验证过- _ -,后面验证如发现不对再修改)

这样,应用程序(进程)可以很快返回,将读写的动作交给了workqueue的线程处理,完成后,再通知应用程序。

然后:

struct file_operations fop = {
.....
...
.aio_read = d_aio_read,
.....
...
};


就ok,异步写和读差不多用法。

异步读写,主要是在系统中差异,驱动只要实现对应的接口,类似同步的。

参考博客:

Linux驱动中的异步函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: