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

来源:互联网 发布:巴西农业部数据 mapa 编辑:程序博客网 时间:2024/05/27 10:42

1.异步IO简介:

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

    如下:



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); } 








0 0
原创粉丝点击