<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          LWN:Rust 另一些對(duì) kernel 有用的特性!

          共 5690字,需瀏覽 12分鐘

           ·

          2021-11-29 20:00

          關(guān)注了就能看到更多這么棒的文章哦~

          More Rust concepts for the kernel

          By Jonathan Corbet
          September 20, 2021
          Kangrejos
          DeepL assisted translation
          https://lwn.net/Articles/869428/

          Kangrejos(Rust for Linux)會(huì)議的第一天介紹了這個(gè)項(xiàng)目以及它所要實(shí)現(xiàn)的目標(biāo);第二天介紹了一些 Rust 的核心概念以及跟內(nèi)核開發(fā)有什么關(guān)系。第三天,也是最后一天的時(shí)候,Wedson Almeida Filho 深入探討了如何讓 Rust 在 Linux 內(nèi)核中用起來,他介紹了目前為止已經(jīng)學(xué)到的一些經(jīng)驗(yàn),并與一些內(nèi)核開發(fā)人員討論了下一步的工作。

          Almeida 首先指出,他不是 Rust 語(yǔ)言的開發(fā)者,也不覺得這種語(yǔ)言是完美的。但他確實(shí)相信,Rust 可以解決內(nèi)核中的一些問題。他是安卓平臺(tái)安全團(tuán)隊(duì)的工程師,一直在尋找改善該平臺(tái)的方法,特別是減少攻擊面(reduce attack surface)。他認(rèn)為 Rust 可以做到這一點(diǎn),并且它還有助于提高正確性,提供一個(gè)超出 C 語(yǔ)言能提供的 expressive type system(類型系統(tǒng))。

          Ownership

          他繼續(xù)介紹了 Rust 中的一個(gè)重要概念,那就是數(shù)據(jù)所有權(quán)(data ownership)。Rust 程序中的每個(gè)數(shù)值都僅有一個(gè)所有者。這個(gè)所有權(quán)會(huì)隨著程序的執(zhí)行而轉(zhuǎn)交給別人,但絕不會(huì)共享。當(dāng)一個(gè)對(duì)象的所有者不再存在時(shí),該對(duì)象就會(huì)被釋放掉(free)。所有權(quán)是具有獨(dú)占性的,但是當(dāng)然還是要有辦法可以將數(shù)據(jù)進(jìn)行搬移和轉(zhuǎn)交的。在 Rust 中,這是用引用(reference)來實(shí)現(xiàn)的。mutable reference (可變引用)允許其持有者來修改數(shù)據(jù),注意 mutable reference 是獨(dú)占的,不可以存在對(duì)該對(duì)象的其他引用。而 shared reference (共享引用)則是非排他性的(non-exclusive),并且是只讀的。

          但是上述規(guī)則有幾種例外情況。Almeida 簡(jiǎn)要提到了內(nèi)部可變性(interior mutability)的想法,但并沒有深入探討細(xì)節(jié)。Rust 也支持原始指針(raw pointer),但是只有在 unsafe 代碼中才支持。

          Rust 的所有權(quán)規(guī)則帶來的一個(gè)結(jié)果是,在用 safe Rust 編寫的代碼中不會(huì)出現(xiàn) data race。因?yàn)橐a(chǎn)生 data race 的話,就必須要有至少兩個(gè) CPU 在以未同步好的方式(unsynchronized manner)訪問共享數(shù)據(jù),并且至少有一個(gè)在進(jìn)行寫入。由于 mutable reference 是獨(dú)占式的,使得這種情況根本不可能出現(xiàn)。

          這些規(guī)則也使得編譯器可以對(duì)那些編譯器無法直接看到的代碼進(jìn)行優(yōu)化。例如下面這樣的代碼:

          *x = 32
          some_function()
          return *x

          編譯器可以完全放心地只返回 32。變量 x 不會(huì)有別名,所以 some_function()不可能會(huì)對(duì)它的值進(jìn)行改動(dòng)。

          那么,這個(gè)所有權(quán)規(guī)則在內(nèi)核代碼中該如何使用呢?Almeida 提出了一個(gè)例子,就是在許多內(nèi)核結(jié)構(gòu)中都有的 private_data 字段。這個(gè)字段一般是由子系統(tǒng)來將自己的特有數(shù)據(jù)填入到由系統(tǒng)中更高一層代碼所管理的結(jié)構(gòu)中。一般情況此字段是一個(gè) void * 指針,當(dāng)其被真正使用起來時(shí)會(huì)被轉(zhuǎn)換為相應(yīng)的類型。根據(jù) Rust 標(biāo)準(zhǔn),這不是安全的用法(not safe usage)。下面以 struct file (在內(nèi)核中用其來表示一個(gè)打開的文件)為例來解釋。

          在 Rust 代碼中,開發(fā)者會(huì)寫一個(gè) open() 函數(shù),該函數(shù)會(huì)創(chuàng)建某種內(nèi)部狀態(tài),通常會(huì)通過 private_data 來存放這些數(shù)據(jù)。這些內(nèi)部狀態(tài)信息將被返回給調(diào)用者,并且這個(gè)狀態(tài)對(duì)象的所有權(quán)也被返回回去。如果用戶空間在打開的文件上調(diào)用 ioctl(),那么 ioctl 處理程序?qū)⒌玫揭粋€(gè)對(duì)此狀態(tài)對(duì)象的共享引用(shared reference)。這個(gè)引用必須是共享的,因?yàn)檫@些調(diào)用可能是并發(fā)出現(xiàn)的。相反,當(dāng)文件被關(guān)閉時(shí),release() 函數(shù)就可以獲得這個(gè)狀態(tài)數(shù)據(jù)的所有權(quán),然后就可以釋放掉。所有這些都可以使用 Rust 的 type 規(guī)則來提供類型安全以及并發(fā)安全(type and concurrency safety)。

          Device IDs, locks, and more

          另一個(gè)例子是整個(gè)驅(qū)動(dòng)程序子系統(tǒng)中的 device-ID table。這些表中每個(gè)數(shù)組元素都包含了一個(gè) ID 以及一個(gè)無類型的可選參數(shù),并且必須是用 null-terminated。Almeida 用 Rust 編寫了一個(gè) PL061(GPIO)驅(qū)動(dòng),來實(shí)現(xiàn)了內(nèi)核中的相應(yīng) C 驅(qū)動(dòng)的功能,并創(chuàng)建了一個(gè)新的 device-ID table 抽象來配合使用。開發(fā)者必須要確定這里可選參數(shù)的類型,并且提供來的所有數(shù)據(jù)都必須是這個(gè)類型的。也沒有必要再將 list 用 null-terminate 了,這就消除了驅(qū)動(dòng)程序作者經(jīng)常犯的一個(gè)錯(cuò)誤。因此,整個(gè)機(jī)制就是類型安全的(type-safe),并且也更容易使用。

          鎖(locking)是內(nèi)核中很多復(fù)雜問題和混亂的來源之一。在 C 語(yǔ)言代碼中,鎖通常被聲明為某個(gè)結(jié)構(gòu)中的一個(gè)字段,而且往往不清楚某個(gè)特定的鎖到底是在保護(hù)什么數(shù)據(jù)。而在 Rust 中,數(shù)據(jù)是直接跟保護(hù)它的鎖關(guān)聯(lián)起來的,這樣一來,如果不先獲得鎖就沒法編寫訪問該數(shù)據(jù)的代碼。至少得滿足這個(gè)條件之后編譯器才會(huì)幫開發(fā)者完成編譯。所有的檢查工作都可以在編譯時(shí)完成。

          Almeida 簡(jiǎn)要地提到了代號(hào) CVE-2021-26708 的漏洞,這是在 mainline 內(nèi)核中一個(gè)可以被惡意攻擊利用的 race condition,就是在獲得保護(hù)數(shù)據(jù)的鎖之前訪問數(shù)據(jù)而造成的問題。他認(rèn)為 Rust 就可以防止這個(gè)漏洞的發(fā)生。鎖在定義的時(shí)候就會(huì)確保在沒有獲得該鎖的情況下不能觸及相關(guān)數(shù)據(jù)。但是,如果開發(fā)者沒有意識(shí)到首先需要一個(gè)鎖,會(huì)發(fā)生什么?在這種情況下,Rust 的所有權(quán)規(guī)則會(huì)起到效果,因?yàn)樵噲D修改未受保護(hù)的數(shù)據(jù)會(huì)因?yàn)槭褂昧隋e(cuò)誤的引用類型而失敗。

          Laurent Pinchart 跳出來說,他喜歡這種把數(shù)據(jù)和保護(hù)它的鎖捆綁在一起的想法。但他比較擔(dān)心開發(fā)者明知道不需要鎖的那些情況,比如初始化部分的代碼就屬于這樣的情況。看起來如果編譯器知道對(duì)有關(guān)對(duì)象只能有一個(gè)引用,那么鎖就沒有必要了,例如,當(dāng)對(duì)象剛剛被創(chuàng)建時(shí)就會(huì)是這種情況。Almeida 說,如果所有其他辦法都沒法用的話,開發(fā)者總是可以使用 "unsafe escape hatch" (意思是寫 unsafe 代碼來繞過編譯器的限制)。

          另一個(gè)需要注意的抽象概念是文件描述符(file descriptors),這些描述符在創(chuàng)建時(shí)首先需要獲得對(duì)底層相應(yīng)的文件結(jié)構(gòu)的引用,然后才能分配描述符編號(hào)。如果分配失敗的話,代碼必須要記著放棄(drop)對(duì)文件的引用。Rust 的生命周期管理功能可以讓錯(cuò)誤處理自動(dòng)就完成,減少了很多八股文一樣的代碼。內(nèi)核代碼中經(jīng)常出現(xiàn)的那種 "goto out; " 的寫法在 Rust 中是沒有必要的。

          Almeida 指出 CVE-2019-15971 就是由于未能增加文件的引用計(jì)數(shù)而產(chǎn)生的 use-after-free 漏洞。在 Rust 中如果犯了這種錯(cuò)誤的話,一定會(huì)收到編譯器的友好提示信息的。

          繼續(xù)談?wù)摰藉e(cuò)誤路徑(error path),Almeida 重復(fù)強(qiáng)調(diào)說,他認(rèn)為在內(nèi)核代碼中看到的大多數(shù)復(fù)雜和容易出錯(cuò)的錯(cuò)誤處理,在使用 Rust 時(shí)都可以消失了。在大多數(shù)情況下,對(duì)象會(huì)在超出 scope (生效范圍)的時(shí)候就會(huì)直接被清理掉,根本不需要顯式去進(jìn)行處理。對(duì)于開發(fā)者需要更多的控制權(quán)的那些情況,可以使用 scopeguard 對(duì)象。這個(gè)對(duì)象在初始化時(shí)會(huì)使用相應(yīng)的 error-handling 信息,如果一切順利的話,不需要調(diào)用這些 error-handling 代碼,那么它的 dismiss() 方法會(huì)被調(diào)用到。否則,如果該對(duì)象超出了生效范圍之后的時(shí)候會(huì)直接執(zhí)行相應(yīng)的 error handling 錯(cuò)誤處理。

          此外會(huì)議上還討論了其他一些內(nèi)核抽象概念,包括 task 結(jié)構(gòu)、紅黑樹,以及對(duì) memory-mapped I/O 區(qū)域的訪問。不過,Almeida 想講的觀點(diǎn)在此時(shí)應(yīng)該已經(jīng)很清楚了。Rust 語(yǔ)言能夠處理內(nèi)核層面的編程工作,這比用 C 語(yǔ)言完成同樣的任務(wù)要安全得多。

          Discussion

          Julia Lawall 首先詢問了在 Rust 中有哪些缺點(diǎn)?有什么突出的缺點(diǎn)?Almeida 回答說,在 Rust 中,所有的對(duì)象在內(nèi)存中都是可移動(dòng)的(movable),這對(duì)那些會(huì)自己引用自己(self-referential)的數(shù)據(jù)結(jié)構(gòu)來說可能是個(gè)問題。解決辦法是釘住(pinning),但這就需要編寫 unsafe 的代碼了。他說,現(xiàn)有的 Rust 驅(qū)動(dòng)中的很多 unsafe 代碼都源于這個(gè)問題。另一個(gè)問題是 Rust 要求所有數(shù)據(jù)都要被初始化,這對(duì) mutex 來說尤其是一個(gè)問題。要解決這個(gè)問題的話主要是要找到并使用正確的抽象概念。

          Pinchart 對(duì) Rust 開發(fā)者所采取的漸進(jìn)式方法提出質(zhì)疑,這個(gè)問題在討論中也多次出現(xiàn)。他說,正確的做法是把內(nèi)核子系統(tǒng)的維護(hù)者關(guān)在一個(gè)房間里,要求他們學(xué)習(xí) Rust,并在過渡期間為這些維護(hù)者提供大量的幫助。如果維護(hù)者被一個(gè)與 Rust 有關(guān)的問題所阻礙了,那么他們應(yīng)該能夠立即得到幫助來解決這個(gè)問題。否則的話,Rust 開發(fā)者將遇到大量的反抗。

          Ojeda 質(zhì)疑是不是真的會(huì)碰到反抗。他說,沒有人要?jiǎng)儕Z使用 C 語(yǔ)言來編寫驅(qū)動(dòng)程序的權(quán)利。Pinchart 回答說,在未來某個(gè)時(shí)刻,維護(hù)者可能不接受這些驅(qū)動(dòng)程序。Ojeda 說,這可能是五年或十年后的事情了,不會(huì)那么快。他認(rèn)為有必要期望內(nèi)核開發(fā)者們來學(xué)習(xí)一些 Rust 知識(shí)。safe 模式下的工作并不困難。他承認(rèn) unsafe 的 Rust 模式確實(shí)比較難,畢竟又會(huì)出現(xiàn)那些對(duì)未定義行為的擔(dān)憂了,而且文檔也沒有那么好。

          Pinchart 又提出了另一個(gè)有很多人提到的擔(dān)心,那就是內(nèi)核開發(fā)者必須要能夠使用整個(gè)源碼 tree 來進(jìn)行工作,很少有開發(fā)者是從來不去查看自己子系統(tǒng)之外的代碼的。這樣一來,我們很難在早期就將 Rust 在內(nèi)核中的影響降到最低,畢竟會(huì)有無數(shù)開發(fā)者可能會(huì)讀到 Rust 部分的代碼。Ojeda 認(rèn)為現(xiàn)有計(jì)劃是只在已經(jīng)了解了 Rust 的維護(hù)者相應(yīng)的子系統(tǒng)中引入 Rust,但 Pinchart 回答說,不應(yīng)該指望其他開發(fā)者就不會(huì)受到這些 Rust 代碼的影響了。開發(fā)人員幾乎肯定也是要用 unsafe Rust 來工作的。Mark Brown 補(bǔ)充說,關(guān)于 Rust 的引入,可能會(huì)有某個(gè)標(biāo)志性的一天,在那一天之后所有維護(hù)者們將不得不在某種程度上了解這種語(yǔ)言。

          Almeida 問道,在這種過渡開始之前,需要有多少比例的內(nèi)核開發(fā)人員要懂得 Rust?Jonathan Cameron 回答說:"a lot"。我從引進(jìn) ReStructured Text 語(yǔ)言文檔支持的過程中得到了一些經(jīng)驗(yàn),那就是這個(gè)過程要比預(yù)期的要長(zhǎng),這個(gè)過程中遇到了一些激烈的(和持續(xù)的)阻力,并且現(xiàn)在仍然沒有全部完成。如果沒有被分開發(fā)社區(qū)中相當(dāng)多的人所接受的話,它就不可能會(huì)達(dá)到今天的這種成功。Rust 的引入要比這個(gè)復(fù)雜得多,因此它被接受的時(shí)間只會(huì)更長(zhǎng)。因此是必須要努力讓大家廣泛能夠接受的。Pinchart 說,現(xiàn)在大多數(shù)開發(fā)者似乎都對(duì) Rust 的價(jià)值感興趣,但其中許多人在擔(dān)心將其引入內(nèi)核帶來的成本是不是過高。

          Ojeda 說,Linux 的 Rust 開發(fā)者需要能說服足夠多的開發(fā)者來相信 Rust 的價(jià)值,這樣 Linus Torvalds 就會(huì)給這個(gè)改動(dòng)給予祝福,否則就可以干脆結(jié)束這些討論了。他期待著即將舉行的 Linux Plumbers Conference 和 Kernel Summit 的討論,能夠幫助把更多的開發(fā)者帶入這個(gè)過程。我對(duì)他過于依賴 Torvalds 祝福的想法表示了一些擔(dān)憂,因?yàn)檫@是一個(gè)必要條件,但遠(yuǎn)遠(yuǎn)不是充分條件。

          Greg Kroah-Hartman 說,他喜歡將 Rust 引入內(nèi)核開發(fā)的想法,但也認(rèn)為這項(xiàng)工作還有很長(zhǎng)的路要走。設(shè)備驅(qū)動(dòng)(也就是 Rust 開發(fā)者初期的目標(biāo)領(lǐng)域)必須要與內(nèi)核的許多部分互動(dòng),包括 driver model、sysfs 和其他各種子系統(tǒng),而能夠?qū)崿F(xiàn)這種交互的 Rust 功能還沒有出現(xiàn)。圍繞著 Rust 的引入,會(huì)有社會(huì)、政治和技術(shù)問題,而目前甚至連技術(shù)問題本身都還沒有處理好。盡管如此,他還是贊揚(yáng)了 Rust 開發(fā)者到目前為止所取得的進(jìn)展。

          會(huì)議時(shí)間快要不夠了,Kroah-Hartman 說,至少在五年內(nèi)不可能要求開發(fā)者用 Rust 編寫。Pinchart 問道,是否有人想過,社區(qū)愿意在這次轉(zhuǎn)型中失去多少開發(fā)者,實(shí)際肯定會(huì)有一些開發(fā)者因此離去的。Ojeda 最后說,讓 Rust 進(jìn)入內(nèi)核的過程是對(duì)這一點(diǎn)來說最重要的一個(gè)因素,他的下一步將是在 Linux Plumbers 大會(huì)上進(jìn)行討論。

          全文完
          LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。

          歡迎分享、轉(zhuǎn)載及基于現(xiàn)有協(xié)議再創(chuàng)作~

          長(zhǎng)按下面二維碼關(guān)注,關(guān)注 LWN 深度文章以及開源社區(qū)的各種新近言論~



          瀏覽 60
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲AV中文 | 亚洲www在线观看 | 亚洲欧美一级视频 | 久久久精品一区二区三区 | 欧美日在线 |