There are a few places in which unionfs_rename() accesses fvp's private
data without holding the necessary lock/interlock. Moreover, the
implementation completely fails to handle the case in which fdvp is not
the same as tdvp; in this case it simply fails to lock fdvp at all.
Finally, it locks fvp while already holding tvp's lock (if tvp is not
NULL and not the same as tdvp), but makes no attempt to deal with
possible LOR there.
Fix this by optimistically using the vnode interlock to protect
the short accesses to fdvp and fvp private data, sequentially.
If a file copy or shadow directory creation is required to prepare
the upper FS for the rename operation, fdvp and fvp must be locked,
so in this case the interlock as well as the tdvp (if different
from fdvp) and tvp locks are dropped prior to locking fdvp and fvp.
This change also removes an apparently-useless call to
unionfs_relookup_for_delete():
--For the case in which fdvp and tdvp are the same, the subsequent
call to unionfs_relookup_for_rename() on tdvp will drop fdvp's lock, effectively rendering the prior relookup_for_delete() useless.
--If fdvp and tdvp are different, the underlying filesystem must
be prepared for the rename operation to be issued without locks held on fdvp/fvp anyway.
Most filesystems seem to unconditionally unlock and then relock
all (potentially up to 4) vnodes in a deadlock-avoiding manner,
so the usefulness of any relookup in unionfs_rename() is
questionable to begin with.