简述:
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驱动中的异步函数