核心中與驅動相關的記憶體操作之十六(非同步I/O)
阿新 • • 發佈:2019-02-02
1.非同步IO簡介:
Linux 非同步 I/O 是Linux 2.6 中的一個標準特性,其本質思想就是程序發出資料傳輸請求之後,程序不會被阻塞,也不用等待任何操作完成,程序可以在資料傳輸的時候繼續執行其他的操作.相對於同步訪問檔案的方式來說,非同步訪問檔案的方式可以提高應用程式的效率,並且提高系統資源利用率.直接 I/O 經常會和非同步訪問檔案的方式結合在一起使用.
如下:
2.核心中關於非同步IO的API:
實際上,非同步IO在驅動中很少會涉及.它也屬於fpos中的一個成員.如下:
aio_fsync 操作只對檔案系統程式碼感興趣, 因此我們在此不必討論它. 其他 2 個, aio_read 和 aio_write, 看起來非常象常規的 read 和 write 方法, 但是有幾個例外. 一個是 offset 引數由值傳遞; 非同步操作從不改變檔案位置, 因此沒有理由傳一個指標給它.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);
這裡比較核心的引數是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.
其中,scullp_aio_read()和scullp_aio_write()分別對應使用者空間的非同步讀寫的系統呼叫.兩函式只調用了scullp_defer_op()函式: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); }
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);
}