W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
讀和寫方法都進行類似的任務(wù), 就是, 從和到應(yīng)用程序代碼拷貝數(shù)據(jù). 因此, 它們的原型相當(dāng)相似, 可以同時介紹它們:
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);
對于 2 個方法, filp 是文件指針, count 是請求的傳輸數(shù)據(jù)大小. buff 參數(shù)指向持有被寫入數(shù)據(jù)的緩存, 或者放入新數(shù)據(jù)的空緩存. 最后, offp 是一個指針指向一個"long offset type"對象, 它指出用戶正在存取的文件位置. 返回值是一個"signed size type"; 它的使用在后面討論.
讓我們重復(fù)一下, read 和 write 方法的 buff 參數(shù)是用戶空間指針. 因此, 它不能被內(nèi)核代碼直接解引用. 這個限制有幾個理由:
依賴于你的驅(qū)動運行的體系, 以及內(nèi)核被如何配置的, 用戶空間指針當(dāng)運行于內(nèi)核模式可能根本是無效的. 可能沒有那個地址的映射, 或者它可能指向一些其他的隨機數(shù)據(jù).
就算這個指針在內(nèi)核空間是同樣的東西, 用戶空間內(nèi)存是分頁的, 在做系統(tǒng)調(diào)用時這個內(nèi)存可能沒有在 RAM 中. 試圖直接引用用戶空間內(nèi)存可能產(chǎn)生一個頁面錯, 這是內(nèi)核代碼不允許做的事情. 結(jié)果可能是一個"oops", 導(dǎo)致進行系統(tǒng)調(diào)用的進程死亡.
置疑中的指針由一個用戶程序提供, 它可能是錯誤的或者惡意的. 如果你的驅(qū)動盲目地解引用一個用戶提供的指針, 它提供了一個打開的門路使用戶空間程序存取或覆蓋系統(tǒng)任何地方的內(nèi)存. 如果你不想負(fù)責(zé)你的用戶的系統(tǒng)的安全危險, 你就不能直接解引用用戶空間指針.
顯然, 你的驅(qū)動必須能夠存取用戶空間緩存以完成它的工作. 但是, 為安全起見這個存取必須使用特殊的, 內(nèi)核提供的函數(shù). 我們介紹幾個這樣的函數(shù)(定義于 <asm/uaccess.h>), 剩下的在第一章"使用 ioctl 參數(shù)"一節(jié)中. 它們使用一些特殊的, 依賴體系的技巧來確保內(nèi)核和用戶空間的數(shù)據(jù)傳輸安全和正確.
scull 中的讀寫代碼需要拷貝一整段數(shù)據(jù)到或者從用戶地址空間. 這個能力由下列內(nèi)核函數(shù)提供, 它們拷貝一個任意的字節(jié)數(shù)組, 并且位于大部分讀寫實現(xiàn)的核心中.
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);
盡管這些函數(shù)表現(xiàn)象正常的 memcpy 函數(shù), 必須加一點小心在從內(nèi)核代碼中存取用戶空間. 尋址的用戶也當(dāng)前可能不在內(nèi)存, 虛擬內(nèi)存子系統(tǒng)會使進程睡眠在這個頁被傳送到位時. 例如, 這發(fā)生在必須從交換空間獲取頁的時候. 對于驅(qū)動編寫者來說, 最終結(jié)果是任何存取用戶空間的函數(shù)必須是可重入的, 必須能夠和其他驅(qū)動函數(shù)并行執(zhí)行, 并且, 特別的, 必須在一個它能夠合法地睡眠的位置. 我們在第 5 章再回到這個主題.
這 2 個函數(shù)的角色不限于拷貝數(shù)據(jù)到和從用戶空間: 它們還檢查用戶空間指針是否有效. 如果指針無效, 不進行拷貝; 如果在拷貝中遇到一個無效地址, 另一方面, 只拷貝部分?jǐn)?shù)據(jù). 在 2 種情況下, 返回值是還要拷貝的數(shù)據(jù)量. scull 代碼查看這個錯誤返回, 并且如果它不是 0 就返回 -EFAULT 給用戶.
用戶空間存取和無效用戶空間指針的主題有些高級, 在第 6 章討論. 然而, 值得注意的是如果你不需要檢查用戶空間指針, 你可以調(diào)用 copy_to_user 和 copy_from_user 來代替. 這是有用處的, 例如, 如果你知道你已經(jīng)檢查了這些參數(shù). 但是, 要小心; 事實上, 如果你不檢查你傳遞給這些函數(shù)的用戶空間指針, 那么你可能造成內(nèi)核崩潰和/或安全漏洞.
至于實際的設(shè)備方法, read 方法的任務(wù)是從設(shè)備拷貝數(shù)據(jù)到用戶空間(使用 copy_to_user), 而 write 方法必須從用戶空間拷貝數(shù)據(jù)到設(shè)備(使用 copy_from_user). 每個 read 或 write 系統(tǒng)調(diào)用請求一個特定數(shù)目字節(jié)的傳送, 但是驅(qū)動可自由傳送較少數(shù)據(jù) -- 對讀和寫這確切的規(guī)則稍微不同, 在本章后面描述.
不管這些方法傳送多少數(shù)據(jù), 它們通常應(yīng)當(dāng)更新 *offp 中的文件位置來表示在系統(tǒng)調(diào)用成功完成后當(dāng)前的文件位置. 內(nèi)核接著在適當(dāng)時候傳播文件位置的改變到文件結(jié)構(gòu). pread 和 pwrite 系統(tǒng)調(diào)用有不同的語義; 它們從一個給定的文件偏移操作, 并且不改變其他的系統(tǒng)調(diào)用看到的文件位置. 這些調(diào)用傳遞一個指向用戶提供的位置的指針, 并且放棄你的驅(qū)動所做的改變.
圖給 read 的參數(shù)表示了一個典型讀實現(xiàn)是如何使用它的參數(shù).
圖?3.2.?給 read 的參數(shù)
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: