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<X>, y: SpinLock<Y>, 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