diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -756,10 +756,12 @@ * Mark a mount point as busy. Used to synchronize access and to delay * unmounting. Eventually, mountlist_mtx is not released on failure. * - * vfs_busy() is a custom lock, it can block the caller. - * vfs_busy() only sleeps if the unmount is active on the mount point. - * For a mountpoint mp, vfs_busy-enforced lock is before lock of any - * vnode belonging to mp. + * vfs_busy() is a custom lock, it can block the caller. vfs_busy() only sleeps + * if the unmount is active on the mount point. + * + * To manipulate 'v_mountedhere' or cross such mounts, please use + * vn_busy_mountedhere(), vn_cross_single_mount() or vn_cross_mounts() depending + * on your needs instead of rolling your own solution. * * Lookup uses vfs_busy() to traverse mount points. * root fs var fs @@ -769,29 +771,25 @@ * * Within each file system, the lock order is C->A->B and F->D->E. * - * When traversing across mounts, the system follows that lock order: + * When traversing across mounts, no lock order should be established between + * the covered vnode and the 'v_mountedhere' mount (B and F). * - * C->A->B - * | - * +->F->D->E + * To illustrate, here are the inner workings of the lookup() process for + * namei("/var"): + * 1. VOP_LOOKUP() obtains B while A is held. + * 2. A is released in order to avoid some deadlock propagation up to the root + * vnode in case a NFS server is not responding (see the corresponding + * comment in vfs_lookup()). + * 3. vfs_busy_mountedhere() obtains F, which may require releasing B. + * 4. VOP_UNLOCK() releases lock on B, if not released at 2. + * 5. VFS_ROOT() obtains lock on D while F is held. + * 6. vfs_unbusy() releases F. + * 7. A is relocked while D is held with vn_lock_pair(). * - * The lookup() process for namei("/var") illustrates the process: - * 1. VOP_LOOKUP() obtains B while A is held - * 2. vfs_busy() obtains a shared lock on F while A and B are held - * 3. vput() releases lock on B - * 4. vput() releases lock on A - * 5. VFS_ROOT() obtains lock on D while shared lock on F is held - * 6. vfs_unbusy() releases shared lock on F - * 7. vn_lock() obtains lock on deadfs vnode vp_crossmp instead of A. - * Attempt to lock A (instead of vp_crossmp) while D is held would - * violate the global order, causing deadlocks. - * - * dounmount() locks B while F is drained. Note that for stacked - * filesystems, D and B in the example above may be the same lock, - * which introdues potential lock order reversal deadlock between - * dounmount() and step 5 above. These filesystems may avoid the LOR - * by setting VV_CROSSLOCK on the covered vnode so that lock B will - * remain held until after step 5. + * dounmount() does not anymore lock B while F is drained. Note that for + * stacked filesystems, D and B in the example above may be the same lock, but + * no lock order reversal can occur anymore since there is no ordering between + * B and F. */ int vfs_busy(struct mount *mp, int flags)