The problem is that g_access() must be called with the GEOM topology lock held.
And that gives a false impression that the lock is indeed held across the call.
But this isn't always true because many classes, ZVOL being one of the many,
need to drop the lock. It's either to perform an I/O on the first open or to
acquire a different lock (like in g_mirror_access).
That, of course, can break many assumptions. For example, g_slice_access()
adds an extra exclusive count on the first open. As described above, an
underlying geom may drop the topology lock and that would open a race with
another thread that would also request another extra exclusive count.
In general, two consumers may be granted incompatible accesses.
To avoid this problem the code is changed to mark a geom with special flag before
calling its access method and clear the flag afterwards.
If another thread sees that flag, then it means that the topology lock has been dropped
(either by the geom in question or downstream from it), so it is not safe to make another access call.
So, the second thread would use g_topology_sleep() to wait until the flag is cleared
and only then would it proceed with the access.
P.S.
This is a more general solution to bug 225960.
The first attempt was D14458.