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, ojeda@xxxxxxxxxx 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