Linux設備驅動程序 之 read和write


read和write原型

read和write方法完成的任務是相似的,亦即,拷貝數據到應用程序空間,或者反過來從應用程序空間拷貝數據;因此,它們的原型很相似,如下:

1 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
2 
3 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

其中參數filp是文件指針,參數count是請求傳輸的數據長度,參數buff指向用戶空間的緩沖區,這個緩沖區或者保存將要寫入的數據,或者是一個存放新讀入數據的空緩沖區;offp指明了用戶在文件中進行存放操作的位置;

一般而言,調用read和write都應該更新*offp所指向的文件位置,以便反應新系統調用成功完成之后當前文件的位置;

 

返回值:

read-

n==count,說明所請求的字節數成功完成;

n>0 && n<count,說明只有部分數據傳輸成功,大部分情況下,程序會重新讀取數據;如果用fread函數讀取數據,則庫函數會不斷的調用系統調用,直至所有的數據傳輸完成;

n==0,到達了文件尾;

n<0,意味着發生了錯誤,該值指明了發生了什么錯誤;

 

write-

n==count,說明所請求數目的字節數成功完成;

n>0 && n<count,說明只有部分數據傳輸成功,程序很可能再次試圖寫入余下的數據;

n==0,意味着什么也沒寫入,這個結果不是錯誤,而且也沒理由返回一個錯誤碼,標准庫會重復調用write;

n<0,意味着發生了錯誤,該值指明了發生了什么錯誤;

 

內核不能直接引用用戶空間指針

因為read和write方法的buff參數是用戶空間指針,所以,內核代碼不能直接引用其中的內容,這種限制的原因如下:

1. 隨着驅動程序所運行的架構的不同或者內核配置的不同個,在內核模式中運行時,用戶空間的指針可能是無效的,該地址可能根本無法映射到內核空間,或者可能指向某些隨機數據;

2. 即使該指針在內核空間代表相同的東西,但是用戶空間的內存是分頁的,而在系統調被調用時,涉及到的內存可能根本就不在RAM中,對用戶空間內存的直接應用將導致頁錯誤,而這對內核嗲嗎來說是不允許發生的事情,其結果可能是oops,導致調用該系統調用的進程死亡;

3. 我們討論的指針可能由用戶程序提供,而改程序可能存在缺陷或者是個惡意程序,如果我們的驅動程序盲目的引用用戶提供的指針,則將導致系統出現打開的后門,從而允許用戶空間程序隨意的訪問或者覆蓋系統中的內存;為了驅動程序的安全性,永遠會不要直接引用用戶空間指針;

大多數read和write代碼要做的工作就是將用戶地址空間和內核地址空間進行整段的數據拷貝,這種能力是由下面的內核函數提供的,它們用於拷貝任意一段字節序列;

1 static __always_inline unsigned long __must_check
2 copy_from_user(void *to, const void __user *from, unsigned long n)
3 
4 static __always_inline unsigned long __must_check
5 copy_to_user(void __user *to, const void *from, unsigned long n)

雖然這些函數的行為很想通常的memcpy,但是當內核空間運行的代碼訪問用戶空間時要多加小心,被尋址的用戶空間頁面可能當前並且不再內存中,於是虛擬內存子系統將該進程轉入睡眠狀態,知道該頁面唄傳送至期望的位置;例如,當頁面必須從交換空間取回時,這樣的情況就會發生,對於驅動程序編寫人員來說,者帶來的結果是訪問用戶空間的任何函數都必須是可重入的,並且必須能和其他驅動程序函數並發執行,更特別的是,必須處於能夠合法休眠的狀態;

這兩個函數的作用並不限於在內核空間和用戶空間之間拷貝數據,它們還檢查用戶空間的指針是佛有效,如果無效,則不會進行拷貝;另一方面,如果在拷貝過程中遇到無效地址,則僅僅會賦值部分數據;在這兩種情況下,返回值是還需要拷貝的內存數量值;

如果並不需要檢查用戶空間指針,則建議調用__copy_to_user和__copy_from_user;在預先知道參數已經檢查過時,這兩個函數很有用,但是,如果並沒有真正的檢查傳遞給這些函數的用戶空間指針,則可能導致內核崩潰或者建立安全漏洞;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM