So maybe I'm missing something but couldn't the algorithm as described lead to an infinite loop where some annoying thread insists on making black objects grey faster than the gc can turn them black again, so that the GC ends up not being able to make progress? I think the fix is that when a black object makes a new reference to a white object, instead of making the black object grey, it should make the white object grey.
There's a variety of ways in which the mutator ("annoying thread") may outrun the collector. These can be resolved by throttling at the point of allocation, "stop the world" collections, or giving up and exploding.