> unless every callsite that locks any item always locks the big global lock first (probably not true, because if you serialize all item access on a global lock then a per-item lock serves no purpose...)
A pattern I've definitely both seen and used is
let guard1 = datastructure_containing_the_whole_world.lock();
let guard2 = guard1.subset_of_that_datastructure.lock();
guard1.unlock();
// Do expensive work
guard2.unlock();
Which works to parallelize work so long as guard2 isn't contended... and at least ensures correctness and forward progress the rest of the time.