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

简述:
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 

详细的关于异步读写应用程序编程,参考下面博客:
慢慢聊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驱动中的异步函数

你可能感兴趣的:(linux驱动)