Sometimes these requirements were reasonable, just unwritten. Sometimes they were a bit too flexible/wild and I had to make some opinionated decisions when writing the Rust abstractions to narrow it down to a safe usage.
Sometimes I had to add extra locking inside the abstraction in order to make it practical to make safe. Sometimes I had to make some small changes to the C side to make it more orthogonal or logical and usable, e.g. to expose an unlocked function to be used with a lock taken.
Sometimes the locking was subtle enough that while I was able to write a safe Rust abstraction, it came with a big doc comment explaining how you have to be careful with usage and drop order to avoid deadlocks (deadlocks are "safe", Rust doesn't inherently protect against them).
Sometimes it was a lost cause without making the C side more reasonable (drm_sched only, really).
However, most of the time the compromises made when writing the Rust abstraction point at issues with the C side design and how it could be improved.
In general the approach is "write the Rust side making as few changes to the C side first to avoid conflict, then maybe propose changes to the C side based on lessons learned" (we haven't really gotten to the second part yet at all).