Offend? Pshaw. "Nothing
personal, it's just ones and zeroes."
Definitely you're going to get your libraries ship-shape first. If you're mixing apples and oranges in the same basket then it will be pragmatically impossible to figure anything out. As of course we all know. You don't say if these are
your libraries or not. If they are, then I trust that you are using version-control
in which case you can look back through the source-code modifications since the "last known-good" point. Or maybe you can just start by re-building everything. Also make very sure that you know which libraries and which versions thereof
are, actually being referenced by the code. (Any possible source of uncertainty you can think of ... chase it down, answer it, and
prove that you have the right answer.)
We can exclude the kernel from consideration because, if mutex locking was not working properly,
nothing in the system would work ... the darned thing would have crashed into a kernel-panic long before now. The semantics of the kernel do change from time to time,
e.g. across major-release boundaries, but fundamental interfaces do tend to remain stable, and mutual-exclusion is just about as "fundamental" as it gets.
Therefore, it is going to be an issue with user-land application code. I'd look very closely at the guts of whatever user-land libraries are used to access your driver. Many bugs like this can masquerade as what you
think they are. (For example, what if the return-code really is nonzero, but the calling-sequence is busted such that your app always sees zero? You need to be able to, among other things,
prove that you know what the return-code should be (tracing the value all the way from its origin to the point where it is given to userland),
and then also prove that the application-side code always comes up with the correct answer in
every single case.