1. 程式人生 > >字元裝置之read和write

字元裝置之read和write

1.核心空間的read()和write():   

    read和write最大的意義是完成使用者空間到核心空間的資料互動.其原型如下:

ssize_t read(struct file *filp,char __user *buff,size_t count,loff_t *offp);
ssize_t write(struct file *filp,const char __user *buff,size_t count,loff_t *offp);
    各引數的意義如下:
filp:檔案指標,由open()產生;
buff:使用者空間的指標;
count:請求傳輸的數量長度,以位元組為單位;
offp:使用者在檔案中進行存取操作的偏移量.因此,我們可以通過指定這個引數並配合count引數讀取某檔案或buf的指定資料段;
   

    1-1.read()的返回值:

返回值為count則說明資料全部傳輸完成;
返回值為正(標誌為len)但是比count小,表明實際傳輸了(count - len)位元組,這時候需要重新讀取資料;
返回值為0,則表示到了檔案尾;
返回值為負表示出錯.

    1-2.write()的返回值:

返回值為count,則說明完成了所請求的數目的位元組資料長度;
返回值為正(標誌為len)並小於count,則只傳輸了(count - len)個位元組,這時候需要重新傳輸資料;
返回值為0,意味著什麼也沒寫入;
返回值為負表示出錯.

2.copy_to_user()和copy_from_user():

    read()和write()只是對應於使用者空間的系統呼叫,並不產生實質的資料互動.並且這裡注意一點,上述的指標引數buff對核心空間而言極有可能是無效的,不作任何處理地引用這個引數指標,有可能引發oops.因此,當用戶空間和核心空間產生資料互動的時候,還需要借用核心提供的API來實現:copy_to_user()和copy_from_user().其原型如下:

unsigned long copy_to_user(void __user *to,const void *from,unsigned long count);
unsigned long copy_from_user(void *to,const void __user *from,unsigned long count);
    兩個函式的第一個引數均為目標地址;第二個引數均為源地址;第三個引數為資料長度.

    這兩個函式若無錯誤產生,則返回0.

    使用這兩個核心API時,需要注意以下兩點:

1).可能會引起睡眠;
2).返回值是還需要拷貝的記憶體資料長度.

    2-1.__copy_to_user()和__copy_from_user():

    在使用者指標對核心的合法性有保障的情況下,可以使用__copy_to_user()和__copy_from_user()兩個函式來取代上述的copy_to_user()和copy_from_user()兩個函式.

3.readv()和writev():

    區別於read()和write()函式,這兩個函式可以實現資料的批量傳輸而達到更高的效率.其原型如下:

ssize_t (*readv)(struct file *filp,const struct iovec *iov,unsigned long count,loff_t *ppos);
ssize_t (*writev)(struct file *filp,const struct iovec *iov,unsigned long count,loff_t *opps);
    這裡的比較明著的引數是iov.其原型如下:
struct iovec
{
    void __user *iov_base;
    __kernel_size_t iov_len;
}
    iovec描述了一個數據塊,此資料塊的起始位置在iov_base,長度為iov_len.其中引數count表示要操作多少個這樣的iovec.