4 ms·
This is probably the biggest issue with Rust in the kernel; because it needs to deal with a lot of existing kernel interfaces and abstractions, you get code whi
by lambda 5y ago
This is probably the biggest issue with Rust in the kernel; because it needs to deal with a lot of existing kernel interfaces and abstractions, you get code which is neither very idiomatic Rust, nor is terribly recognizable to someone who knows the kernel abstractions fairly well.
Now, some of that is just a matter of learning curve; once you have learned the Rust-in-Linux abstractions the above will probably be somewhat more readable.
Coming from someone who's more familiar with Rust, and less so with the kernel, here are a few notes.
* It might not be the best idea to post the example drivers with inferred types, for this familiarization reason. While there are a few types (such as those involving closures) that you can't write and can only use via type inference, or others that are too large to want to write out, these types should be fairly easy to write and it would improve readability during the familiarization process
* A lot of these things that you were having trouble with look like they are basically just dereferencing and accessing some data contained within the spinlock, and casting what is only guaranteed by the API to be an immutable (shared) reference into a mutable (unique) reference in an `unsafe` block. This is a place where trying to use simple Rust wrappers over core kernel structures which weren't designed for Rust makes things a bit more difficult to read, as you need to do a bit of an unidiomatic dance to tell the compiler "yes, the language and type don't gurantee uniqueness, but I promise this reference is unique and I won't misuse it."
* One of the small little humps to get over when learning Rust is to learn that "mut" actually means "unique", and unmarked (immutable) references means "potentially shared." But since you do need to sometimes write to objects that are potentially shared, it just means that you need to either guarantee yourself or use some kind of synchronization mechanism to ensure that at any given moment of time that data is only mutable in one place at a time.
So, I don't know the details of these APIs myself, but when I look at this here's what I see
* we're constructing some device data object protected by a spinlock
* we're providing some brief justification for why this particular usage is safe, since the API and compiler can't guarantee that it's safe
* we're extracting a mutable reference from it, for which we need to uphold the single exclusive access principle without assistance from the compiler
* we're wrapping that in a new reference to device data type which presumably provides a more idiomatic interface than what the raw primitives provide
I'm guessing that the following code which actually uses this Ref::<DeviceData> object will then be a bit more readable and require fewer uses of unsafe, as it looks like this code is what is providing that translation between some core kernel primitives which are not terribly idiomatic to use in Rust and a safer, more idiomatic wrapper.
- afiori 5y ago> It might not be the best idea to post the example drivers with inferred types, a `cargo fmt` option to add inferred types to the source code would have some advantages for that.