Re: [PATCH 00/13] [RFC] Rust support
On Tue, Apr 20, 2021 at 07:56:18AM +0200, Greg Kroah-Hartman wrote: > I would LOVE it if some "executives" would see the above presentations, > because then they would maybe actually fund developers to fix bugs and > maintain the kernel code, instead of only allowing them to add new > features. > > Seriously, that's the real problem, that Dmitry's work has exposed, the > lack of people allowed to do this type of bugfixing and maintenance on > company time, for something that the company relies on, is a huge issue. > "executives" feel that they are willing to fund the initial work and > then "throw it over the wall to the community" once it is merged, and > then they can forget about it as "the community" will maintain it for > them for free. And that's a lie, as Dmitry's work shows. That's sadly the eternal situation, and I'm suspecting that software development and maintenance is not identified as a requirement for a large number of hardware vendors, especially on the consumer side where margins are lower. A contractor is paid to develop a driver, *sometimes* to try to mainline it (and the later they engage with the community, the longer it takes in round trips), and once the code finally gets merged, all the initial budget is depleted and no more software work will be done. Worse, we could imagine kicking unmaintained drivers faster off the tree, but that would actually help these unscrupulous vendors by forcing their customers to switch to the new model :-/ And most of them wouldn't care either if their contributions were refused based on their track record of not maintaining their code, since they often see this as a convenience to please their customers and not something they need (after all, relying on a bogus and vulnerable BSP has never prevented from selling a device, quite the opposite). In short, there is a parallel universe where running highly bogus and vulnerable out-of-tree code seems like the norm and where there is no sort of care for what is mainlined as it's possibly just made to look "cool". We also need to recognize that it's expectable that some vendors are not willing to engage on supporting a driver for a decade if they expect their device to last 5 years only, and maybe we should make some rules clear about mainlining drivers and what to expect for users (in which case the end of support would be clear and nobody would be surprised if the driver is removed at the end of its maintenance, barring a switch to a community maintainer). Just my two cents, Willy
Re: [PATCH 00/13] [RFC] Rust support
On Mon, Apr 19, 2021 at 05:24:33PM -0700, Nick Desaulniers wrote: > On Fri, Apr 16, 2021 at 10:39 AM Willy Tarreau wrote: > > > > resources usage, I'm really not convinced at all it's suited for > > low-level development. I understand the interest of the experiment > > to help the language evolve into that direction, but I fear that > > the kernel will soon be as bloated and insecure as a browser, and > > that's really not to please me. > > Dunno, I don't think the introduction of Rust made Firefox _more_ insecure. > https://wiki.mozilla.org/Oxidation#Within_Firefox > > I pray no executives ever see Dmitry Vyukov's 2019 Linux Plumbers Conf > talk "Reflections on kernel quality, development process and testing." > https://www.youtube.com/watch?v=iAfrrNdl2f4 > or his 2018 Linux Security Summit talk "Syzbot and the Tale of > Thousand Kernel Bugs" https://www.youtube.com/watch?v=qrBVXxZDVQY > (and they're just fuzzing the syscall interface and USB devices. > Imagine once folks can more easily craft malformed bluetooth and wifi > packets.) > > I'd imagine the first term that comes to mind for them might be > "liability." They are quite sensitive to these vulnerabilities with > silly names, logos, and websites. There are many of us that believe > an incremental approach of introducing a memory safe language to our > existing infrastructure at the very least to attempt to improve the > quality of drivers for those that choose to use such tools is a better > approach. I would LOVE it if some "executives" would see the above presentations, because then they would maybe actually fund developers to fix bugs and maintain the kernel code, instead of only allowing them to add new features. Seriously, that's the real problem, that Dmitry's work has exposed, the lack of people allowed to do this type of bugfixing and maintenance on company time, for something that the company relies on, is a huge issue. "executives" feel that they are willing to fund the initial work and then "throw it over the wall to the community" once it is merged, and then they can forget about it as "the community" will maintain it for them for free. And that's a lie, as Dmitry's work shows. The world creates new use cases and testing ability all the time, which exposes bugs that have been around in old code. Once the bugs are fixed in that layer of code, the next layer down can finally be tested and then look, more corner cases of issues. Rewriting the kernel in another language is not going to fix the majority of the issues that fuzzing finds here automagically, as that work has exposed us to things like fault-injection and malicious USB packets that no language would have saved us from "automatically". All of those code paths deal with "unsafe" data that doesn't magically become "safe" because we switch languages. And over time, what we have determined is "safe" has changed! People forget that only a few years ago have we decided that the kernel now has to protect userspace programs from malicious hardware. That's a major shift in thinking, now data that we used to blindly trust can not be trusted at all. And "executives" want us to fix all of those issues for free, when really it's a major design shift for loads of kernel subsystems to handle this new threat model. So yes, please spread that talk around. Maybe then will we actually get funding and support to FIX the bugs that those tools test. Right now, the primary fixer of those findings are _INTERNS_ as that's all companies are willing to fund to fix this type of thing. And don't get me started on the inability for "executives" to fund other parts of Linux that they rely on, because they want "other companies" to do it instead. The tragedy-of-the-commons is a real threat to Linux, and always has been... thanks, greg k-h
Re: [PATCH 00/13] [RFC] Rust support
Hi Nick, On Mon, Apr 19, 2021 at 05:24:33PM -0700, Nick Desaulniers wrote: > I don't think the introduction of Rust made Firefox _more_ insecure. > https://wiki.mozilla.org/Oxidation#Within_Firefox Browsers are human interfaces and do not fundamentally require low level access to memory/hardware/whatever. They can be written in about any language, only the resource usage and performance will make a difference. As such, some were even written in Java or JS for example. Operating systems, and particularly drivers *do* require low-level accesses, and stuff that can hardly be abstracted or understood by a compiler. You may have to perform two 16-bit reads/writes on a 32-bit MMIO address to perform an operation and the compiler does not have to know it, just to obey. > Really, a key point is that a lot of common mistakes in C are compile > time errors in Rust. I know no "true" kernel dev would make such > mistakes in C, Everyone makes mistakes, the level of attention varies over time and the focus often changes when dealing with build errors. How many time some of us facing a bug remembered having changed the code very late after a build error, and being less careful from this point when the goal changed from "let's do it right" to "let's get this to build" ? > but is there nothing we can do to help our peers > writing drivers? The point is to transfer cost from runtime to > compile time to avoid costs at runtime; like all of the memory safety > bugs which are costing our industry. And do we have stats on the number of logical bugs, some of which are caused by developers trying to work around compilers' stubbornness ? For me, personally speaking, they have *increased* over time, usually trying to avoid some annoying modern gcc warnings, resulting in integer casts being placed close to string formats, or returns being placed in switch/case to avoid the fall-through warning, etc. Thus I'm worried that a non-negligible part of the 70% of bugs caused by memory safety issues could be replaced with logic bugs to get to the point where the rust compiler finally accepts to compile the code. It makes me think about researchers trying to reduce the causes of certain deaths and claiming to "save lives" while in the end the people they "save" will simply die from something else. And I'm not particularly trying to blindly defend C here. I'm complaining every single day about some of its shortcomings like the vast amount of UB, stupid type promotion, counter-intuitive operators precedence when combining bit-ops with arithmetic, limited size of enums, lack of rotate operator, strict aliasing, or the recourse to asm() statements every 10 lines to do stuff that can hardly be expressed in a way understandable by a compiler. I'm just seeing that a lot of the griefs I'm having against C come from the compiler trying to be too smart or too stubborn, so giving even more of the handle to a compiler doesn't appeal me at all. In addition, we all know how painful it is to work around compiler bugs by writing complex code that carefully avoids certain constructs. I'm wondering if we'll still have that luxury with a stricter compiler, or if the only response will have to be between "let's disable this driver that does not compile" or "please force distros to upgrade their compilers". But we'll see :-/ Regards, Willy
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 10:39 AM Willy Tarreau wrote: > > resources usage, I'm really not convinced at all it's suited for > low-level development. I understand the interest of the experiment > to help the language evolve into that direction, but I fear that > the kernel will soon be as bloated and insecure as a browser, and > that's really not to please me. Dunno, I don't think the introduction of Rust made Firefox _more_ insecure. https://wiki.mozilla.org/Oxidation#Within_Firefox I pray no executives ever see Dmitry Vyukov's 2019 Linux Plumbers Conf talk "Reflections on kernel quality, development process and testing." https://www.youtube.com/watch?v=iAfrrNdl2f4 or his 2018 Linux Security Summit talk "Syzbot and the Tale of Thousand Kernel Bugs" https://www.youtube.com/watch?v=qrBVXxZDVQY (and they're just fuzzing the syscall interface and USB devices. Imagine once folks can more easily craft malformed bluetooth and wifi packets.) I'd imagine the first term that comes to mind for them might be "liability." They are quite sensitive to these vulnerabilities with silly names, logos, and websites. There are many of us that believe an incremental approach of introducing a memory safe language to our existing infrastructure at the very least to attempt to improve the quality of drivers for those that choose to use such tools is a better approach. I think a lot of the current discussion picking nits in syntax, format of docs, ease of installation, or theoretical memory models for which no language (not even the one the kernel is implemented in) provides all rightly should still be added to a revised RFC under "Why not [Rust]?" but perhaps are severely overlooking the benefits. A tradeoff for sure though. Really, a key point is that a lot of common mistakes in C are compile time errors in Rust. I know no "true" kernel dev would make such mistakes in C, but is there nothing we can do to help our peers writing drivers? The point is to transfer cost from runtime to compile time to avoid costs at runtime; like all of the memory safety bugs which are costing our industry. Curiously recurring statistics: https://www.zdnet.com/article/microsoft-70-percent-of-all-security-bugs-are-memory-safety-issues/ "Microsoft security engineer Matt Miller said that over the last 12 years, around 70 percent of all Microsoft patches were fixes for memory safety bugs." https://www.chromium.org/Home/chromium-security/memory-safety "The Chromium project finds that around 70% of our serious security bugs are memory safety problems." https://security.googleblog.com/2021/01/data-driven-security-hardening-in.html (59% of Critical and High severity vulnerabilities fixed in Android Security Bulletins in 2019 are classified as "Memory," FWIW) https://hacks.mozilla.org/2019/02/rewriting-a-browser-component-in-rust/ "If we’d had a time machine and could have written this component in Rust from the start, 51 (73.9%) of these bugs would not have been possible." -- Thanks, ~Nick Desaulniers
Re: [PATCH 00/13] [RFC] Rust support
Hi Nick, On Mon, Apr 19, 2021 at 10:36 PM Nick Desaulniers wrote: > > This is a much different process than drafts thrown over the wall. > What hope do any kernel contributors have to participate in the ISO > WGs, other than hoping their contributions to a draft foresee/address > any concerns members of the committee might have? How do members of > the ISO WG communicate with folks interested in the outcomes of their > decisions? For WG21, several folks write trip reports of each meeting, and you can check the status of papers in GitHub at https://github.com/cplusplus/papers/issues. For WG14, there are way less papers going on. It is more or less easy to follow by reading the list of latest additions in the first pages of the draft, as well as the Editor's Report. > The two processes are quite different; one doesn't require "joining a > national body" (which I assume involves some monetary transaction, if > not for the individual participant, for their employer) for instance. > (http://www.open-std.org/jtc1/sc22/wg14/www/contributing which links > to https://www.iso.org/members.html; I wonder if we have kernel > contributors in those grayed out countries?) They are indeed very different processes. Being an ISO standard has advantages and disadvantages. In any case, I should note that not everyone that goes to the meetings pays, e.g. some go as guests, some are funded by their country (or the EU or other organizations), etc. In fact, the bigger costs, in my experience, are the time commitment (a week several times a year) and the costs of traveling (before the pandemic, that is). Furthermore, contributing proposals does not actually require attending the meetings nor joining the committee -- some people contribute to the standards via proxy, i.e. somebody else presents their proposals in the committee. > It was always very ironic to me that the most important body of free > software was subject to decisions made by ISO, for better or for > worse. I would think Rust's RFC process would be more accessible to > kernel developers, modulo the anti-github crowd, but with the Rust's > community's values in inclusion I'm sure they'd be happy to accomodate > folks for the RFC process without requiring github. I'm not sure ISO > can be as flexible for non-members. Well, the kernel already ignores the C standard here and there. ;-) In the end, it is "just" a standard -- the kernel and compilers can do something else when they need. > Either way, I think Rust's RFC process is something worth adding to > the list of benefits under the heading "Why Rust?" in this proposed > RFC. The Rust RFC process has indeed upsides. It is very dynamic and easy to participate, and allows for anybody to easily comment on proposals, even anonymously. But, for better or worse, does not lead to an ISO standard (which some people & companies really value, e.g. as requirements in contracts etc.). In the end, writing an RFC is similar to writing a paper for ISO. The bigger differences, as mentioned above, are on the requirements if you actually want to go there and present the paper yourself and/or if you want to have voting rights etc. Personally, I think some ISO policies could be improved for some types of standards (or at least let WGs relax them to some degree), but... Cheers, Miguel
Re: [PATCH 00/13] [RFC] Rust support
On Mon, Apr 19, 2021 at 01:35:56PM -0700, Nick Desaulniers wrote: > On Fri, Apr 16, 2021 at 11:47 AM Paul E. McKenney wrote: > > > > On Thu, Apr 15, 2021 at 11:04:37PM -0700, Nick Desaulniers wrote: > > > On Thu, Apr 15, 2021 at 9:27 PM Boqun Feng wrote: > > > > > > > > But I think the Rust Community still wants to have a good memory model, > > > > and they are open to any kind of suggestion and input. I think we (LKMM > > > > people) should really get involved, because the recent discussion on > > > > RISC-V's atomics shows that if we didn't people might get a "broken" > > > > design because they thought C11 memory model is good enough: > > > > > > > > https://lore.kernel.org/lkml/YGyZPCxJYGOvqYZQ@boqun-archlinux/ > > > > > > > > And the benefits are mutual: a) Linux Kernel Memory Model (LKMM) is > > > > defined by combining the requirements of developers and the behavior of > > > > hardwares, it's pratical and can be a very good input for memory model > > > > designing in Rust; b) Once Rust has a better memory model, the compiler > > > > technologies whatever Rust compilers use to suppor the memory model can > > > > be adopted to C compilers and we can get that part for free. > > > > > > Yes, I agree; I think that's a very good approach. Avoiding the ISO > > > WG14 is interesting; at least the merits could be debated in the > > > public and not behind closed doors. > > > > WG14 (C) and WG21 (C++) are at least somewhat open. Here are some of > > the proposals a few of us have in flight: > > Wow, the working groups have been busy. Thank you Paul and Boqun (and > anyone else on thread) for authoring many of the proposals listed > below. Looks like I have a lot of reading to do to catch up. And this is only the proposals relating to low-level concurrency. There are way more proposals relating to vector processing, GPGPUs, task-based concurrency, and so on. Here is the list of papers submitted thus far this year: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/ > Have any of those been accepted yet, or led to amendments to either > language's specs? Where's the best place to track that? None of them have yet to be accepted. P1121R2 has been recommended for Concurrency Technical Specification 2, which is a stepping stone to the International Standard. I hope that P1122R2 will follow soon. > My point has more to do with _participation_. Rust's RFC process is > well documented (https://rust-lang.github.io/rfcs/introduction.html) > and is done via github pull requests[0]. > > This is a much different process than drafts thrown over the wall. > What hope do any kernel contributors have to participate in the ISO > WGs, other than hoping their contributions to a draft foresee/address > any concerns members of the committee might have? How do members of > the ISO WG communicate with folks interested in the outcomes of their > decisions? I participate in ISO SC22 WG21 (C++) and to a lesser extent WG14 (C). Participation is key. The various US National Laboratories send quite a few people, which has a lot to do with these two standards accommodating their wishes. > The two processes are quite different; one doesn't require "joining a > national body" (which I assume involves some monetary transaction, if > not for the individual participant, for their employer) for instance. > (http://www.open-std.org/jtc1/sc22/wg14/www/contributing which links > to https://www.iso.org/members.html; I wonder if we have kernel > contributors in those grayed out countries?) Your employer is already a member of WG21 (C++), so there is no ISO obstacle to participation by you or by your colleagues. If you contact me offlist, I would be happy to connect you to your employer's WG21 representative. > It was always very ironic to me that the most important body of free > software was subject to decisions made by ISO, for better or for > worse. I would think Rust's RFC process would be more accessible to > kernel developers, modulo the anti-github crowd, but with the Rust's > community's values in inclusion I'm sure they'd be happy to accomodate > folks for the RFC process without requiring github. I'm not sure ISO > can be as flexible for non-members. Being a member is not all that necessary. Yes, at the end of the day, only national bodies can formally vote, but I have not come across a case of anyone being barred from discussions, paper submissions, or straw polls (informal votes used to set direction) due to not being a member. Given that the national bodies are only permitted to comment on and vote on finished proposals, you can argue that individuals have more influence. Similarly, it is not necessary to be personally acquainted with me in order to get patches into Linux-kernel RCU. > Either way, I think Rust's RFC process is something worth adding to > the list of benefits under the heading "Why Rust?" in this proposed > RFC. Comparing Rust's process to that of the C or C++ standard committe
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 11:47 AM Paul E. McKenney wrote: > > On Thu, Apr 15, 2021 at 11:04:37PM -0700, Nick Desaulniers wrote: > > On Thu, Apr 15, 2021 at 9:27 PM Boqun Feng wrote: > > > > > > But I think the Rust Community still wants to have a good memory model, > > > and they are open to any kind of suggestion and input. I think we (LKMM > > > people) should really get involved, because the recent discussion on > > > RISC-V's atomics shows that if we didn't people might get a "broken" > > > design because they thought C11 memory model is good enough: > > > > > > https://lore.kernel.org/lkml/YGyZPCxJYGOvqYZQ@boqun-archlinux/ > > > > > > And the benefits are mutual: a) Linux Kernel Memory Model (LKMM) is > > > defined by combining the requirements of developers and the behavior of > > > hardwares, it's pratical and can be a very good input for memory model > > > designing in Rust; b) Once Rust has a better memory model, the compiler > > > technologies whatever Rust compilers use to suppor the memory model can > > > be adopted to C compilers and we can get that part for free. > > > > Yes, I agree; I think that's a very good approach. Avoiding the ISO > > WG14 is interesting; at least the merits could be debated in the > > public and not behind closed doors. > > WG14 (C) and WG21 (C++) are at least somewhat open. Here are some of > the proposals a few of us have in flight: Wow, the working groups have been busy. Thank you Paul and Boqun (and anyone else on thread) for authoring many of the proposals listed below. Looks like I have a lot of reading to do to catch up. Have any of those been accepted yet, or led to amendments to either language's specs? Where's the best place to track that? My point has more to do with _participation_. Rust's RFC process is well documented (https://rust-lang.github.io/rfcs/introduction.html) and is done via github pull requests[0]. This is a much different process than drafts thrown over the wall. What hope do any kernel contributors have to participate in the ISO WGs, other than hoping their contributions to a draft foresee/address any concerns members of the committee might have? How do members of the ISO WG communicate with folks interested in the outcomes of their decisions? The two processes are quite different; one doesn't require "joining a national body" (which I assume involves some monetary transaction, if not for the individual participant, for their employer) for instance. (http://www.open-std.org/jtc1/sc22/wg14/www/contributing which links to https://www.iso.org/members.html; I wonder if we have kernel contributors in those grayed out countries?) It was always very ironic to me that the most important body of free software was subject to decisions made by ISO, for better or for worse. I would think Rust's RFC process would be more accessible to kernel developers, modulo the anti-github crowd, but with the Rust's community's values in inclusion I'm sure they'd be happy to accomodate folks for the RFC process without requiring github. I'm not sure ISO can be as flexible for non-members. Either way, I think Rust's RFC process is something worth adding to the list of benefits under the heading "Why Rust?" in this proposed RFC. > > P2055R0 A Relaxed Guide to memory_order_relaxed > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2055r0.pdf > P0124R7 Linux-Kernel Memory Model (vs. that of C/C++) > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0124r7.html > P1726R4 Pointer lifetime-end zap > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1726r4.pdf > > https://docs.google.com/document/d/1MfagxTa6H0rTxtq9Oxyh4X53NzKqOt7y3hZBVzO_LMk/edit?usp=sharing > P1121R2 Hazard Pointers: Proposed Interface and Wording for Concurrency TS 2 > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1121r2.pdf > P1382R1 volatile_load and volatile_store > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1382r1.pdf > P1122R2 Proposed Wording for Concurrent Data Structures: Read-Copy-Update > (RCU) > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1122r2.pdf > > https://docs.google.com/document/d/1MfagxTa6H0rTxtq9Oxyh4X53NzKqOt7y3hZBVzO_LMk/edit?usp=sharing > P0190R4 Proposal for New memory order consume Definition > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0190r4.pdf > P0750R1 Consume > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0750r1.html Does wg14 not participate in these discussions? (Or, is there a lot of overlap between participants in both?) http://93.90.116.65/JTC1/SC22/WG14/www/docs/ seems like a list of proposals and meeting minutes, but all of the above links look like WG21. The model of decisions being made for C++ then trickling down to C is definitely curious. Though perhaps for the topics of memory orderings there's enough overlap between the two languages for it not to matter. > > P1726R
Re: [PATCH 00/13] [RFC] Rust support
On Mon, Apr 19, 2021 at 11:38 AM Paolo Bonzini wrote: > > It changes it for the worse, in that access to fields that are shared > across threads *must* either use atomic types Well, we won't be using those broken types in the core kernel, so that would all be entirely on the Rust side. And I don't expect the Rust side to do a lot of non-locked accesses, which presumably shouldn't need any of this anyway. If Rust code ends up accessing actual real kernel data structures with memory ordering, then that will be to types that do *not* follow the useless C++ atomics, and that in turn presumably means that it will be done as "unsafe" helpers that do what the LKMM does (ie READ_ONCE() and all the rest of it). Linus
Re: [PATCH 00/13] [RFC] Rust support
On 19/04/21 19:14, Linus Torvalds wrote: On Mon, Apr 19, 2021 at 2:36 AM Peter Zijlstra wrote: I also don't see how this is better than seq_cst. But yes, not broken, but also very much not optimal. I continue to feel like kernel people should just entirely ignore the C++ memory ordering standard. It's inferior to what we already have, and simply not helpful. It doesn't actually solve any problems as far as the kernel is concerned, and it generates its own set of issues (ie assuming that the compiler supports it, and assuming the compiler gets it right). The really subtle cases that it could have been helpful for (eg RCU, or the load-store control dependencies) were _too_ subtle for the standard. And I do not believe Rust changes _any_ of that. It changes it for the worse, in that access to fields that are shared across threads *must* either use atomic types (which boil down to the same compiler intrinsics as the C/C++ memory model) or synchronization primitives. LKMM operates in the grey area between the C standard and what gcc/clang actually implement, but there's no such grey area in Rust unless somebody wants to rewrite arch/*/asm atomic access primitives and memory barriers in Rust. Of course it's possible to say Rust code just uses the C/C++/Rust model and C code follows the LKMM, but that really only delays the inevitable until a driver is written part in C part in Rust, and needs to perform accesses outside synchronization primitives. Paolo Any kernel Rust code will simply have to follow the LKMM rules, and use the kernel model for the interfaces. Things like the C++ memory model is simply not _relevant_ to the kernel.
Re: [PATCH 00/13] [RFC] Rust support
On Mon, Apr 19, 2021 at 2:36 AM Peter Zijlstra wrote: > > I also don't see how this is better than seq_cst. > > But yes, not broken, but also very much not optimal. I continue to feel like kernel people should just entirely ignore the C++ memory ordering standard. It's inferior to what we already have, and simply not helpful. It doesn't actually solve any problems as far as the kernel is concerned, and it generates its own set of issues (ie assuming that the compiler supports it, and assuming the compiler gets it right). The really subtle cases that it could have been helpful for (eg RCU, or the load-store control dependencies) were _too_ subtle for the standard. And I do not believe Rust changes _any_ of that. Any kernel Rust code will simply have to follow the LKMM rules, and use the kernel model for the interfaces. Things like the C++ memory model is simply not _relevant_ to the kernel. Linus
Re: [PATCH 00/13] [RFC] Rust support
On Mon, Apr 19, 2021 at 11:40:54AM +0200, Paolo Bonzini wrote: > On 19/04/21 11:36, Peter Zijlstra wrote: > > On Mon, Apr 19, 2021 at 11:02:12AM +0200, Paolo Bonzini wrote: > > > > void writer(void) > > > > { > > > > atomic_store_explicit(&seq, seq+1, memory_order_relaxed); > > > > atomic_thread_fence(memory_order_acquire); > > > > > > This needs to be memory_order_release. The only change in the resulting > > > assembly is that "dmb ishld" becomes "dmb ish", which is not as good as > > > the > > > "dmb ishst" you get from smp_wmb() but not buggy either. > > > > Yuck! And that is what requires the insides to be > > atomic_store_explicit(), otherwise this fence doesn't have to affect > > them. > > Not just that, even the write needs to be atomic_store_explicit in order to > avoid a data race.atomic_store_explicit https://wg21.link/P0690 was an attempt to address this, but I don't know if any of the ideas got adopted in the end. Will
Re: [PATCH 00/13] [RFC] Rust support
On 19/04/21 11:36, Peter Zijlstra wrote: On Mon, Apr 19, 2021 at 11:02:12AM +0200, Paolo Bonzini wrote: void writer(void) { atomic_store_explicit(&seq, seq+1, memory_order_relaxed); atomic_thread_fence(memory_order_acquire); This needs to be memory_order_release. The only change in the resulting assembly is that "dmb ishld" becomes "dmb ish", which is not as good as the "dmb ishst" you get from smp_wmb() but not buggy either. Yuck! And that is what requires the insides to be atomic_store_explicit(), otherwise this fence doesn't have to affect them. Not just that, even the write needs to be atomic_store_explicit in order to avoid a data race.atomic_store_explicit I also don't see how this is better than seq_cst. It is better than seq_cst on TSO architectures. Another possibility is to use release stores for everything (both increments and the stores between them). But yes, not broken, but also very much not optimal. Agreed on that, just like RCU/memory_order_consume. Paolo
Re: [PATCH 00/13] [RFC] Rust support
On Mon, Apr 19, 2021 at 11:02:12AM +0200, Paolo Bonzini wrote: > > void writer(void) > > { > > atomic_store_explicit(&seq, seq+1, memory_order_relaxed); > > atomic_thread_fence(memory_order_acquire); > > This needs to be memory_order_release. The only change in the resulting > assembly is that "dmb ishld" becomes "dmb ish", which is not as good as the > "dmb ishst" you get from smp_wmb() but not buggy either. Yuck! And that is what requires the insides to be atomic_store_explicit(), otherwise this fence doesn't have to affect them. I also don't see how this is better than seq_cst. But yes, not broken, but also very much not optimal.
Re: [PATCH 00/13] [RFC] Rust support
On 19/04/21 10:26, Peter Zijlstra wrote: On Mon, Apr 19, 2021 at 09:53:06AM +0200, Paolo Bonzini wrote: On 19/04/21 09:32, Peter Zijlstra wrote: On Sat, Apr 17, 2021 at 04:51:58PM +0200, Paolo Bonzini wrote: On 16/04/21 09:09, Peter Zijlstra wrote: Well, the obvious example would be seqlocks. C11 can't do them Sure it can. C11 requires annotating with (the equivalent of) READ_ONCE all reads of seqlock-protected fields, but the memory model supports seqlocks just fine. How does that help? IIRC there's two problems, one on each side the lock. On the write side we have: seq++; smp_wmb(); X = r; Y = r; smp_wmb(); seq++; Which C11 simply cannot do right because it does't have wmb. It has atomic_thread_fence(memory_order_release), and atomic_thread_fence(memory_order_acquire) on the read side. https://godbolt.org/z/85xoPxeE5 void writer(void) { atomic_store_explicit(&seq, seq+1, memory_order_relaxed); atomic_thread_fence(memory_order_acquire); This needs to be memory_order_release. The only change in the resulting assembly is that "dmb ishld" becomes "dmb ish", which is not as good as the "dmb ishst" you get from smp_wmb() but not buggy either. The read side can use "dmb ishld" so it gets the same code as Linux. LWN needs a "C11 memory model for kernel folks" article. In the meanwhile there is http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0124r4.html which is the opposite (Linux kernel memory model for C11 folks). Paolo X = 1; Y = 2; atomic_store_explicit(&seq, seq+1, memory_order_release); } gives: writer: adrpx1, .LANCHOR0 add x0, x1, :lo12:.LANCHOR0 ldr w2, [x1, #:lo12:.LANCHOR0] add w2, w2, 1 str w2, [x0] dmb ishld ldr w1, [x1, #:lo12:.LANCHOR0] mov w3, 1 mov w2, 2 stp w3, w2, [x0, 4] add w1, w1, w3 stlrw1, [x0] ret Which, afaict, is completely buggered. What it seems to be doing is turning the seq load into a load-acquire, but what we really need is to make sure the seq store (increment) is ordered before the other stores.
Re: [PATCH 00/13] [RFC] Rust support
On Mon, Apr 19, 2021 at 10:26:57AM +0200, Peter Zijlstra wrote: > https://godbolt.org/z/85xoPxeE5 That wants _Atomic on the seq definition for clang. > void writer(void) > { > atomic_store_explicit(&seq, seq+1, memory_order_relaxed); > atomic_thread_fence(memory_order_acquire); > > X = 1; > Y = 2; > > atomic_store_explicit(&seq, seq+1, memory_order_release); > } > > gives: > > writer: > adrpx1, .LANCHOR0 > add x0, x1, :lo12:.LANCHOR0 > ldr w2, [x1, #:lo12:.LANCHOR0] > add w2, w2, 1 > str w2, [x0] > dmb ishld > ldr w1, [x1, #:lo12:.LANCHOR0] > mov w3, 1 > mov w2, 2 > stp w3, w2, [x0, 4] > add w1, w1, w3 > stlrw1, [x0] > ret > > Which, afaict, is completely buggered. What it seems to be doing is > turning the seq load into a load-acquire, but what we really need is to > make sure the seq store (increment) is ordered before the other stores. Put differently, what you seem to want is store-acquire, but there ain't no such thing.
Re: [PATCH 00/13] [RFC] Rust support
On Mon, Apr 19, 2021 at 09:53:06AM +0200, Paolo Bonzini wrote: > On 19/04/21 09:32, Peter Zijlstra wrote: > > On Sat, Apr 17, 2021 at 04:51:58PM +0200, Paolo Bonzini wrote: > > > On 16/04/21 09:09, Peter Zijlstra wrote: > > > > Well, the obvious example would be seqlocks. C11 can't do them > > > > > > Sure it can. C11 requires annotating with (the equivalent of) READ_ONCE > > > all > > > reads of seqlock-protected fields, but the memory model supports seqlocks > > > just fine. > > > > How does that help? > > > > IIRC there's two problems, one on each side the lock. On the write side > > we have: > > > > seq++; > > smp_wmb(); > > X = r; > > Y = r; > > smp_wmb(); > > seq++; > > > > Which C11 simply cannot do right because it does't have wmb. > > It has atomic_thread_fence(memory_order_release), and > atomic_thread_fence(memory_order_acquire) on the read side. https://godbolt.org/z/85xoPxeE5 void writer(void) { atomic_store_explicit(&seq, seq+1, memory_order_relaxed); atomic_thread_fence(memory_order_acquire); X = 1; Y = 2; atomic_store_explicit(&seq, seq+1, memory_order_release); } gives: writer: adrpx1, .LANCHOR0 add x0, x1, :lo12:.LANCHOR0 ldr w2, [x1, #:lo12:.LANCHOR0] add w2, w2, 1 str w2, [x0] dmb ishld ldr w1, [x1, #:lo12:.LANCHOR0] mov w3, 1 mov w2, 2 stp w3, w2, [x0, 4] add w1, w1, w3 stlrw1, [x0] ret Which, afaict, is completely buggered. What it seems to be doing is turning the seq load into a load-acquire, but what we really need is to make sure the seq store (increment) is ordered before the other stores.
Re: [PATCH 00/13] [RFC] Rust support
On 19/04/21 09:32, Peter Zijlstra wrote: On Sat, Apr 17, 2021 at 04:51:58PM +0200, Paolo Bonzini wrote: On 16/04/21 09:09, Peter Zijlstra wrote: Well, the obvious example would be seqlocks. C11 can't do them Sure it can. C11 requires annotating with (the equivalent of) READ_ONCE all reads of seqlock-protected fields, but the memory model supports seqlocks just fine. How does that help? IIRC there's two problems, one on each side the lock. On the write side we have: seq++; smp_wmb(); X = r; Y = r; smp_wmb(); seq++; Which C11 simply cannot do right because it does't have wmb. It has atomic_thread_fence(memory_order_release), and atomic_thread_fence(memory_order_acquire) on the read side. You end up having to use seq_cst for the first wmb or make both X and Y (on top of the last seq) a store-release, both options are sub-optimal. seq_cst (except for the fence which is just smp_mb) is a pile of manure, no doubt about that. :) Paolo
Re: [PATCH 00/13] [RFC] Rust support
On Sat, Apr 17, 2021 at 04:51:58PM +0200, Paolo Bonzini wrote: > On 16/04/21 09:09, Peter Zijlstra wrote: > > Well, the obvious example would be seqlocks. C11 can't do them > > Sure it can. C11 requires annotating with (the equivalent of) READ_ONCE all > reads of seqlock-protected fields, but the memory model supports seqlocks > just fine. How does that help? IIRC there's two problems, one on each side the lock. On the write side we have: seq++; smp_wmb(); X = r; Y = r; smp_wmb(); seq++; Which C11 simply cannot do right because it does't have wmb. You end up having to use seq_cst for the first wmb or make both X and Y (on top of the last seq) a store-release, both options are sub-optimal. On the read side you get: do { s = seq; smp_rmb(); r1 = X; r2 = Y; smp_rmb(); } while ((s&1) || seq != s); And then you get into trouble the last barrier, so the first seq load can be load-acquire, after which the loads of X, Y come after, but you need then to happen before the second seq load, for which you then need seq_cst, or make X and Y load-acquire. Again, not optimal. I have also seen *many* broken variants of it on the web. Some work on x86 but are totally broken when you build them on LL/SC ARM64.
Re: [PATCH 00/13] [RFC] Rust support
On Sat, Apr 17, 2021 at 04:21:27PM +0200, Willy Tarreau wrote: > Well, I can't express how much I hate abstractions because I constantly > need to know what it's doing under the hood, and I spend my time reading > the output asm code because I always want to confirm my assumptions about > the compiler not cheating on me (and not hitting one of its bugs), > especially after C compilers have become so smart that they completely > replace your code with what they think is better for you, (including > nothing), I understand the feeling. One thing I can say about the abstractions we've been talking about is that they're zero-cost. So you'd still have the ability to inspect generated code and relate that to source, although it would still be subject to optimisations like C (or perhaps more optimisations as the compiler knows more about the code). > so I guess all of this is really not for someone like me. This may indeed be the case. But I'd invite you to try it out for yourself anyway before discounting it. I used to hate destructors in C++ because they were called implicitly: C was king because I had full control. Now I find myself publicly backing Rust. I feel the advantages outweigh the cost. > However while I'm pretty sure that based on our respective experiences > we'd probably disagree forever on a wide number of approaches when it > comes to deciding whether the developer or the compiler should have the > last say, I sincerely appreciate that you take the time to calmly explain > your differing views and the rationale behind, so many thanks for this! Thank you. I also appreciate your willingness to engage with us. Cheers, -Wedson
Re: [PATCH 00/13] [RFC] Rust support
On Wed, Apr 14, 2021 at 09:09:53PM +0100, Matthew Wilcox wrote: > By the way, I don't think that Rust necessarily has to conform to the > current way that Linux works. If this prompted us to track the current > context (inside spinlock, handling interrupt, performing writeback, etc) > and do away with (some) GFP flags, that's not the end of the world. > We're already moving in that direction to a certain extent with the > scoped memory allocation APIs to replace GFP_NOFS / GFP_NOIO. I hadn't myself considered this option but it looks enticing to me. Do you have a sense of which GFP flags we wouldn't be able to obviate even if we did track state?
Re: [PATCH 00/13] [RFC] Rust support
On Thu, Apr 15, 2021 at 2:41 AM wrote: > Regarding compilers, we support Clang-built kernels as well as > `LLVM=1` builds where possible (i.e. as long as supported by > the ClangBuiltLinux project). We also maintain some configurations > of GCC-built kernels working, but they are not intended to be used > at the present time. Having a `bindgen` backend for GCC would be > ideal to improve support for those builds. Sp this effectively means gcc is a second class citizen and even if gcc is supported at some point one needs a super recent gcc *and* rust toolchain to build a rust-enabeled kernel? I understand that this is right now not a big deal, but as soon a non-trival subsystem is rust-only people are forced to upgrade. Don't get me wrong, I'm all for having rust support in Linux. But I'm a bit worried about new dependencies on compiler toolchains. As someone who works a lot with long supported embedded systems I learned that as soon an application gains a hard dependency on clang or rust I'm in trouble. -- Thanks, //richard
Re: [PATCH 00/13] [RFC] Rust support
On Sat, Apr 17, 2021 at 4:21 PM Willy Tarreau wrote: > > Well, I can't express how much I hate abstractions because I constantly > need to know what it's doing under the hood, and I spend my time reading > the output asm code because I always want to confirm my assumptions about > the compiler not cheating on me (and not hitting one of its bugs), > especially after C compilers have become so smart that they completely > replace your code with what they think is better for you, (including > nothing), so I guess all of this is really not for someone like me. Concerning compiler bugs etc.: as you mention, nowadays that applies to both C and Rust. Manually inspecting the output asm does not really scale anymore because we need to worry about all compiler versions out there, including future ones, for both GCC and Clang. So we would need to disable optimizations, or reduce the set of supported compiler versions, or automatically check the generated asm (like in the compiler's own test suites), or keep binary blobs after checking (like in some safety-critical domains), etc. Since none of those are really doable for us (except perhaps for small subsets of code or unit tests), we need other ways to help with this. Rust provides several here. For instance, the UB-less subset means less surprises and less double-checking if some particular construct is UB and may give problems later on. Similarly, Rust is actually more explicit in many cases than C, to reduce surprises further. For instance, regarding implicit type conversions, none of these compile: fn f1(n: i32) -> i64 { n } fn f2(n: i32, m: i64) { n + m; } fn f3(b: bool) -> i32 { b } fn f4(n: i32) -> bool { n } fn f5(n: i32) -> i32 { if n { 42 } else { 53 } } Building abstractions also helps to ensure you get the semantics you want in the face of smart optimizers -- rather than the opposite. For instance, continuing with the integer examples, you may use a `NonZeroU32`. Or a `Wrapping` for intentional wrapping integer arithmetic, etc. Cheers, Miguel
Re: [PATCH 00/13] [RFC] Rust support
On 16/04/21 17:58, Theodore Ts'o wrote: Another fairly common use case is a lockless, racy test of a particular field, as an optimization before we take the lock before we test it for realsies. In this particular case, we can't allocate memory while holding a spinlock, so we check to see without taking the spinlock to see whether we should allocate memory (which is expensive, and unnecessasry most of the time): alloc_transaction: /* * This check is racy but it is just an optimization of allocating new * transaction early if there are high chances we'll need it. If we * guess wrong, we'll retry or free the unused transaction. */ if (!data_race(journal->j_running_transaction)) { /* * If __GFP_FS is not present, then we may be being called from * inside the fs writeback layer, so we MUST NOT fail. */ if ((gfp_mask & __GFP_FS) == 0) gfp_mask |= __GFP_NOFAIL; new_transaction = kmem_cache_zalloc(transaction_cache, gfp_mask); if (!new_transaction) return -ENOMEM; } From my limited experience with Rust, things like these are a bit annoying indeed, sooner or later Mutex<> just doesn't cut it and you have to deal with its limitations. In this particular case you would use an AtomicBool field, place it outside the Mutex-protected struct, and make sure that is only accessed under the lock just like in C. One easy way out is to make the Mutex protect (officially) nothing, i.e. Mutex<()>, and handle the mutable fields yourself using RefCell (which gives you run-time checking but has some some space cost) or UnsafeCell (which is unsafe as the name says). Rust makes it pretty easy to write smart pointers (Mutex<>'s lock guard itself is a smart pointer) so you also have the possibility of writing a safe wrapper for the combination of Mutex<()> and UnsafeCell. Another example is when yu have a list of XYZ objects and use the same mutex for both the list of XYZ and a field in struct XYZ. You could place that field in an UnsafeCell and write a function that receives a guard for the list lock and returns the field, or something like that. It *is* quite ugly though. As an aside, from a teaching standpoint associating a Mutex with a specific data structure is bad IMNSHO, because it encourages too fine-grained locking. Sometimes the easiest path to scalability is to use a more coarse lock and ensure that contention is extremely rare. But it does work for most simple use cases (and device drivers would qualify as simple more often than not). Paolo
Re: [PATCH 00/13] [RFC] Rust support
On 16/04/21 09:09, Peter Zijlstra wrote: Well, the obvious example would be seqlocks. C11 can't do them Sure it can. C11 requires annotating with (the equivalent of) READ_ONCE all reads of seqlock-protected fields, but the memory model supports seqlocks just fine. Simlar thing for RCU; C11 can't optimally do that Technically if you know what you're doing (i.e. that you're not on Alpha) you can do RCU using a relaxed load followed by an atomic_signal_fence(memory_order_consume). Which I agree is horrible and not entirely within the standard, but it works in practice. The Linux implementation of memory barriers, atomic RMW primitives, load-acquire/store-release etc. is also completely outside the standard, so it's not much different and more portable. The only thing that I really, really miss when programming with C11 atomics is smp_mb__{before,after}_atomic(). Paolo
Re: [PATCH 00/13] [RFC] Rust support
On Sat, Apr 17, 2021 at 04:24:43PM +0200, Peter Zijlstra wrote: > On Sat, Apr 17, 2021 at 01:46:23PM +0200, Willy Tarreau wrote: > > For me the old trick of casting one side as long long still works: > > > > unsigned long long mul3264(unsigned int a, unsigned int b) > > { > > return (unsigned long long)a * b; > > } > > > > i386: > > : > > 0: 8b 44 24 08 mov0x8(%esp),%eax > > 4: f7 64 24 04 mull 0x4(%esp) > > 8: c3ret > > > > x86_64: > > : > > 0: 89 f8 mov%edi,%eax > > 2: 89 f7 mov%esi,%edi > > 4: 48 0f af c7 imul %rdi,%rax > > 8: c3retq > > > > Or maybe you had something else in mind ? > > Last time I tried it, the thing refused :/ which is how we ended up with > mul_u32_u32() in asm. Oh I trust you, I do remember having noticed it on one gcc version as well (maybe 4.5). But I've been successfully using this since 2.95, and could quickly recheck that 4.7, 4.8, 5.4, 6.5, 7.4, 9.3 and 11-trunk do produce the code above, which is reassuring, as we all prefer to limit the amount of asm statements. Willy
Re: [PATCH 00/13] [RFC] Rust support
On Sat, Apr 17, 2021 at 01:46:23PM +0200, Willy Tarreau wrote: > For me the old trick of casting one side as long long still works: > > unsigned long long mul3264(unsigned int a, unsigned int b) > { > return (unsigned long long)a * b; > } > > i386: > : > 0: 8b 44 24 08 mov0x8(%esp),%eax > 4: f7 64 24 04 mull 0x4(%esp) > 8: c3ret > > x86_64: > : > 0: 89 f8 mov%edi,%eax > 2: 89 f7 mov%esi,%edi > 4: 48 0f af c7 imul %rdi,%rax > 8: c3retq > > Or maybe you had something else in mind ? Last time I tried it, the thing refused :/ which is how we ended up with mul_u32_u32() in asm.
Re: [PATCH 00/13] [RFC] Rust support
On Sat, Apr 17, 2021 at 02:53:10PM +0100, Wedson Almeida Filho wrote: > > > Note that this is > > > another area where Rust offers advantages: read-only guards (in C, if you > > > take a > > > read lock, nothing prevents you from making changes to fields you should > > > only be > > > allowed to read); > > > > But I'm happily doing that when I know what I'm doing. What you call a > > read lock usually is in fact a shared lock as opposed to an exclusive > > lock (generally used for writes). For me it's perfectly valid to perform > > atomic writes under a read lock instead of forcing everyone to wait by > > taking a write lock. You may for example take a read lock on a structure > > to make sure that a field you're accessing in it points to stable memory > > that is only modified under the write lock, but the pointer itself is > > atomically accessed and swapped under the read lock. > > Yes, this is a great example. Also easily expressible in Rust: they have this > concept of interior mutability where certain types allow their contents to be > modified even when shared immutably. Atomics offer such interior mutability, > so > the scenario you describe is fine. > > Rust in fact has an extra enforcement here that C doesn't: it requires > interior > mutability for this scenario to be allowed, so you can't do it with a plain > naked type (say u64) -- you'd need to use something like an atomic64_t, where > you're required to specify memory ordering when accessing them. > > In C we of course have atomics but the compiler never alerts us for when we > need > them. OK thanks for explaining. > > > In fact, this is also an advantage of Rust. It would *force* developers to > > > lock/unlock the RCU lock before they can access the protected data. > > > > I'm really afraid by languages which force developers to do this or that. > > When I say that Rust forces developers to do certain things, it's to provide > the > compile-time safety guarantees. Some of these requirements are imposed by our > own abstractions -- we can always revisit and try to improve them. In cases > when > the abstractions cannot be further refined, developers always have the escape > hatch of unsafety, where they're allowed to do pretty much everything as in C, > but then they also give up the compile-time guarantees for those parts. Well, I can't express how much I hate abstractions because I constantly need to know what it's doing under the hood, and I spend my time reading the output asm code because I always want to confirm my assumptions about the compiler not cheating on me (and not hitting one of its bugs), especially after C compilers have become so smart that they completely replace your code with what they think is better for you, (including nothing), so I guess all of this is really not for someone like me. However while I'm pretty sure that based on our respective experiences we'd probably disagree forever on a wide number of approaches when it comes to deciding whether the developer or the compiler should have the last say, I sincerely appreciate that you take the time to calmly explain your differing views and the rationale behind, so many thanks for this! Willy
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 06:14:44PM +0200, Willy Tarreau wrote: > But will this remain syntactically readable/writable by mere humans ? I would certainly hope so. > > Note that this is > > another area where Rust offers advantages: read-only guards (in C, if you > > take a > > read lock, nothing prevents you from making changes to fields you should > > only be > > allowed to read); > > But I'm happily doing that when I know what I'm doing. What you call a > read lock usually is in fact a shared lock as opposed to an exclusive > lock (generally used for writes). For me it's perfectly valid to perform > atomic writes under a read lock instead of forcing everyone to wait by > taking a write lock. You may for example take a read lock on a structure > to make sure that a field you're accessing in it points to stable memory > that is only modified under the write lock, but the pointer itself is > atomically accessed and swapped under the read lock. Yes, this is a great example. Also easily expressible in Rust: they have this concept of interior mutability where certain types allow their contents to be modified even when shared immutably. Atomics offer such interior mutability, so the scenario you describe is fine. Rust in fact has an extra enforcement here that C doesn't: it requires interior mutability for this scenario to be allowed, so you can't do it with a plain naked type (say u64) -- you'd need to use something like an atomic64_t, where you're required to specify memory ordering when accessing them. In C we of course have atomics but the compiler never alerts us for when we need them. > > In fact, this is also an advantage of Rust. It would *force* developers to > > lock/unlock the RCU lock before they can access the protected data. > > I'm really afraid by languages which force developers to do this or that. When I say that Rust forces developers to do certain things, it's to provide the compile-time safety guarantees. Some of these requirements are imposed by our own abstractions -- we can always revisit and try to improve them. In cases when the abstractions cannot be further refined, developers always have the escape hatch of unsafety, where they're allowed to do pretty much everything as in C, but then they also give up the compile-time guarantees for those parts.
RE: [PATCH 00/13] [RFC] Rust support
From: Peter Zijlstra > Sent: 17 April 2021 12:17 ... > > (i'd argue this is C being broken; promoting only as far as int, when > > assigning to an unsigned long is Bad, but until/unless either GCC fixes > > that or the language committee realises that being stuck in the 1970s > > is Bad, people are going to keep making this kind of mistake) > > Well, I think the rules actually make sense, at the point in the syntax > tree where + happens, we have 'unsigned char' and 'int', so at that > point we promote to 'int'. Subsequently 'int' gets shifted and bad > things happen. The 1970s were fine. K&R C was sign preserving - so 'unsigned char' promoted to 'unsigned int'. The ANSI C committee broke things by changing it to value preserving with the strong preference for signed types. Even with ANSI C the type of ((unsigned char)x + 1) can be unsigned! All it needs as an architecture where sizeof (int) == 1. (sizeof (char) has to be 1 - even though that isn't directly explicit.) Of course, having 32-bit 'char' and 'int' does give problems with the value for EOF. David - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 04:03:07PM +0100, Matthew Wilcox wrote: > Well, we could do that in C too. > > struct unlocked_inode { > spinlock_t i_lock; > }; > > struct locked_inode { > spinlock_t i_lock; > unsigned short i_bytes; > blkcnt_t i_blocks; > }; > > struct locked_inode *lock_inode(struct unlocked_inode *inode) > { > spin_lock(&inode->i_lock); > return (struct locked_inode *)inode; > } Indeed you can do this kind of thing in C, but as I said before (apologies if I'm too repetitive on this) Rust forces you to do it the right way, whereas the lack of enforcement in C leaves room for mistakes. If you do add extensions to C to add some of these restrictions (and I encourage you to pursue such extensions as we all benefit from better C), it is likely not sufficient to reach the level of compile-time guarantee that Rust offers because you need a whole slew of restrictions/enforcements. I also note that academics have a formalisation of [a subset of] Rust that show the soundness of these guarantees and the requirements on unsafe to compose safely. So we're not talking about guesswork, there are formal machine-checked proofs published about this (see for example https://people.mpi-sws.org/~dreyer/papers/safe-sysprog-rust/paper.pdf).
Re: [PATCH 00/13] [RFC] Rust support
On Sat, Apr 17, 2021 at 12:41:23PM +, David Laight wrote: > Or the cases where the locks are released in the 'wrong' order. > Typically for: > lock(table) > item = lookup(table, key) > lock(item) > unlock(table) > ... > unlock(item) This is expressible in Rust with something like: table = table_mutex.lock() item = table.lookup(key).lock() drop(table) ... // item will be unlocked when it goes out of scope or on drop(item) The added bonus here from Rust is that table is not accessible after drop(table), so a developer cannot accidentally access fields after unlocking it. > > (In the kernel the table lock might be RCU.) > > Or, with similar data: > write_lock(table); > foreach(item, table) > lock(item) > unlock(item) > /* No items can be locked until we release the write_lock. > ... > unlock(table) I think I'm missing something here. Would you help me understand what part is out of the ordinary in the code above? It would be expressible in Rust with something like: table = table_mutex.write(); for (item_mutex in table) item = item_mutex.lock // item is unlocked at the end of the loop iteration (out of scope) // table gets unlocked when it goes out of scope Cheers, -Wedson
RE: [PATCH 00/13] [RFC] Rust support
.. > The more you make it look like (Kernel) C, the easier it is for us C > people to actually read. My eyes have been reading C for almost 30 years > by now, they have a lexer built in the optical nerve; reading something > that looks vaguely like C but is definitely not C is an utterly painful > experience. I'll see your 30 years and raise to over 35. (And writing code that accesses hardware for 6 or 7 years before that.) Both Java and go can look more like the K&R style C than any of the examples from microsoft - which seem to utilise as much vertical space as humanly? possible. Those rust examples seemed to be of the horrid microsoft sytle. Nothing about that style makes reading code easy. David - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
RE: [PATCH 00/13] [RFC] Rust support
From: Peter Zijlstra > Sent: 16 April 2021 15:19 > > On Fri, Apr 16, 2021 at 02:07:49PM +0100, Wedson Almeida Filho wrote: > > On Fri, Apr 16, 2021 at 01:24:23PM +0200, Peter Zijlstra wrote: > > > > int perf_event_task_enable(void) > > > { > > > + DEFINE_MUTEX_GUARD(event_mutex, ¤t->perf_event_mutex); > > > > There is nothing in C forcing developers to actually use > > DEFINE_MUTEX_GUARD. So > > someone may simply forget (or not know that they need) to lock > > current->perf_event_mutex and directly access some field protected by it. > > This > > is unlikely to happen when one first writes the code, but over time as > > different > > people modify the code and invariants change, it is possible for this to > > happen. > > > > In Rust, this isn't possible: the data protected by a lock is only > > accessible > > when the lock is locked. So developers cannot accidentally make mistakes of > > this > > kind. And since the enforcement happens at compile time, there is no runtime > > cost. > > > > This, we believe, is fundamental to the discussion: we agree that many of > > these > > idioms can be implemented in C (albeit in this case with a compiler > > extension), > > but their use is optional, people can (and do) still make mistakes that > > lead to > > vulnerabilities; Rust disallows classes of mistakes by construction. > > Does this also not prohibit constructs where modification must be done > while holding two locks, but reading can be done while holding either > lock? > > That's a semi common scheme in the kernel, but not something that's > expressible by, for example, the Java sync keyword. > > It also very much doesn't work for RCU, where modification must be done > under a lock, but access is done essentially lockless. ... Or the cases where the locks are released in the 'wrong' order. Typically for: lock(table) item = lookup(table, key) lock(item) unlock(table) ... unlock(item) (In the kernel the table lock might be RCU.) Or, with similar data: write_lock(table); foreach(item, table) lock(item) unlock(item) /* No items can be locked until we release the write_lock. ... unlock(table) You can also easily end up with a 'fubar' we have at work where someone wrote a C++ condvar class that inherits from mutex. David - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Re: [PATCH 00/13] [RFC] Rust support
On Sat, Apr 17, 2021 at 01:17:21PM +0200, Peter Zijlstra wrote: > Well, I think the rules actually make sense, at the point in the syntax > tree where + happens, we have 'unsigned char' and 'int', so at that > point we promote to 'int'. Subsequently 'int' gets shifted and bad > things happen. That's always the problem caused by signedness being applied to the type while modern machines do not care about that and use it during (or even after) the operation instead :-/ We'd need to define some macros to zero-extend and sign-extend some values to avoid such issues. I'm sure this would be more intuitive than trying to guess how many casts (and in what order) to place to make sure an operation works as desired. > The 'unsigned long' doesn't happen until quite a bit later. > > Anyway, the rules are imo fairly clear and logical, but yes they can be > annoying. The really silly thing here is that << and >> have UB at all, > and I would love a -fwrapv style flag that simply defines it. Yes it > will generate worse code in some cases, but having the UB there is just > stupid. I'd also love to have a UB-less mode with well defined semantics for plenty of operations that are known to work well on modern machines, like integer wrapping, bit shifts ignoring higher bits etc. Lots of stuff we often have to write useless code for, just to please the compiler. > That of course doesn't help your case here, it would simply misbehave > and not be UB. > > Another thing the C rules cannot really express is a 32x32->64 > multiplication, some (older) versions of GCC can be tricked into it, but > mostly it just doesn't want to do that sanely and the C rules are > absolutely no help there. For me the old trick of casting one side as long long still works: unsigned long long mul3264(unsigned int a, unsigned int b) { return (unsigned long long)a * b; } i386: : 0: 8b 44 24 08 mov0x8(%esp),%eax 4: f7 64 24 04 mull 0x4(%esp) 8: c3ret x86_64: : 0: 89 f8 mov%edi,%eax 2: 89 f7 mov%esi,%edi 4: 48 0f af c7 imul %rdi,%rax 8: c3retq Or maybe you had something else in mind ? Willy
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 07:08:29PM +0100, Matthew Wilcox wrote: > On Fri, Apr 16, 2021 at 07:18:48PM +0200, Peter Zijlstra wrote: > > On Fri, Apr 16, 2021 at 07:10:17PM +0200, Miguel Ojeda wrote: > > > > > Of course, UB is only a subset of errors, but it is a major one, and > > > particularly critical for privileged code. > > > > I've seen relatively few UBSAN warnings that weren't due to UBSAN being > > broken. > > Lucky you. > > 84c34df158cf215b0cd1475ab3b8e6f212f81f23 > > (i'd argue this is C being broken; promoting only as far as int, when > assigning to an unsigned long is Bad, but until/unless either GCC fixes > that or the language committee realises that being stuck in the 1970s > is Bad, people are going to keep making this kind of mistake) Well, I think the rules actually make sense, at the point in the syntax tree where + happens, we have 'unsigned char' and 'int', so at that point we promote to 'int'. Subsequently 'int' gets shifted and bad things happen. The 'unsigned long' doesn't happen until quite a bit later. Anyway, the rules are imo fairly clear and logical, but yes they can be annoying. The really silly thing here is that << and >> have UB at all, and I would love a -fwrapv style flag that simply defines it. Yes it will generate worse code in some cases, but having the UB there is just stupid. That of course doesn't help your case here, it would simply misbehave and not be UB. Another thing the C rules cannot really express is a 32x32->64 multiplication, some (older) versions of GCC can be tricked into it, but mostly it just doesn't want to do that sanely and the C rules are absolutely no help there.
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 4:24 AM Peter Zijlstra wrote: > Simlar thing for RCU; C11 can't optimally do that; it needs to make > rcu_dereference() a load-acquire [something ARM64 has already done in C > because the compiler might be too clever by half when doing LTO :-(]. > But it's the compiler needing the acquire semantics, not the computer, > which is just bloody wrong. You may already know, but perhaps worth clarifying: C11 does have atomic_signal_fence() which is a compiler fence. But a compiler fence only ensures the loads will be emitted in the right order, not that the CPU will execute them in the right order. CPU architectures tend to guarantee that two loads will be executed in the right order if the second one's address depends on the first one's result, but a dependent load can stop being dependent after compiler optimizations involving value speculation. Using a load-acquire works around this, not because it stops the compiler from performing any optimization, but because it tells the computer to execute the loads in the right order *even if* the compiler has broken the value dependence. So C11 atomics don't make the situation worse, compared to Linux's atomics implementation based on volatile and inline assembly. Both are unsound in the presence of value speculation. C11 atomics were *supposed* to make the situation better, with memory_order_consume, which would have specifically forbidden the compiler from performing value speculation. But all the compilers punted on getting this to work and instead just implemented memory_order_consume as memory_order_acquire. As for Rust, it compiles to the same LLVM IR that Clang compiles C into. Volatile, inline assembly, and C11-based atomics: all of these are available in Rust, and generate exactly the same code as their C counterparts, for better or for worse. Unfortunately, the Rust project has relatively limited muscle when it comes to contributing to LLVM. So while it would definitely be nice if Rust could make RCU sound, and from a specification perspective I think people would be quite willing and probably easier to work with than the C committee... I suspect that implementing this would require the kind of sweeping change to LLVM that is probably not going to come from Rust. There are other areas where I think that kind of discussion might be more fruitful. For example, the Rust documentation currently says that a volatile read racing with a non-volatile write (i.e. seqlocks) is undefined behavior. [1] However, I am of the opinion that this is essentially a spec bug, for reasons that are probably not worth getting into here. [1] https://doc.rust-lang.org/nightly/std/ptr/fn.read_volatile.html
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 12:27:39PM +0800, Boqun Feng wrote: > Josh, I think it's good if we can connect to the people working on Rust > memoryg model, I think the right person is Ralf Jung and the right place > is https://github.com/rust-lang/unsafe-code-guidelines, but you > cerntainly know better than me ;-) Or maybe we can use Rust-for-Linux or > linux-toolchains list to discuss. Ralf is definitely the right person to talk to. I don't think the UCG repository is the right place to start that discussion, though. For now, I'd suggest starting an email thread with Ralf and some C-and-kernel memory model folks (hi Paul!) to suss out the most important changes that would be needed. With my language team hat on, I'd *absolutely* like to see the Rust memory model support RCU-style deferred reclamation in a sound way, ideally with as little unsafe code as possible.
Re: [PATCH 00/13] [RFC] Rust support
On Thu, Apr 15, 2021 at 11:04:37PM -0700, Nick Desaulniers wrote: > On Thu, Apr 15, 2021 at 9:27 PM Boqun Feng wrote: > > > > [Copy LKMM people, Josh, Nick and Wedson] > > > > On Thu, Apr 15, 2021 at 08:58:16PM +0200, Peter Zijlstra wrote: > > > On Wed, Apr 14, 2021 at 08:45:51PM +0200, oj...@kernel.org wrote: > > > > > > > Rust is a systems programming language that brings several key > > > > advantages over C in the context of the Linux kernel: > > > > > > > > - No undefined behavior in the safe subset (when unsafe code is > > > > sound), including memory safety and the absence of data races. > > > > > > And yet I see not a single mention of the Rust Memory Model and how it > > > aligns (or not) with the LKMM. The C11 memory model for example is a > > > really poor fit for LKMM. > > > > > > > I think Rust currently uses C11 memory model as per: > > > > https://doc.rust-lang.org/nomicon/atomics.html > > > > , also I guess another reason that they pick C11 memory model is because > > LLVM has the support by default. > > > > But I think the Rust Community still wants to have a good memory model, > > and they are open to any kind of suggestion and input. I think we (LKMM > > people) should really get involved, because the recent discussion on > > RISC-V's atomics shows that if we didn't people might get a "broken" > > design because they thought C11 memory model is good enough: > > > > https://lore.kernel.org/lkml/YGyZPCxJYGOvqYZQ@boqun-archlinux/ > > > > And the benefits are mutual: a) Linux Kernel Memory Model (LKMM) is > > defined by combining the requirements of developers and the behavior of > > hardwares, it's pratical and can be a very good input for memory model > > designing in Rust; b) Once Rust has a better memory model, the compiler > > technologies whatever Rust compilers use to suppor the memory model can > > be adopted to C compilers and we can get that part for free. > > Yes, I agree; I think that's a very good approach. Avoiding the ISO > WG14 is interesting; at least the merits could be debated in the > public and not behind closed doors. WG14 (C) and WG21 (C++) are at least somewhat open. Here are some of the proposals a few of us have in flight: P2055R0 A Relaxed Guide to memory_order_relaxed http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2055r0.pdf P0124R7 Linux-Kernel Memory Model (vs. that of C/C++) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0124r7.html P1726R4 Pointer lifetime-end zap http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1726r4.pdf https://docs.google.com/document/d/1MfagxTa6H0rTxtq9Oxyh4X53NzKqOt7y3hZBVzO_LMk/edit?usp=sharing P1121R2 Hazard Pointers: Proposed Interface and Wording for Concurrency TS 2 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1121r2.pdf P1382R1 volatile_load and volatile_store http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1382r1.pdf P1122R2 Proposed Wording for Concurrent Data Structures: Read-Copy-Update (RCU) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1122r2.pdf https://docs.google.com/document/d/1MfagxTa6H0rTxtq9Oxyh4X53NzKqOt7y3hZBVzO_LMk/edit?usp=sharing P0190R4 Proposal for New memory order consume Definition http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0190r4.pdf P0750R1 Consume http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0750r1.html P1726R4 is of particular concern, along with consume. > > At least I personally is very intereted to help Rust on a complete and > > pratical memory model ;-) > > > > Josh, I think it's good if we can connect to the people working on Rust > > memoryg model, I think the right person is Ralf Jung and the right place > > is https://github.com/rust-lang/unsafe-code-guidelines, but you > > cerntainly know better than me ;-) Or maybe we can use Rust-for-Linux or > > linux-toolchains list to discuss. > > > > [...] > > > > - Boqun Feng is working hard on the different options for > > > > threading abstractions and has reviewed most of the `sync` PRs. > > > > > > Boqun, I know you're familiar with LKMM, can you please talk about how > > > Rust does things and how it interacts? > > > > As Wedson said in the other email, currently there is no code requiring > > synchronization between C side and Rust side, so we are currently fine. > > But in the longer term, we need to teach Rust memory model about the > > "design patterns" used in Linux kernel for parallel programming. > > > > What I have been doing so far is reviewing patches which have memory > > orderings in Rust-for-Linux project, try to make sure we don't include > > memory ordering bugs for the beginning. I believe that compatibility with both C/C++ and the Linux kernel are important. Thanx, Paul
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 07:18:48PM +0200, Peter Zijlstra wrote: > On Fri, Apr 16, 2021 at 07:10:17PM +0200, Miguel Ojeda wrote: > > > Of course, UB is only a subset of errors, but it is a major one, and > > particularly critical for privileged code. > > I've seen relatively few UBSAN warnings that weren't due to UBSAN being > broken. Lucky you. 84c34df158cf215b0cd1475ab3b8e6f212f81f23 (i'd argue this is C being broken; promoting only as far as int, when assigning to an unsigned long is Bad, but until/unless either GCC fixes that or the language committee realises that being stuck in the 1970s is Bad, people are going to keep making this kind of mistake)
Re: [PATCH 00/13] [RFC] Rust support
On 4/16/21 12:37 PM, Willy Tarreau wrote: > Hi Miguel, > > On Fri, Apr 16, 2021 at 07:10:17PM +0200, Miguel Ojeda wrote: >> And by having the compiler enforce this safe-unsafe split, you can >> review safe code without having to constantly worry about UB; and be >> extra alert when dealing with `unsafe` blocks. > > I do appreciate this safe/unsafe split and a few other things I've seen > in the language. The equivalent I'm using in C is stronger typing and > "const" modifiers wherever possible. Of course it's much more limited, > it's just to explain that I do value this. I just feel like "unsafe" > is the universal response to any question "how would I do this" while > at the same time "safe" is the best selling argument for the language. > As such, I strongly doubt about the real benefits once facing reality > with everything marked unsafe. Except that it will be easier to blame > the person having written the unsafe one-liner instead of writing 60 > cryptic lines doing the functional equivalent using some lesser known > extensions :-/ > It's possible that many of the questions you've been specifically asking about, by sheer coincidence, are targeted towards the problems that would indeed require a lower-level abstraction built within an unsafe block; meaning you've managed to evade the tons of other upper layers that could be written in safe Rust. Indeed, at a certain layer, unsafe is unavoidable for the kind of work that is done in the kernel. The goal is to shrink the unsafe blocks as much as possible and confirm the correctness of those pieces, then build safe abstractions on top of it. For what it's worth, if there was some post-human apocalyptic world where literally everything had to go inside an unsafe block, the silver lining in a hypothetical situation like this is that unsafe does not disable all of Rust's static analysis like the borrow checker, etc. It allows you to do things like directly dereference a pointer, etc. Unsafe also doesn't automatically mean that the code is wrong or that it has memory issues; it just means that the compiler can't guarantee that it doesn't based on what you do in the unsafe block. Connor
Re: [PATCH 00/13] [RFC] Rust support
Hi Miguel, On Fri, Apr 16, 2021 at 07:10:17PM +0200, Miguel Ojeda wrote: > And by having the compiler enforce this safe-unsafe split, you can > review safe code without having to constantly worry about UB; and be > extra alert when dealing with `unsafe` blocks. I do appreciate this safe/unsafe split and a few other things I've seen in the language. The equivalent I'm using in C is stronger typing and "const" modifiers wherever possible. Of course it's much more limited, it's just to explain that I do value this. I just feel like "unsafe" is the universal response to any question "how would I do this" while at the same time "safe" is the best selling argument for the language. As such, I strongly doubt about the real benefits once facing reality with everything marked unsafe. Except that it will be easier to blame the person having written the unsafe one-liner instead of writing 60 cryptic lines doing the functional equivalent using some lesser known extensions :-/ > Of course, UB is only a subset of errors, but it is a major one, and > particularly critical for privileged code. Not in my experience. I do create bugs that very seldomly stem from UB, like any of us probably. But the vast majority of my bugs are caused by stupid logic errors. When you invert an error check somewhere because the function name looks like a boolean but its result works the other way around, you can pass 10 times over it without noticing, and the compiler will not help. And these ones are due to the human brain not being that powerful in front of a computer, and whatever language will not change this. Or worse, if it's harder to express what I want, I will write more bugs. It happened to me quite a few times already trying to work around absurd gcc warnings. Based on the comments in this thread and the responses often being around "we'll try to get this done" or "we'll bring the issue to the compiler team", combined with the difficulty to keep control over resources usage, I'm really not convinced at all it's suited for low-level development. I understand the interest of the experiment to help the language evolve into that direction, but I fear that the kernel will soon be as bloated and insecure as a browser, and that's really not to please me. Cheers, Willy
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 07:10:17PM +0200, Miguel Ojeda wrote: > Of course, UB is only a subset of errors, but it is a major one, and > particularly critical for privileged code. I've seen relatively few UBSAN warnings that weren't due to UBSAN being broken.
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 6:14 PM Willy Tarreau wrote: > > I'm really afraid by languages which force developers to do this or that. > Many bugs in C come from casts because developers know their use case > better than the compiler's developers, and result in lack of warnings > when the code evolves, leaving pending bugs behind. What is important > in my opinion is to let developers express what they want and report > suspicious constructs, not to force them to dirtily work around rules > that conflict with their use case :-/ I understand your concerns. The idea is that by restricting some patterns (in the safe subset), you gain the ability to guarantee the absence of UB (as long as the `unsafe` code is sound). But please note that the `unsafe` side is still there, and you can reach out for it when needed. Thus, if you find yourself in a situation where the safe abstractions are not enough for what you need to convey, you have two options: ideally, you think about how to model that pattern in a way that can be exposed as a safe API so that others can reuse it. And if that is not possible, you reach out for `unsafe` yourself. Even in those cases where there is no other way around `unsafe`, note that you still have gained something very important: now you have made it explicit in the code that this is needed, and you will have written a `SAFETY` annotation that tells others why your usage is sound (i.e. why it cannot trigger UB). And by having the compiler enforce this safe-unsafe split, you can review safe code without having to constantly worry about UB; and be extra alert when dealing with `unsafe` blocks. Of course, UB is only a subset of errors, but it is a major one, and particularly critical for privileged code. Cheers, Miguel
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 5:43 PM Peter Zijlstra wrote: > > http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2659.htm > > That's just not making any damn sense what so ever. That seems to be > about sprinkling abort() all over the place, which is just total > rubbish. No, it is not about that. It is semantically a no-op: N2659 is not about a safe subset of C -- it just triggered discussions about it in the reflector. The point is that we think it is important to improve C for the kernel too. We are not working on bringing Rust to the kernel "just because we want Rust", but because we believe it has a sizable amount of advantages that outweigh the costs. Cheers, Miguel
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 11:58:05AM -0400, Theodore Ts'o wrote: > Another fairly common use case is a lockless, racy test of a > particular field, as an optimization before we take the lock before we > test it for realsies. In this particular case, we can't allocate > memory while holding a spinlock, so we check to see without taking the > spinlock to see whether we should allocate memory (which is expensive, > and unnecessasry most of the time): I'd have to think more about whether we can build generic safe abstraction for this pattern. But even if we can't, we always have the unsafe escape hatch: we can grant unsafe unlocked access to the data; in such cases, the onus is on the caller to convince themselves that what they're doing is safe, i.e., the compiler won't offer compile-time guarantees. However, and I think this is also an advantage of Rust, such unsafe accesses *must* be explicitly tagged as such (and this is enforced at compile-time), so you'd do something like: // SAFETY: The below is safe because... if !unsafe{ journal.access_unlocked().j_running_transaction } { } And the idea is that unsafe blocks like the one above will require additional scrutiny from reviewers. So this also makes the lives of maintainers/reviewers easier as they'd know that these sections need more attention. > The other thing that I'll note is that diferent elements in thet > journal structure are protected by different spinlocks; we don't have > a global lock protecting the entire structure, which is critical for > scalability on systems with a large number of CPU's with a lot of > threads all wanting to perform file system operations. Yes, this is fine, the way to do it in Rust would be to break your struct up into something like (we have something like this in Binder): struct X { [...] } struct Y { [...] } struct Z { x: SpinLock, y: SpinLock, a: u32, [...] } > So having a guard structure which can't be bypassed on the entire > structure would result in a pretty massive performance penalty for the > ext4 file system. I know that initially the use of Rust in the kernel > is targetted for less performance critical modules, such as device > drivers, but I thought I would mention some of the advantages of more > advanced locking techniques. Thanks for this. Yes, while the initial target is drivers, we do want to provide a general framework that could potentially be used anywhere. Please let us know if you find other patterns that seem problematic. Cheers, -Wedson
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 04:33:51PM +0100, Wedson Almeida Filho wrote: > On Fri, Apr 16, 2021 at 04:19:07PM +0200, Peter Zijlstra wrote: > > Does this also not prohibit constructs where modification must be done > > while holding two locks, but reading can be done while holding either > > lock? > > I don't believe it does. Remember that we have full control of the > abstractions, > so we can (and will when the need arises) build an abstraction that provides > the > functionality you describe. For the read path, we can have functions that > return > a read-only guard (which is the gateway to the data in Rust) when locking > either > of the locks, or when showing evidence that either lock is already locked > (i.e., > by temporarily transferring ownership of another guard). But will this remain syntactically readable/writable by mere humans ? I mean, I keep extremely bad memories of having tried to write a loop oconcatenating at most N times a string to another one, where N was a number provided on the command line, with the compiler shouting at me all the time until I blindly copy-pasted random pieces of unreadable code from the net with a horribly complicated syntax that still resulted in the impossibility for me to check for memory allocation before failing. So I'm wondering how complicated that can become after adding all sort of artificial protections on top of this :-/ > Note that this is > another area where Rust offers advantages: read-only guards (in C, if you > take a > read lock, nothing prevents you from making changes to fields you should only > be > allowed to read); But I'm happily doing that when I know what I'm doing. What you call a read lock usually is in fact a shared lock as opposed to an exclusive lock (generally used for writes). For me it's perfectly valid to perform atomic writes under a read lock instead of forcing everyone to wait by taking a write lock. You may for example take a read lock on a structure to make sure that a field you're accessing in it points to stable memory that is only modified under the write lock, but the pointer itself is atomically accessed and swapped under the read lock. > In fact, this is also an advantage of Rust. It would *force* developers to > lock/unlock the RCU lock before they can access the protected data. I'm really afraid by languages which force developers to do this or that. Many bugs in C come from casts because developers know their use case better than the compiler's developers, and result in lack of warnings when the code evolves, leaving pending bugs behind. What is important in my opinion is to let developers express what they want and report suspicious constructs, not to force them to dirtily work around rules that conflict with their use case :-/ Willy
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 02:07:49PM +0100, Wedson Almeida Filho wrote: > On Fri, Apr 16, 2021 at 01:24:23PM +0200, Peter Zijlstra wrote: > > On Wed, Apr 14, 2021 at 08:45:51PM +0200, oj...@kernel.org wrote: > > > - Featureful language: sum types, pattern matching, generics, > > > RAII, lifetimes, shared & exclusive references, modules & > > > visibility, powerful hygienic and procedural macros... > > > > IMO RAII is over-valued, but just in case you care, the below seems to > > work just fine. No fancy new language needed, works today. Similarly you > > can create refcount_t guards, or with a little more work full blown > > smart_ptr crud. > > Peter, we do care, thank you for posting this. It's a great example for us to > discuss some of the minutiae of what we think Rust brings to the table in > addition to what's already possible in C. Another fairly common use case is a lockless, racy test of a particular field, as an optimization before we take the lock before we test it for realsies. In this particular case, we can't allocate memory while holding a spinlock, so we check to see without taking the spinlock to see whether we should allocate memory (which is expensive, and unnecessasry most of the time): alloc_transaction: /* * This check is racy but it is just an optimization of allocating new * transaction early if there are high chances we'll need it. If we * guess wrong, we'll retry or free the unused transaction. */ if (!data_race(journal->j_running_transaction)) { /* * If __GFP_FS is not present, then we may be being called from * inside the fs writeback layer, so we MUST NOT fail. */ if ((gfp_mask & __GFP_FS) == 0) gfp_mask |= __GFP_NOFAIL; new_transaction = kmem_cache_zalloc(transaction_cache, gfp_mask); if (!new_transaction) return -ENOMEM; } ... repeat: read_lock(&journal->j_state_lock); ... if (!journal->j_running_transaction) { read_unlock(&journal->j_state_lock); if (!new_transaction) goto alloc_transaction; write_lock(&journal->j_state_lock); if (!journal->j_running_transaction && (handle->h_reserved || !journal->j_barrier_count)) { jbd2_get_transaction(journal, new_transaction); new_transaction = NULL; } write_unlock(&journal->j_state_lock); goto repeat; } ... The other thing that I'll note is that diferent elements in thet journal structure are protected by different spinlocks; we don't have a global lock protecting the entire structure, which is critical for scalability on systems with a large number of CPU's with a lot of threads all wanting to perform file system operations. So having a guard structure which can't be bypassed on the entire structure would result in a pretty massive performance penalty for the ext4 file system. I know that initially the use of Rust in the kernel is targetted for less performance critical modules, such as device drivers, but I thought I would mention some of the advantages of more advanced locking techniques. Cheers, - Ted
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 05:04:41PM +0200, Miguel Ojeda wrote: > Of course, we could propose something similar for C -- in fact, there > was a recent discussion around this in the C committee triggered by my > n2659 "Safety attributes for C" paper. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2659.htm That's just not making any damn sense what so ever. That seems to be about sprinkling abort() all over the place, which is just total rubbish.
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 04:19:07PM +0200, Peter Zijlstra wrote: > Does this also not prohibit constructs where modification must be done > while holding two locks, but reading can be done while holding either > lock? I don't believe it does. Remember that we have full control of the abstractions, so we can (and will when the need arises) build an abstraction that provides the functionality you describe. For the read path, we can have functions that return a read-only guard (which is the gateway to the data in Rust) when locking either of the locks, or when showing evidence that either lock is already locked (i.e., by temporarily transferring ownership of another guard). Note that this is another area where Rust offers advantages: read-only guards (in C, if you take a read lock, nothing prevents you from making changes to fields you should only be allowed to read); and the ability to take temporary ownership, giving it back even within the same function. Similarly, to access a mutable guard, you'd have to show evidence that both locks are held. > That's a semi common scheme in the kernel, but not something that's > expressible by, for example, the Java sync keyword. > > It also very much doesn't work for RCU, where modification must be done > under a lock, but access is done essentially lockless. Why not? RCU is a lock -- it may have zero cost in most (all?) architectures on the read path, but it is a lock. We can model access to variables/fields protected by it just like any other lock, with the implementation of lock/unlock optimizing to no-ops on the read path where possible. In fact, this is also an advantage of Rust. It would *force* developers to lock/unlock the RCU lock before they can access the protected data. > I would much rather have a language extention where we can associate > custom assertions with variable access, sorta like a sanitizer: > > static inline void assert_foo_bar(struct foo *f) > { > lockdep_assert_held(&f->lock); > } > > struct foo { > spinlock_t lock; > int bar __assert__(assert_foo_bar); > }; > > Such things can be optional and only enabled for debug builds on new > compilers. These would be great, but would still fall short of the compile-time guaranteed safety that Rust offers in these cases. > C does indeed not have the concept of ownership, unlike modern C++ I > think. But I would much rather see a C language extention for that than > go Rust. > > This would mean a far more agressive push for newer C compilers than > we've ever done before, but at least it would all still be a single > language. Convertion to the new stuff can be done gradually and where > it makes sense and new extentions can be evaluated on performance impact > etc. I encourage you to pursue this. We'd all benefit from better C. I'd be happy to review and provide feedback on proposed extensions that are deemed equivalent/better than what Rust offers. My background is also in C. I'm no Rust fanboy, I'm just taking what I think is a pragmatic view of the available options.
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 4:19 PM Peter Zijlstra wrote: > > Does this also not prohibit constructs where modification must be done > while holding two locks, but reading can be done while holding either > lock? Yeah, this came up in some discussions we had. There are some locking patterns that we need to think about how to model best within Rust's type system. But even if some patterns cannot be made safe, that is fine and does not diminish the advantages everywhere else. > I would much rather have a language extention where we can associate > custom assertions with variable access, sorta like a sanitizer: > > static inline void assert_foo_bar(struct foo *f) > { > lockdep_assert_held(&f->lock); > } > > struct foo { > spinlock_t lock; > int bar __assert__(assert_foo_bar); > }; > > Such things can be optional and only enabled for debug builds on new > compilers. More sanitizers and ways to check "unsafe" code is sound are always welcome -- not just for C, also for Rust `unsafe` code (e.g. Miri). However, the main advantage of Rust for us is its safe subset (which handles quite a lot of patterns, thanks to the lifetime tracking / borrow checker). Of course, we could propose something similar for C -- in fact, there was a recent discussion around this in the C committee triggered by my n2659 "Safety attributes for C" paper. However, achieving that would require a lot of work, time, new syntax, etc. It is not something that is in the radar just yet. Similarly, if some compiler ends up implementing an extension that actually realizes the same guarantees as Rust, we would likely end up wrapping everything with macros like in the guards example you mentioned, and even then we would not have got the rest of the advantages that Rust brings to the table. > C does indeed not have the concept of ownership, unlike modern C++ I > think. But I would much rather see a C language extention for that than > go Rust. Many "resource-like" C++ types model ownership, yes; e.g. `std::unique_ptr` for memory, as well as a myriad of ones in different projects for different kinds of resources, plus generic ones like the proposed P0052. However, they do not enforce their usage is correct. Cheers, Miguel
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 02:07:49PM +0100, Wedson Almeida Filho wrote: > There is nothing in C forcing developers to actually use DEFINE_MUTEX_GUARD. > So > someone may simply forget (or not know that they need) to lock > current->perf_event_mutex and directly access some field protected by it. This > is unlikely to happen when one first writes the code, but over time as > different > people modify the code and invariants change, it is possible for this to > happen. > > In Rust, this isn't possible: the data protected by a lock is only accessible > when the lock is locked. So developers cannot accidentally make mistakes of > this > kind. And since the enforcement happens at compile time, there is no runtime > cost. Well, we could do that in C too. struct unlocked_inode { spinlock_t i_lock; }; struct locked_inode { spinlock_t i_lock; unsigned short i_bytes; blkcnt_t i_blocks; }; struct locked_inode *lock_inode(struct unlocked_inode *inode) { spin_lock(&inode->i_lock); return (struct locked_inode *)inode; } There's a combinatoric explosion when you have multiple locks in a data structure that protect different things in it (and things in a data structure that are protected by locks outside that data structure), but I'm not sufficiently familiar with Rust to know if/how it solves that problem. Anyway, my point is that if we believe this is a sufficiently useful feature to have, and we're willing to churn the kernel, it's less churn to do this than it is to rewrite in Rust. > Another scenario: suppose within perf_event_task_enable you need to call a > function that requires the mutex to be locked and that will unlock it for you > on > error (or unconditionally, doesn't matter). How would you do that in C? In > Rust, > there is a clean idiomatic way of transferring ownership of a guard (or any > other object) such that the previous owner cannot continue to use it after > ownership is transferred. Again, this is enforced at compile time. I'm happy > to > provide a small example if that would help. I think we could do that too with an __attribute__((free)). It isn't, of course, actually freeing the pointer to the locked_inode, but it will make the compiler think the pointer is invalid after the function returns. (hm, looks like gcc doesn't actually have __attribute__((free)) yet. that's unfortunate. there's a potential solution in gcc-11 that might do what we need)
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 1:24 PM Peter Zijlstra wrote: > > IMO RAII is over-valued, but just in case you care, the below seems to > work just fine. No fancy new language needed, works today. Similarly you > can create refcount_t guards, or with a little more work full blown > smart_ptr crud. Please note that even smart pointers (as in C++'s `std::unique_ptr` etc.) do not guarantee memory safety. Yes, they help a lot writing sound code (in particular exception-safe C++ code), but they do not bring the same guarantees. That's why using C language extensions (the existing ones, that is) to recreate RAII/guards, smart pointers, etc. would only bring you to a point closer to C++, but not to Rust. Cheers, Miguel
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 02:07:49PM +0100, Wedson Almeida Filho wrote: > On Fri, Apr 16, 2021 at 01:24:23PM +0200, Peter Zijlstra wrote: > > int perf_event_task_enable(void) > > { > > + DEFINE_MUTEX_GUARD(event_mutex, ¤t->perf_event_mutex); > > There is nothing in C forcing developers to actually use DEFINE_MUTEX_GUARD. > So > someone may simply forget (or not know that they need) to lock > current->perf_event_mutex and directly access some field protected by it. This > is unlikely to happen when one first writes the code, but over time as > different > people modify the code and invariants change, it is possible for this to > happen. > > In Rust, this isn't possible: the data protected by a lock is only accessible > when the lock is locked. So developers cannot accidentally make mistakes of > this > kind. And since the enforcement happens at compile time, there is no runtime > cost. > > This, we believe, is fundamental to the discussion: we agree that many of > these > idioms can be implemented in C (albeit in this case with a compiler > extension), > but their use is optional, people can (and do) still make mistakes that lead > to > vulnerabilities; Rust disallows classes of mistakes by construction. Does this also not prohibit constructs where modification must be done while holding two locks, but reading can be done while holding either lock? That's a semi common scheme in the kernel, but not something that's expressible by, for example, the Java sync keyword. It also very much doesn't work for RCU, where modification must be done under a lock, but access is done essentially lockless. I would much rather have a language extention where we can associate custom assertions with variable access, sorta like a sanitizer: static inline void assert_foo_bar(struct foo *f) { lockdep_assert_held(&f->lock); } struct foo { spinlock_t lock; int bar __assert__(assert_foo_bar); }; Such things can be optional and only enabled for debug builds on new compilers. > Another scenario: suppose within perf_event_task_enable you need to call a > function that requires the mutex to be locked and that will unlock it for you > on > error (or unconditionally, doesn't matter). How would you do that in C? In > Rust, > there is a clean idiomatic way of transferring ownership of a guard (or any > other object) such that the previous owner cannot continue to use it after > ownership is transferred. Again, this is enforced at compile time. I'm happy > to > provide a small example if that would help. C does indeed not have the concept of ownership, unlike modern C++ I think. But I would much rather see a C language extention for that than go Rust. This would mean a far more agressive push for newer C compilers than we've ever done before, but at least it would all still be a single language. Convertion to the new stuff can be done gradually and where it makes sense and new extentions can be evaluated on performance impact etc.
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 01:24:23PM +0200, Peter Zijlstra wrote: > On Wed, Apr 14, 2021 at 08:45:51PM +0200, oj...@kernel.org wrote: > > - Featureful language: sum types, pattern matching, generics, > > RAII, lifetimes, shared & exclusive references, modules & > > visibility, powerful hygienic and procedural macros... > > IMO RAII is over-valued, but just in case you care, the below seems to > work just fine. No fancy new language needed, works today. Similarly you > can create refcount_t guards, or with a little more work full blown > smart_ptr crud. Peter, we do care, thank you for posting this. It's a great example for us to discuss some of the minutiae of what we think Rust brings to the table in addition to what's already possible in C. > > --- > diff --git a/include/linux/mutex.h b/include/linux/mutex.h > index e19323521f9c..f03a72dd8cea 100644 > --- a/include/linux/mutex.h > +++ b/include/linux/mutex.h > @@ -197,4 +197,22 @@ extern void mutex_unlock(struct mutex *lock); > > extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock); > > +struct mutex_guard { > + struct mutex *mutex; > +}; > + > +static inline struct mutex_guard mutex_guard_lock(struct mutex *mutex) > +{ > + mutex_lock(mutex); > + return (struct mutex_guard){ .mutex = mutex, }; > +} > + > +static inline void mutex_guard_unlock(struct mutex_guard *guard) > +{ > + mutex_unlock(guard->mutex); > +} > + > +#define DEFINE_MUTEX_GUARD(name, lock) \ > + struct mutex_guard __attribute__((__cleanup__(mutex_guard_unlock))) > name = mutex_guard_lock(lock) > + > #endif /* __LINUX_MUTEX_H */ > diff --git a/kernel/events/core.c b/kernel/events/core.c > index 8ee3249de2f0..603d197a83b8 100644 > --- a/kernel/events/core.c > +++ b/kernel/events/core.c > @@ -5715,16 +5715,15 @@ static long perf_compat_ioctl(struct file *file, > unsigned int cmd, > > int perf_event_task_enable(void) > { > + DEFINE_MUTEX_GUARD(event_mutex, ¤t->perf_event_mutex); There is nothing in C forcing developers to actually use DEFINE_MUTEX_GUARD. So someone may simply forget (or not know that they need) to lock current->perf_event_mutex and directly access some field protected by it. This is unlikely to happen when one first writes the code, but over time as different people modify the code and invariants change, it is possible for this to happen. In Rust, this isn't possible: the data protected by a lock is only accessible when the lock is locked. So developers cannot accidentally make mistakes of this kind. And since the enforcement happens at compile time, there is no runtime cost. This, we believe, is fundamental to the discussion: we agree that many of these idioms can be implemented in C (albeit in this case with a compiler extension), but their use is optional, people can (and do) still make mistakes that lead to vulnerabilities; Rust disallows classes of mistakes by construction. Another scenario: suppose within perf_event_task_enable you need to call a function that requires the mutex to be locked and that will unlock it for you on error (or unconditionally, doesn't matter). How would you do that in C? In Rust, there is a clean idiomatic way of transferring ownership of a guard (or any other object) such that the previous owner cannot continue to use it after ownership is transferred. Again, this is enforced at compile time. I'm happy to provide a small example if that would help. Again, thanks for bringing this up. And please keep your concerns and feedback coming, we very much want to have these discussions and try to improve what we have based on feedback from the community. > struct perf_event_context *ctx; > struct perf_event *event; > > - mutex_lock(¤t->perf_event_mutex); > list_for_each_entry(event, ¤t->perf_event_list, owner_entry) { > ctx = perf_event_ctx_lock(event); > perf_event_for_each_child(event, _perf_event_enable); > perf_event_ctx_unlock(event, ctx); > } > - mutex_unlock(¤t->perf_event_mutex); > > return 0; > }
Re: [PATCH 00/13] [RFC] Rust support
On Wed, Apr 14, 2021 at 08:45:51PM +0200, oj...@kernel.org wrote: > - Featureful language: sum types, pattern matching, generics, > RAII, lifetimes, shared & exclusive references, modules & > visibility, powerful hygienic and procedural macros... IMO RAII is over-valued, but just in case you care, the below seems to work just fine. No fancy new language needed, works today. Similarly you can create refcount_t guards, or with a little more work full blown smart_ptr crud. --- diff --git a/include/linux/mutex.h b/include/linux/mutex.h index e19323521f9c..f03a72dd8cea 100644 --- a/include/linux/mutex.h +++ b/include/linux/mutex.h @@ -197,4 +197,22 @@ extern void mutex_unlock(struct mutex *lock); extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock); +struct mutex_guard { + struct mutex *mutex; +}; + +static inline struct mutex_guard mutex_guard_lock(struct mutex *mutex) +{ + mutex_lock(mutex); + return (struct mutex_guard){ .mutex = mutex, }; +} + +static inline void mutex_guard_unlock(struct mutex_guard *guard) +{ + mutex_unlock(guard->mutex); +} + +#define DEFINE_MUTEX_GUARD(name, lock) \ + struct mutex_guard __attribute__((__cleanup__(mutex_guard_unlock))) name = mutex_guard_lock(lock) + #endif /* __LINUX_MUTEX_H */ diff --git a/kernel/events/core.c b/kernel/events/core.c index 8ee3249de2f0..603d197a83b8 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -5715,16 +5715,15 @@ static long perf_compat_ioctl(struct file *file, unsigned int cmd, int perf_event_task_enable(void) { + DEFINE_MUTEX_GUARD(event_mutex, ¤t->perf_event_mutex); struct perf_event_context *ctx; struct perf_event *event; - mutex_lock(¤t->perf_event_mutex); list_for_each_entry(event, ¤t->perf_event_list, owner_entry) { ctx = perf_event_ctx_lock(event); perf_event_for_each_child(event, _perf_event_enable); perf_event_ctx_unlock(event, ctx); } - mutex_unlock(¤t->perf_event_mutex); return 0; }
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 10:16:05AM +0200, Michal Kubecek wrote: > And I don't see how the two languages might coexist peacefully without > rust toolchain being necessary for building any kernel useful in > practice and anyone seriously involved in kernel development having to > be proficient in both languages. Two languages ? No, one is specified and multiple-implemented, the other one is the defined as what its only compiler understands at the moment, so it's not a language, it's a compiler's reference manual at best. I'm waiting for the day you're force to write things which look wrong with a big comment around saying "it's not a bug it's a workaround for a bug in the unique compiler, waiting to be retrofitted into the spec to solve the problem for every user". Already seen for at least another "language" implemented by a single vendor 22 years ago. > Neither of these looks appealing to me. > > The dependency on rust toolchain was exactly what made me give up on > building Firefox from mercurial snapshots few years ago. To be able to > build them, one needed bleeding edge snapshots of rust toolchain which > my distribution couldn't possibly provide and building them myself > required way too much effort. This very discussion already revealed that > rust kernel code would provide similar experience. I also have my doubts > about the "optional" part; once there are some interesting drivers > written in rust, even if only in the form of out of tree modules, there > will be an enormous pressure on distributions, both community and > enterprise, to enable rust support. Yes this scarily looks like the usual "embrace and extend... and abandon the corpse once it doesn't move anymore". I've already faced situations where I couldn't compile a recent 5.x kernel using my previous gcc-4.7 compiler and this really really really pissed me off because I'd had it in a build farm for many architectures and I had to give up. But I also know that updating to a newer version will take time, will be durable and will be worth it for the long term (except for the fact that gcc doubles the build time every two versions). But here having to use *the* compiler of the day and being prepared to keep a collection of them to work with different stable kernels, no! Also, I'm a bit worried about long-term survival of the new language-of-the-day-that-makes-you-look-cool-at-beer-events. I was once told perl would replace C everywhere. Does someone use it outside of checkpatch.pl anymore ? Then I was told that C was dead because PHP was appearing everywhere. I've even seen (slow) log processors written with it. Now PHP seems to only be a WAF-selling argument. Then Ruby was "safe" and would rule them all. Safe as its tab[-1] which crashed the interpreter. Anyone heard of it recently ? Then Python, whose 2.7 is still present on a lot of systems because the forced transition to 3 broke tons of code. Will there ever be a 4 after this sore experience ? Then JS, Rust, Go, Zig and I don't know what. What I'm noting is that such languages appear, serve a purpose well, have their moment of fame, last a decade and disappear except at a few enthousiasts. C has been there for 50 years and served as the basis of many newer languages so it's still well understood. I'm sure about one thing, the C bugs we have today will be fixable in 20 years. I'm not even sure the Rust code we'll merge today will still be compilable in 10 years nor will support the relevant architectures available by then, and probably this code will have to be rewritten in C to become maintained again. > The other problem is even worse. Once we have non-trivial amount of rust > code around the tree, even if it's "just some drivers", you cannot > completely ignore it. One example would be internal API changes. Today, > if I want to touch e.g. ethtool_ops, I need to adjust all in tree NIC > drivers providing the affected callback and adjust them. Usually most of > the patch is generated by spatch but manual tweaks are often needed here > and there. In the world of bilingual kernel with nontrivial number of > NIC drivers written in rust, I don't see how I could do that without > also being proficient in rust. You'll simply change the code you're able to change and those in charge of their driver will use your commit message as instruction to fix the build on theirs. How do you want it to be otherwise ? > Rust enthusiasts tell us they want to > open kernel development to more people but the result could as well be > exactly the opposite: it could restrict kernel development to people > proficient in _both_ languages. This has been my understanding from the very beginning. Language prophets always want to conquier very visible targets as a gauge of their baby's popularity. > As Peter said, it's not an imminent problem but as it's obvious this is > just the first step, we should have a clear idea what the plan is and > what we can and should expect. I think the experience could b
Re: [PATCH 00/13] [RFC] Rust support
On Thu, Apr 15, 2021 at 08:58:16PM +0200, Peter Zijlstra wrote: > > This; can we mercilessly break the .rs bits when refactoring? What > happens the moment we cannot boot x86_64 without Rust crap on? > > We can ignore this as a future problem, but I think it's only fair to > discuss now. I really don't care for that future, and IMO adding this > Rust or any other second language is a fail. I believe this is the most important question and we really need a honest answer in advance: where exactly is this heading? At the moment and with this experimental RFC, rust stuff can be optional and isolated but it's obvious that the plan is very different: to have rust all around the standard kernel tree. (If not, why is the example driver in drivers/char/ ?) And I don't see how the two languages might coexist peacefully without rust toolchain being necessary for building any kernel useful in practice and anyone seriously involved in kernel development having to be proficient in both languages. Neither of these looks appealing to me. The dependency on rust toolchain was exactly what made me give up on building Firefox from mercurial snapshots few years ago. To be able to build them, one needed bleeding edge snapshots of rust toolchain which my distribution couldn't possibly provide and building them myself required way too much effort. This very discussion already revealed that rust kernel code would provide similar experience. I also have my doubts about the "optional" part; once there are some interesting drivers written in rust, even if only in the form of out of tree modules, there will be an enormous pressure on distributions, both community and enterprise, to enable rust support. Once the major distributions do, most others will have to follow. And from what I have seen, you need rust toolchain for build even if you want to only load modules written in rust. The other problem is even worse. Once we have non-trivial amount of rust code around the tree, even if it's "just some drivers", you cannot completely ignore it. One example would be internal API changes. Today, if I want to touch e.g. ethtool_ops, I need to adjust all in tree NIC drivers providing the affected callback and adjust them. Usually most of the patch is generated by spatch but manual tweaks are often needed here and there. In the world of bilingual kernel with nontrivial number of NIC drivers written in rust, I don't see how I could do that without also being proficient in rust. Also, how about maintainers and reviewers? What if someone comes with a new module under foo/ or foo/bar/ and relevant maintainer does not know rust or just not well enough to be able to review the submission properly? Can they simply say "Sorry, I don't speak rust so no rust in foo/bar/"? Leaf drivers are one thing, how about netfilter matches and targets, TCP congestion control algorighms, qdiscs, filesystems, ...? Having kernel tree divided into "rusty" and "rustfree" zones does not sound like a great idea. But if we don't want that, do we expect every subsystem maintainer and reviewer to learn rust to a level sufficient for reviewing rust (kernel) code? Rust enthusiasts tell us they want to open kernel development to more people but the result could as well be exactly the opposite: it could restrict kernel development to people proficient in _both_ languages. As Peter said, it's not an imminent problem but as it's obvious this is just the first step, we should have a clear idea what the plan is and what we can and should expect. Michal
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 06:02:33AM +0100, Wedson Almeida Filho wrote: > On Fri, Apr 16, 2021 at 04:25:34AM +, Al Viro wrote: > > And as one of those freaks I can tell > > you where exactly I would like you to go and what I would like you to do > > with implicit suggestions to start a browser when I need to read some > > in-tree documentation. > > I could be mistaken but you seem angry. Perhaps it wouldn't be a bad idea to > read your own code of conduct, I don't think you need a browser for that > either. Welcome to LKML. CoC does not forbid human emotions just yet. Deal with it.
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 03:22:16AM +0100, Wedson Almeida Filho wrote: > On Thu, Apr 15, 2021 at 08:58:16PM +0200, Peter Zijlstra wrote: > > On Wed, Apr 14, 2021 at 08:45:51PM +0200, oj...@kernel.org wrote: > > > > > Rust is a systems programming language that brings several key > > > advantages over C in the context of the Linux kernel: > > > > > > - No undefined behavior in the safe subset (when unsafe code is > > > sound), including memory safety and the absence of data races. > > > > And yet I see not a single mention of the Rust Memory Model and how it > > aligns (or not) with the LKMM. The C11 memory model for example is a > > really poor fit for LKMM. > > We don't intend to directly expose C data structures to Rust code (outside the > kernel crate). Instead, we intend to provide wrappers that expose safe > interfaces even though the implementation may use unsafe blocks. So we expect > the vast majority of Rust code to just care about the Rust memory model. > > We admittedly don't have a huge number of wrappers yet, but we do have enough > to > implement most of Binder and so far it's been ok. We do intend to eventually > cover other classes of drivers that may unveil unforeseen difficulties, we'll > see. > > If you have concerns that we might have overlooked, we'd be happy to hear > about > them from you (or anyone else). Well, the obvious example would be seqlocks. C11 can't do them. The not sharing of data structures would avoid most of that, but will also cost you in performance. Simlar thing for RCU; C11 can't optimally do that; it needs to make rcu_dereference() a load-acquire [something ARM64 has already done in C because the compiler might be too clever by half when doing LTO :-(]. But it's the compiler needing the acquire semantics, not the computer, which is just bloody wrong. And there's more sharp corners to be had. But yes, if you're not actually sharing anything; and taking the performance hit that comes with that, you might get away with it. > > HTML is not a valid documentation format. Heck, markdown itself is > > barely readable. > > Are you stating [what you perceive as] a fact or just venting? If the former, > would you mind enlightening us with some evidence? I've yet to see a program that renders HTML (including all the cruft often used in docs, which might include SVG graphics and whatnot) sanely in ASCII. Lynx does not qualify, it's output is atrocious crap. Yes, lynx lets you read HTML in ASCII, but at the cost of bleeding eyeballs and missing content. Nothing beats a sane ASCII document with possibly, where really needed some ASCII art. Sadly the whole kernel documentation project is moving away from that as well, which just means I'm back to working on an undocumented codebase. This rst crap they adopted is unreadable garbage. > > It is really *really* hard to read. It has all sorts of weird things, > > like operators at the beginning after a line break: > > > > if (foo > > || bar) > > > > which is just wrong. And it suffers from CamelCase, which is just about > > the worst thing ever. Not even the C++ std libs have that (or had, back > > when I still did knew C++). > > > > I also see: > > > > if (foo) { > > ... > > } > > > > and > > > > if foo { > > } > > > > the latter, ofcourse, being complete rubbish. > > There are advantages to adopting the preferred style of a language (when one > exists). We, of course, are not required to adopt it but I am of the opinion > that we should have good reasons to diverge if that's our choice in the end. > > "Not having parentheses around the if-clause expression is complete rubbish" > doesn't sound like a good reason to me. Of course it does; my internal lexer keeps screaming syntax error at me; how am I going to understand code when I can't sanely read it? The more you make it look like (Kernel) C, the easier it is for us C people to actually read. My eyes have been reading C for almost 30 years by now, they have a lexer built in the optical nerve; reading something that looks vaguely like C but is definitely not C is an utterly painful experience. You're asking to join us, not the other way around. I'm fine in a world without Rust.
Re: [PATCH 00/13] [RFC] Rust support
On Thu, Apr 15, 2021 at 9:27 PM Boqun Feng wrote: > > [Copy LKMM people, Josh, Nick and Wedson] > > On Thu, Apr 15, 2021 at 08:58:16PM +0200, Peter Zijlstra wrote: > > On Wed, Apr 14, 2021 at 08:45:51PM +0200, oj...@kernel.org wrote: > > > > > Rust is a systems programming language that brings several key > > > advantages over C in the context of the Linux kernel: > > > > > > - No undefined behavior in the safe subset (when unsafe code is > > > sound), including memory safety and the absence of data races. > > > > And yet I see not a single mention of the Rust Memory Model and how it > > aligns (or not) with the LKMM. The C11 memory model for example is a > > really poor fit for LKMM. > > > > I think Rust currently uses C11 memory model as per: > > https://doc.rust-lang.org/nomicon/atomics.html > > , also I guess another reason that they pick C11 memory model is because > LLVM has the support by default. > > But I think the Rust Community still wants to have a good memory model, > and they are open to any kind of suggestion and input. I think we (LKMM > people) should really get involved, because the recent discussion on > RISC-V's atomics shows that if we didn't people might get a "broken" > design because they thought C11 memory model is good enough: > > https://lore.kernel.org/lkml/YGyZPCxJYGOvqYZQ@boqun-archlinux/ > > And the benefits are mutual: a) Linux Kernel Memory Model (LKMM) is > defined by combining the requirements of developers and the behavior of > hardwares, it's pratical and can be a very good input for memory model > designing in Rust; b) Once Rust has a better memory model, the compiler > technologies whatever Rust compilers use to suppor the memory model can > be adopted to C compilers and we can get that part for free. Yes, I agree; I think that's a very good approach. Avoiding the ISO WG14 is interesting; at least the merits could be debated in the public and not behind closed doors. > > At least I personally is very intereted to help Rust on a complete and > pratical memory model ;-) > > Josh, I think it's good if we can connect to the people working on Rust > memoryg model, I think the right person is Ralf Jung and the right place > is https://github.com/rust-lang/unsafe-code-guidelines, but you > cerntainly know better than me ;-) Or maybe we can use Rust-for-Linux or > linux-toolchains list to discuss. > > [...] > > > - Boqun Feng is working hard on the different options for > > > threading abstractions and has reviewed most of the `sync` PRs. > > > > Boqun, I know you're familiar with LKMM, can you please talk about how > > Rust does things and how it interacts? > > As Wedson said in the other email, currently there is no code requiring > synchronization between C side and Rust side, so we are currently fine. > But in the longer term, we need to teach Rust memory model about the > "design patterns" used in Linux kernel for parallel programming. > > What I have been doing so far is reviewing patches which have memory > orderings in Rust-for-Linux project, try to make sure we don't include > memory ordering bugs for the beginning. > > Regards, > Boqun -- Thanks, ~Nick Desaulniers
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 06:02:33 +0100, Wedson Almeida Filho wrote: > On Fri, Apr 16, 2021 at 04:25:34AM +, Al Viro wrote: > >>> Are you stating [what you perceive as] a fact or just venting? If the >>> former, >>> would you mind enlightening us with some evidence? >> >> How about "not everyone uses a browser as a part of their workflow"? > > The documentation is available in markdown alongside the code. You don't need > a > browser to see it. I, for one, use neovim and a rust LSP, so I can see the > documentation by pressing shift+k. > >> I realize that it might sound ridiculous for folks who spent a while >> around Mozilla, but it's really true and kernel community actually >> has quite a few of such freaks. > > I haven't spent any time around Mozilla myself (not that there's anything > wrong > with it), so I can't really comment on this. > >> And as one of those freaks I can tell >> you where exactly I would like you to go and what I would like you to do >> with implicit suggestions to start a browser when I need to read some >> in-tree documentation. > > I could be mistaken but you seem angry. Perhaps it wouldn't be a bad idea to > read your own code of conduct, I don't think you need a browser for that > either. Haven't you folks ever head of lynx? Good old-fashioned command-line tool that opens html files in a terminal window, supports following links within the file, good stuff like that. I don't see how the dinosaurs^W traditional folks could object to that! -- Paul
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 04:25:34AM +, Al Viro wrote: > > Are you stating [what you perceive as] a fact or just venting? If the > > former, > > would you mind enlightening us with some evidence? > > How about "not everyone uses a browser as a part of their workflow"? The documentation is available in markdown alongside the code. You don't need a browser to see it. I, for one, use neovim and a rust LSP, so I can see the documentation by pressing shift+k. > I realize that it might sound ridiculous for folks who spent a while > around Mozilla, but it's really true and kernel community actually > has quite a few of such freaks. I haven't spent any time around Mozilla myself (not that there's anything wrong with it), so I can't really comment on this. > And as one of those freaks I can tell > you where exactly I would like you to go and what I would like you to do > with implicit suggestions to start a browser when I need to read some > in-tree documentation. I could be mistaken but you seem angry. Perhaps it wouldn't be a bad idea to read your own code of conduct, I don't think you need a browser for that either.
Re: [PATCH 00/13] [RFC] Rust support
[Copy LKMM people, Josh, Nick and Wedson] On Thu, Apr 15, 2021 at 08:58:16PM +0200, Peter Zijlstra wrote: > On Wed, Apr 14, 2021 at 08:45:51PM +0200, oj...@kernel.org wrote: > > > Rust is a systems programming language that brings several key > > advantages over C in the context of the Linux kernel: > > > > - No undefined behavior in the safe subset (when unsafe code is > > sound), including memory safety and the absence of data races. > > And yet I see not a single mention of the Rust Memory Model and how it > aligns (or not) with the LKMM. The C11 memory model for example is a > really poor fit for LKMM. > I think Rust currently uses C11 memory model as per: https://doc.rust-lang.org/nomicon/atomics.html , also I guess another reason that they pick C11 memory model is because LLVM has the support by default. But I think the Rust Community still wants to have a good memory model, and they are open to any kind of suggestion and input. I think we (LKMM people) should really get involved, because the recent discussion on RISC-V's atomics shows that if we didn't people might get a "broken" design because they thought C11 memory model is good enough: https://lore.kernel.org/lkml/YGyZPCxJYGOvqYZQ@boqun-archlinux/ And the benefits are mutual: a) Linux Kernel Memory Model (LKMM) is defined by combining the requirements of developers and the behavior of hardwares, it's pratical and can be a very good input for memory model designing in Rust; b) Once Rust has a better memory model, the compiler technologies whatever Rust compilers use to suppor the memory model can be adopted to C compilers and we can get that part for free. At least I personally is very intereted to help Rust on a complete and pratical memory model ;-) Josh, I think it's good if we can connect to the people working on Rust memoryg model, I think the right person is Ralf Jung and the right place is https://github.com/rust-lang/unsafe-code-guidelines, but you cerntainly know better than me ;-) Or maybe we can use Rust-for-Linux or linux-toolchains list to discuss. [...] > > - Boqun Feng is working hard on the different options for > > threading abstractions and has reviewed most of the `sync` PRs. > > Boqun, I know you're familiar with LKMM, can you please talk about how > Rust does things and how it interacts? As Wedson said in the other email, currently there is no code requiring synchronization between C side and Rust side, so we are currently fine. But in the longer term, we need to teach Rust memory model about the "design patterns" used in Linux kernel for parallel programming. What I have been doing so far is reviewing patches which have memory orderings in Rust-for-Linux project, try to make sure we don't include memory ordering bugs for the beginning. Regards, Boqun
Re: [PATCH 00/13] [RFC] Rust support
On Fri, Apr 16, 2021 at 03:22:16AM +0100, Wedson Almeida Filho wrote: > > HTML is not a valid documentation format. Heck, markdown itself is > > barely readable. > > Are you stating [what you perceive as] a fact or just venting? If the former, > would you mind enlightening us with some evidence? How about "not everyone uses a browser as a part of their workflow"? I realize that it might sound ridiculous for folks who spent a while around Mozilla, but it's really true and kernel community actually has quite a few of such freaks. And as one of those freaks I can tell you where exactly I would like you to go and what I would like you to do with implicit suggestions to start a browser when I need to read some in-tree documentation. Linus might have different reasons, obviously.
Re: [PATCH 00/13] [RFC] Rust support
On Thu, Apr 15, 2021 at 08:58:16PM +0200, Peter Zijlstra wrote: > On Wed, Apr 14, 2021 at 08:45:51PM +0200, oj...@kernel.org wrote: > > > Rust is a systems programming language that brings several key > > advantages over C in the context of the Linux kernel: > > > > - No undefined behavior in the safe subset (when unsafe code is > > sound), including memory safety and the absence of data races. > > And yet I see not a single mention of the Rust Memory Model and how it > aligns (or not) with the LKMM. The C11 memory model for example is a > really poor fit for LKMM. We don't intend to directly expose C data structures to Rust code (outside the kernel crate). Instead, we intend to provide wrappers that expose safe interfaces even though the implementation may use unsafe blocks. So we expect the vast majority of Rust code to just care about the Rust memory model. We admittedly don't have a huge number of wrappers yet, but we do have enough to implement most of Binder and so far it's been ok. We do intend to eventually cover other classes of drivers that may unveil unforeseen difficulties, we'll see. If you have concerns that we might have overlooked, we'd be happy to hear about them from you (or anyone else). > HTML is not a valid documentation format. Heck, markdown itself is > barely readable. Are you stating [what you perceive as] a fact or just venting? If the former, would you mind enlightening us with some evidence? > It is really *really* hard to read. It has all sorts of weird things, > like operators at the beginning after a line break: > > if (foo > || bar) > > which is just wrong. And it suffers from CamelCase, which is just about > the worst thing ever. Not even the C++ std libs have that (or had, back > when I still did knew C++). > > I also see: > > if (foo) { > ... > } > > and > > if foo { > } > > the latter, ofcourse, being complete rubbish. There are advantages to adopting the preferred style of a language (when one exists). We, of course, are not required to adopt it but I am of the opinion that we should have good reasons to diverge if that's our choice in the end. "Not having parentheses around the if-clause expression is complete rubbish" doesn't sound like a good reason to me.
Re: [PATCH 00/13] [RFC] Rust support
On Wed, Apr 14, 2021 at 08:45:51PM +0200, oj...@kernel.org wrote: > Rust is a systems programming language that brings several key > advantages over C in the context of the Linux kernel: > > - No undefined behavior in the safe subset (when unsafe code is > sound), including memory safety and the absence of data races. And yet I see not a single mention of the Rust Memory Model and how it aligns (or not) with the LKMM. The C11 memory model for example is a really poor fit for LKMM. > ## Why not? > > Rust also has disadvantages compared to C in the context of > the Linux kernel: > > - The many years of effort in tooling for C around the kernel, > including compiler plugins, sanitizers, Coccinelle, lockdep, > sparse... However, this will likely improve if Rust usage in > the kernel grows over time. This; can we mercilessly break the .rs bits when refactoring? What happens the moment we cannot boot x86_64 without Rust crap on? We can ignore this as a future problem, but I think it's only fair to discuss now. I really don't care for that future, and IMO adding this Rust or any other second language is a fail. > Thirdly, in Rust code bases, most documentation is written alongside > the source code, in Markdown. We follow this convention, thus while > we have a few general documents in `Documentation/rust/`, most of > the actual documentation is in the source code itself. > > In order to read this documentation easily, Rust provides a tool > to generate HTML documentation, just like Sphinx/kernel-doc, but > suited to Rust code bases and the language concepts. HTML is not a valid documentation format. Heck, markdown itself is barely readable. > Moreover, as explained above, we are taking the chance to enforce > some documentation guidelines. We are also enforcing automatic code > formatting, a set of Clippy lints, etc. We decided to go with Rust's > idiomatic style, i.e. keeping `rustfmt` defaults. For instance, this > means 4 spaces are used for indentation, rather than a tab. We are > happy to change that if needed -- we think what is important is > keeping the formatting automated. It is really *really* hard to read. It has all sorts of weird things, like operators at the beginning after a line break: if (foo || bar) which is just wrong. And it suffers from CamelCase, which is just about the worst thing ever. Not even the C++ std libs have that (or had, back when I still did knew C++). I also see: if (foo) { ... } and if foo { } the latter, ofcourse, being complete rubbish. > Another important topic we would like feedback on is the Rust > "native" documentation that is written alongside the code, as > explained above. We have uploaded it here: > > https://rust-for-linux.github.io/docs/kernel/ > > We like how this kind of generated documentation looks. Please take > a look and let us know what you think! I cannot view with less or vim. Therefore it looks not at all. > - Boqun Feng is working hard on the different options for > threading abstractions and has reviewed most of the `sync` PRs. Boqun, I know you're familiar with LKMM, can you please talk about how Rust does things and how it interacts?
Re: [PATCH 00/13] [RFC] Rust support
On Thu, Apr 15, 2021 at 08:26:21AM +, David Laight wrote: > ... > > Besides just FP, 128-bit, etc, I remain concerned about just basic > > math operations. C has no way to describe the intent of integer > > overflow, so the kernel was left with the only "predictable" result: > > wrap around. Unfortunately, this is wrong in most cases, and we're left > > with entire classes of vulnerability related to such overflows. > > I'm not sure any of the alternatives (except perhaps panic) > are much better. > Many years ago I used a COBOL system that skipped the assignment > if ADD X to Y (y += x) would overflow. > That gave a very hard to spot error when the sump of a long list > way a little too large. > If it had wrapped the error would be obvious. > > There are certainly places where saturate is good. > Mostly when dealing with analogue samples. > > I guess the problematic code is stuff that checks: > if (foo->size + constant > limit) goto error; > instead of: > if (foo->size > limit - constant) goto error; Right. This and alloc(size * count) are the primary offenders. :) -- Kees Cook
Re: [PATCH 00/13] [RFC] Rust support
On Thu, Apr 15, 2021 at 3:38 AM Kees Cook wrote: > > Before anything else: yay! I'm really glad to see this RFC officially > hit LKML. :) Thanks! :) > When originally learning Rust I was disappointed to see that (by default) > Rust similarly ignores the overflow problem, but I'm glad to see the > very intentional choices in the Rust-in-Linux design to deal with it > directly. I think the default behavior should be saturate-with-WARN > (this will match the ultimate goals of the UBSAN overflow support[1][2] > in the C portions of the kernel). Rust code wanting wrapping/checking > can expressly use those. The list of exploitable overflows is lng, > and this will remain a weakness in Rust unless we get it right from > the start. What's not clear to me is if it's better to say "math with > undeclared overflow expectation" will saturate" or to say "all math must > declare its overflow expectation". +1 Agreed, we need to get this right (and ideally make both the C and Rust sides agree...). Cheers, Miguel
Re: [PATCH 00/13] [RFC] Rust support
On Thu, Apr 15, 2021 at 2:23 AM Nick Desaulniers wrote: > > Looks like Wedson's writeup is now live. Nice job Wedson! > https://security.googleblog.com/2021/04/rust-in-linux-kernel.html +1 It is very nicely written and explains the semaphore samples (included in the RFC) he wrote, with nice tables comparing how different parts look like between C and Rust! Anyone interested in this RFC, C or Rust, please take a look! Cheers, Miguel
RE: [PATCH 00/13] [RFC] Rust support
... > Besides just FP, 128-bit, etc, I remain concerned about just basic > math operations. C has no way to describe the intent of integer > overflow, so the kernel was left with the only "predictable" result: > wrap around. Unfortunately, this is wrong in most cases, and we're left > with entire classes of vulnerability related to such overflows. I'm not sure any of the alternatives (except perhaps panic) are much better. Many years ago I used a COBOL system that skipped the assignment if ADD X to Y (y += x) would overflow. That gave a very hard to spot error when the sump of a long list way a little too large. If it had wrapped the error would be obvious. There are certainly places where saturate is good. Mostly when dealing with analogue samples. I guess the problematic code is stuff that checks: if (foo->size + constant > limit) goto error; instead of: if (foo->size > limit - constant) goto error; David - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Re: [PATCH 00/13] [RFC] Rust support
Before anything else: yay! I'm really glad to see this RFC officially hit LKML. :) On Wed, Apr 14, 2021 at 10:20:51PM +0200, Miguel Ojeda wrote: > - On floating-point, 128-bit, etc.: the main issue is that the > `core` library is a single big blob at the moment. I have already > mentioned this to some Rust team folks. We will need a way to "cut" > some things out, for instance with the "feature flags" they already > have for other crates (or they can split `core` in to several, like > `alloc` is for similar reasons). Or we could do it on our side > somehow, but I prefer to avoid that (we cannot easily customize `core` > like we can with `alloc`, because it is tied to the compiler too > tightly). Besides just FP, 128-bit, etc, I remain concerned about just basic math operations. C has no way to describe the intent of integer overflow, so the kernel was left with the only "predictable" result: wrap around. Unfortunately, this is wrong in most cases, and we're left with entire classes of vulnerability related to such overflows. When originally learning Rust I was disappointed to see that (by default) Rust similarly ignores the overflow problem, but I'm glad to see the very intentional choices in the Rust-in-Linux design to deal with it directly. I think the default behavior should be saturate-with-WARN (this will match the ultimate goals of the UBSAN overflow support[1][2] in the C portions of the kernel). Rust code wanting wrapping/checking can expressly use those. The list of exploitable overflows is lng, and this will remain a weakness in Rust unless we get it right from the start. What's not clear to me is if it's better to say "math with undeclared overflow expectation" will saturate" or to say "all math must declare its overflow expectation". -Kees [1] https://github.com/KSPP/linux/issues/26 [2] https://github.com/KSPP/linux/issues/27 -- Kees Cook
Re: [PATCH 00/13] [RFC] Rust support
On Wed, Apr 14, 2021 at 11:47 AM wrote: > > From: Miguel Ojeda > > Some of you have noticed the past few weeks and months that > a serious attempt to bring a second language to the kernel was > being forged. We are finally here, with an RFC that adds support > for Rust to the Linux kernel. > > This cover letter is fairly long, since there are quite a few topics > to describe, but I hope it answers as many questions as possible > before the discussion starts. > > If you are interested in following this effort, please join us > in the mailing list at: > > rust-for-li...@vger.kernel.org > > and take a look at the project itself at: > > https://github.com/Rust-for-Linux Looks like Wedson's writeup is now live. Nice job Wedson! https://security.googleblog.com/2021/04/rust-in-linux-kernel.html -- Thanks, ~Nick Desaulniers
RE: [PATCH 00/13] [RFC] Rust support
From: Linus Torvalds > Sent: 14 April 2021 21:22 > > On Wed, Apr 14, 2021 at 1:10 PM Matthew Wilcox wrote: > > > > There's a philosophical point to be discussed here which you're skating > > right over! Should rust-in-the-linux-kernel provide the same memory > > allocation APIs as the rust-standard-library, or should it provide a Rusty > > API to the standard-linux-memory-allocation APIs? > > Yeah, I think that the standard Rust API may simply not be acceptable > inside the kernel, if it has similar behavior to the (completely > broken) C++ "new" operator. ISTM that having memory allocation failure cause a user process to exit is a complete failure in something designed to run as and kind of service program. There are all sorts of reasons why malloc() might fail. You almost never want a 'real' program to abort on one. David - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Re: [PATCH 00/13] [RFC] Rust support
On Wed, Apr 14, 2021 at 01:21:52PM -0700, Linus Torvalds wrote: > On Wed, Apr 14, 2021 at 1:10 PM Matthew Wilcox wrote: > > > > There's a philosophical point to be discussed here which you're skating > > right over! Should rust-in-the-linux-kernel provide the same memory > > allocation APIs as the rust-standard-library, or should it provide a Rusty > > API to the standard-linux-memory-allocation APIs? > > Yeah, I think that the standard Rust API may simply not be acceptable > inside the kernel, if it has similar behavior to the (completely > broken) C++ "new" operator. > > So anything that does "panic!" in the normal Rust API model needs to > be (statically) caught, and never exposed as an actual call to > "panic()/BUG()" in the kernel. Rust has both kinds of allocation APIs: you can call a method like `Box::new` that panics on allocation failure, or a method like `Box::try_new` that returns an error on allocation failure. With some additional infrastructure that's still in progress, we could just not supply the former kind of methods at all, and *only* supply the latter, so that you're forced to handle allocation failure. That just requires introducing some further ability to customize the Rust standard library. (There are some cases of methods in the standard library that don't have a `try_` equivalent, but we could fix that. Right now, for instance, there isn't a `try_` equivalent of every Vec method, and you're instead expected to call `try_reserve` to make sure you have enough memory first; however, that could potentially be changed.)
Re: [PATCH 00/13] [RFC] Rust support
On Wed, Apr 14, 2021 at 10:10 PM Matthew Wilcox wrote: > > On Wed, Apr 14, 2021 at 08:45:51PM +0200, oj...@kernel.org wrote: > > - Manish Goregaokar implemented the fallible `Box`, `Arc`, and `Rc` > > allocator APIs in Rust's `alloc` standard library for us. > > There's a philosophical point to be discussed here which you're skating > right over! Should rust-in-the-linux-kernel provide the same memory > allocation APIs as the rust-standard-library, or should it provide a Rusty > API to the standard-linux-memory-allocation APIs? You seem to be doing > both ... there was a wrapper around alloc_pages() in the Binder patches, > and then you talk about Box, Arc and Rc here. Please see my reply to Linus. The Rust standard library team is doing work on allocators, fallible allocations, etc., but that is very much a WIP. We hope that our usage and needs inform them in their design. Manish Goregaokar implemented the `try_reserve` feature since he knew we wanted to have fallible allocations etc. (I was not really involved in that, perhaps somebody else can comment); but we will have to replace `alloc` anyway in the near feature, and we wanted to give Manish credit for advancing the state of the art there nevertheless. > Maybe there's some details about when one can use one kind of API and > when to use another. But I fear that we'll have Rust code at interrupt > level trying to use allocators which assume that they can sleep, and > things will go badly wrong. Definitely. In fact, we want to have all public functions exposed by Rust infrastructure tagged with the context they can work in, etc. Ideally, we could propose a language feature like "colored `unsafe`" so that one can actually inform the compiler that a function is only safe in some contexts, e.g. `unsafe(interrupt)`. But language features are a moonshot, for the moment we want to go with the annotation in the doc-comment, like we do with the `Safety` preconditions and type invariants. Cheers, Miguel
Re: [PATCH 00/13] [RFC] Rust support
On Wed, Apr 14, 2021 at 1:10 PM Matthew Wilcox wrote: > > There's a philosophical point to be discussed here which you're skating > right over! Should rust-in-the-linux-kernel provide the same memory > allocation APIs as the rust-standard-library, or should it provide a Rusty > API to the standard-linux-memory-allocation APIs? Yeah, I think that the standard Rust API may simply not be acceptable inside the kernel, if it has similar behavior to the (completely broken) C++ "new" operator. So anything that does "panic!" in the normal Rust API model needs to be (statically) caught, and never exposed as an actual call to "panic()/BUG()" in the kernel. So "Result" is basically the way to go, and if the standard Rust library alloc() model is based on "panic!" then that kind of model must simply not be used in the kernel. Linus Linus
Re: [PATCH 00/13] [RFC] Rust support
On Wed, Apr 14, 2021 at 9:45 PM Linus Torvalds wrote: > > With the main point of Rust being safety, there is no way I will ever > accept "panic dynamically" (whether due to out-of-memory or due to > anything else - I also reacted to the "floating point use causes > dynamic panics") as a feature in the Rust model. Agreed on all your points. As I mentioned in the other message (we crossed emails), we have a lot of work to do regarding `alloc` and slicing `core` for things that are not needed for the kernel (floating-point, etc.). We haven't done it just yet because it is not a trivial amount of work and we wanted to have some overall sentiment from you and the community overall before tackling everything. But it is doable and there isn't any fundamental reason that prevents it (in fact, the language supports no-allocation code). Worst case, we may need to request a few bits here and there to the `rustc` and standard library teams, but that should be about it. In summary, to be clear: - On allocation: this is just our usage of `alloc` in order to speed development up -- it will be replaced (or customized, we have to decide how we will approach it) with our own allocation and data structures. - On floating-point, 128-bit, etc.: the main issue is that the `core` library is a single big blob at the moment. I have already mentioned this to some Rust team folks. We will need a way to "cut" some things out, for instance with the "feature flags" they already have for other crates (or they can split `core` in to several, like `alloc` is for similar reasons). Or we could do it on our side somehow, but I prefer to avoid that (we cannot easily customize `core` like we can with `alloc`, because it is tied to the compiler too tightly). Thanks a lot for having taken a look so quickly, by the way! Cheers, Miguel
Re: [PATCH 00/13] [RFC] Rust support
On Wed, Apr 14, 2021 at 08:45:51PM +0200, oj...@kernel.org wrote: > - Manish Goregaokar implemented the fallible `Box`, `Arc`, and `Rc` > allocator APIs in Rust's `alloc` standard library for us. There's a philosophical point to be discussed here which you're skating right over! Should rust-in-the-linux-kernel provide the same memory allocation APIs as the rust-standard-library, or should it provide a Rusty API to the standard-linux-memory-allocation APIs? You seem to be doing both ... there was a wrapper around alloc_pages() in the Binder patches, and then you talk about Box, Arc and Rc here. Maybe there's some details about when one can use one kind of API and when to use another. But I fear that we'll have Rust code at interrupt level trying to use allocators which assume that they can sleep, and things will go badly wrong. By the way, I don't think that Rust necessarily has to conform to the current way that Linux works. If this prompted us to track the current context (inside spinlock, handling interrupt, performing writeback, etc) and do away with (some) GFP flags, that's not the end of the world. We're already moving in that direction to a certain extent with the scoped memory allocation APIs to replace GFP_NOFS / GFP_NOIO.
Re: [PATCH 00/13] [RFC] Rust support
On Wed, Apr 14, 2021 at 11:46 AM wrote: > > Some of you have noticed the past few weeks and months that > a serious attempt to bring a second language to the kernel was > being forged. We are finally here, with an RFC that adds support > for Rust to the Linux kernel. So I replied with my reactions to a couple of the individual patches, but on the whole I don't hate it. HOWEVER. I do think that the "run-time failure panic" is a fundamental issue. I may not understand the ramifications of when it can happen, so maybe it's less of an issue than I think it is, but very fundamentally I think that if some Rust allocation can cause a panic, this is simply _fundamentally_ not acceptable. Allocation failures in a driver or non-core code - and that is by definition all of any new Rust code - can never EVER validly cause panics. Same goes for "oh, some case I didn't test used 128-bit integers or floating point". So if the Rust compiler causes hidden allocations that cannot be caught and returned as errors, then I seriously think that this whole approach needs to be entirely NAK'ed, and the Rust infrastructure - whether at the compiler level or in the kernel wrappers - needs more work. So if the panic was just some placeholder for things that _can_ be caught, then I think that catching code absolutely needs to be written, and not left as a to-do. And if the panic situation is some fundamental "this is what the Rust compiler does for internal allocation failures", then I think it needs more than just kernel wrapper work - it needs the Rust compiler to be *fixed*. Because kernel code is different from random user-space system tools. Running out of memory simply MUST NOT cause an abort. It needs to just result in an error return. I don't know enough about how the out-of-memory situations would be triggered and caught to actually know whether this is a fundamental problem or not, so my reaction comes from ignorance, but basically the rule has to be that there are absolutely zero run-time "panic()" calls. Unsafe code has to either be caught at compile time, or it has to be handled dynamically as just a regular error. With the main point of Rust being safety, there is no way I will ever accept "panic dynamically" (whether due to out-of-memory or due to anything else - I also reacted to the "floating point use causes dynamic panics") as a feature in the Rust model. Linus
[PATCH 00/13] [RFC] Rust support
From: Miguel Ojeda Some of you have noticed the past few weeks and months that a serious attempt to bring a second language to the kernel was being forged. We are finally here, with an RFC that adds support for Rust to the Linux kernel. This cover letter is fairly long, since there are quite a few topics to describe, but I hope it answers as many questions as possible before the discussion starts. If you are interested in following this effort, please join us in the mailing list at: rust-for-li...@vger.kernel.org and take a look at the project itself at: https://github.com/Rust-for-Linux Cheers, Miguel # A second language in the kernel We know there are huge costs and risks in introducing a new main language in the kernel. We risk dividing efforts and we increase the knowledge required to contribute to some parts of the kernel. Most importantly, any new language introduced means any module written in that language will be way harder to replace later on if the support for the new language gets dropped. Nevertheless, we believe that, even today, the advantages of using Rust outweighs the cost. We will explain why in the following sections. Please note that the Rust support is intended to enable writing drivers and similar "leaf" modules in Rust, at least for the foreseeable future. In particular, we do not intend to rewrite the kernel core nor the major kernel subsystems (e.g. `kernel/`, `mm/`, `sched/`...). Instead, the Rust support is built on top of those. ## Goals By using Rust in the Linux kernel, our hope is that: - New code written in Rust has a reduced risk of memory safety bugs, data races and logic bugs overall, thanks to the language properties mentioned below. - Maintainers are more confident in refactoring and accepting patches for modules thanks to the safe subset of Rust. - New drivers and modules become easier to write, thanks to abstractions that are easier to reason about, based on modern language features, as well as backed by detailed documentation. - More people get involved overall in developing the kernel thanks to the usage of a modern language. - By taking advantage of Rust tooling, we keep enforcing the documentation guidelines we have established so far in the project. For instance, we require having all public APIs, safety preconditions, `unsafe` blocks and type invariants documented. ## Why Rust? Rust is a systems programming language that brings several key advantages over C in the context of the Linux kernel: - No undefined behavior in the safe subset (when unsafe code is sound), including memory safety and the absence of data races. - Stricter type system for further reduction of logic errors. - A clear distinction between safe and `unsafe` code. - Featureful language: sum types, pattern matching, generics, RAII, lifetimes, shared & exclusive references, modules & visibility, powerful hygienic and procedural macros... - Extensive freestanding standard library: vocabulary types such as `Result` and `Option`, iterators, formatting, pinning, checked/saturating/wrapping integer arithmetic, etc. - Integrated out of the box tooling: documentation generator, formatter and linter all based on the compiler itself. Overall, Rust is a language that has successfully leveraged decades of experience from system programming languages as well as functional ones, and added lifetimes and borrow checking on top. ## Why not? Rust also has disadvantages compared to C in the context of the Linux kernel: - The many years of effort in tooling for C around the kernel, including compiler plugins, sanitizers, Coccinelle, lockdep, sparse... However, this will likely improve if Rust usage in the kernel grows over time. - Single implementation based on LLVM. There are third-party efforts underway to fix this, such as a GCC frontend, a `rustc` backend based on Cranelift and `mrustc`, a compiler intended to reduce the bootstrapping chain. Any help for those projects would be very welcome! - Not standardized. While it is not clear whether standardization would be beneficial for the kernel, several points minimize this issue in any case: the Rust stability promise, the extensive documentation, the WIP reference, the detailed RFCs... - Slower compilation in general, due to more complex language features and limitations in the current compiler. - At the present time, we require certain nightly features. That is, features that are not available in the stable compiler. Nevertheless, we aim to remove this restriction within a year by either `rustc` landing the features in stable or removing our usage of them otherwise. We maintain a report here: https://github.com/Rust-for-Linux/linux/issues/2 - Bigger than needed text currently, due to the unused parts from the `core` and `alloc` Rust standard librarie