An alternate approach that could be considered would be a unioning volume.
The advantage is that it would work with any file-system type that simply expects a volume to be a series of sectors that it reads and writes. Since the meta-data is stored somewhere on those volume sectors, there is no need to worry about whiteout/opaque directories or copy-file-on-write, etc.
In exchange, it would have a totally different set of problem issues. The over-volume has to keep track of which sectors it actually contains and which are transparent and need to go to the underlying volume. When the set of changed sectors is small, a hash of the sector ids that have been changed would point to the changed content (which would be contained in a small area of contiguous sectors on the over-volume) might be the best representation. When the change set got to be a significant proportion of the entire volume, a bit map selecting the over-volume/under-volume would be providing and the over-volume would use the same sector number as the under-volume, perhaps with an offset if the bitmap is kept at the beginning of the volume. Somewhere in between, as the number of changed sectors grew, it would have to transition between the two formats (and perhaps go through other intervening ones). In all cases, the union device driver would likely need to store some fairly large amounts of data in memory (either the hash table, or the bit map). Another representation might be to have a table mapping contiguous blocks of sectors that are in the over-volume - that would save the space of requiring a bit for every sector and allow the over-volume to not have its sectors in the same place as the under-volume; although it would degrade horribly if there were huge numbers of non-contiguous sectors over-written. Such a table would be slower though, requiring a binary search O(log n) instead of a hash or bitmap lookup of O(1) to find where to get a sector.)