内核中与驱动相关的内存操作之十六(异步I/O)

1.异步IO简介:

    Linux 异步 I/O 是Linux 2.6 中的一个标准特性,其本质思想就是进程发出数据传输请求之后,进程不会被阻塞,也不用等待任何操作完成,进程可以在数据传输的时候继续执行其他的操作.相对于同步访问文件的方式来说,异步访问文件的方式可以提高应用程序的效率,并且提高系统资源利用率.直接 I/O 经常会和异步访问文件的方式结合在一起使用.

    如下:

内核中与驱动相关的内存操作之十六(异步I/O)_第1张图片


2.内核中关于异步IO的API:

    实际上,异步IO在驱动中很少会涉及.它也属于fpos中的一个成员.如下:

ssize_t (*aio_read) (struct kiocb *iocb, char *buffer,size_t count, loff_t offset);
ssize_t (*aio_write) (struct kiocb *iocb, const char *buffer,size_t count, loff_t offset);
int (*aio_fsync) (struct kiocb *iocb, int datasync);
    aio_fsync 操作只对文件系统代码感兴趣, 因此我们在此不必讨论它. 其他 2 个, aio_read 和 aio_write, 看起来非常象常规的 read 和 write 方法, 但是有几个例外. 一个是 offset 参数由值传递; 异步操作从不改变文件位置, 因此没有理由传一个指针给它.

    这里比较核心的参数是iocb,它是由内核创建、传递的,专门用于异步IO操作的.

    异步IO状态查询:

int is_sync_kiocb(struct kiocb *iocb); 
    如果这个函数返回一个非零值, 你的驱动必须同步执行这个操作.

    完成一个异步IO操作:

int aio_complete(struct kiocb *iocb, long res, long res2);
    iocb 是起初传递给你的同一个 IOCB,并且 res 是这个操作的通常的结果状态.res2 是将被返回给用户空间的第2个结果码;大部分的异步 I/O 实现作为 0 传递 res2. 一旦你调用 aio_complete,你不应当再碰 IOCB 或者用户缓冲.
    

3.示例模板:

    下面的示例模板来自LDD3.

static ssize_t scullp_aio_read(struct kiocb *iocb, char *buf, size_t count, loff_t pos)
{
        return scullp_defer_op(0, iocb, buf, count, pos);
}

static ssize_t scullp_aio_write(struct kiocb *iocb, const char *buf, size_t count, loff_t pos)
{
        return scullp_defer_op(1, iocb, (char *) buf, count, pos);
}
    其中,scullp_aio_read()和scullp_aio_write()分别对应用户空间的异步读写的系统调用.两函数只调用了scullp_defer_op()函数:

struct async_work
{
        struct kiocb *iocb;
        int result;
        struct work_struct work;

};

static int scullp_defer_op(int write, struct kiocb *iocb, char *buf, size_t count, loff_t pos)
{
        struct async_work *stuff;
        int result;

        /* Copy now while we can access the buffer */
        if (write)
                result = scullp_write(iocb->ki_filp, buf, count, &pos);
        else
                result = scullp_read(iocb->ki_filp, buf, count, &pos);

        /* If this is a synchronous IOCB, we return our status now. */
        if (is_sync_kiocb(iocb))
                return result;

        /* Otherwise defer the completion for a few milliseconds. */
        stuff = kmalloc (sizeof (*stuff), GFP_KERNEL);
        if (stuff == NULL)

                return result; /* No memory, just complete now */
        stuff->iocb = iocb;
        stuff->result = result;
        INIT_WORK(&stuff->work, scullp_do_deferred_op, stuff);
        schedule_delayed_work(&stuff->work, HZ/100);
        return -EIOCBQUEUED;
}
    注意到上述对iocb进行了状态的轮询,见上述语句:

        if (is_sync_kiocb(iocb))
                return result;
    一个异步IO的完成在等待队列里面:

static void scullp_do_deferred_op(void *p) 
{
 struct async_work *stuff = (struct async_work *) p;
 aio_complete(stuff->iocb, stuff->result, 0);
 kfree(stuff); 
} 








你可能感兴趣的:(内核中与驱动相关的内存操作之十六(异步I/O))