Are there any particular technical obstacles that need to be overcome?
One big obstacle is the difference in semantics. Copying a directory (in the case where the target doesn’t already exist) results in copies of all its contents, and a new directory pointing to all those contents. In particular, this means that while the source and target directories end up containing the same names, the target inode for each name is different.
If you clone directories in the same way as cloning files, you end up with two directories whose contents point to the same inodes — effectively, you’re creating a directory containing hard links to the original directory’s contents. This won’t work for directories, and it creates surprising semantics for files — cloning dira containing file, as dirb, means that editing dirb/file will also edit dira/file, which presumably wasn’t the original intent.
So this means that sharing storage for directory copies won’t work in the general case, and would only be useful in a small number of cases.
copy_file_range and the FICLONE ioctls however don’t assume that underlying storage will be shared. They are requests of the form “kernel, please copy this (portion of) file”; they have benefits where storage can be shared, but also where delegated copying is more efficient than reading and writing. For example, on networked file systems, cloning can be handled on the server, which is far more efficient than client-driven copies. Applying this reasoning to directory copies, without necessarily sharing underlying storage, could be useful.
Even in scenarios where it’s useful, the implementation and use of the kernel operation would be complex.
File cloning operations have a single file to handle, initially in a single file system. Even then, the extension of copy_file_range to handle copies across multiple file systems has led to a number of issues.
A “clone” operation for directories would be much more complex. Copying a directory involves not only copying the directory itself (i.e. the map of file names to inodes), but also the contents of the directory. As already mentioned, you can’t just hard link files, the semantics would then be different; and even if that were an acceptable simplification, you would still need to deal with entries which can’t be hard linked, such as directories in the directory you’re trying to clone. Then we get to mount points, and the level of “fun” just goes up by a whole lot. All this of course while handling permissions.
Assuming someone implements all this, you then need to update relevant user space programs to use the new operation, with existing code as fallback. Unlike single-file clones, the semantics are rather different, and it may not be easy in all cases to splice the new function in. The resulting file system semantics are also different (arguably, those could be changed without breaking the world if it was worth it — see relatime and noatime).
There are probably other obstacles I haven’t thought of yet; but the first one shows that there is really little opportunity for directories to actually share storage anyway.