FreeBSD/sys/fs/tmpfs/tmpfs_vnops.c
/*
 * We acquire all but fdvp locks using non-blocking acquisitions.  If we
 * fail to acquire any lock in the path we will drop all held locks,
 * acquire the new lock in a blocking fashion, and then release it and
 * restart the rename.  This acquire/release step ensures that we do not
 * spin on a lock waiting for release.  On error release all vnode locks
 * and decrement references the way tmpfs_rename() would do.
 */
We acquire all but fdvp locks using non-blocking acquisitions.  If we
fail to acquire any lock in the path we will drop all held locks,
acquire the new lock in a blocking fashion, and then release it and
restart the rename.  This acquire/release step ensures that we do not
spin on a lock waiting for release.  On error release all vnode locks
and decrement references the way tmpfs_rename() would do.
We acquire all but fdvp locks using non - blocking acquisitions . If we fail to acquire any lock in the path we will drop all held locks acquire the new lock in a blocking fashion and then release it and restart the rename . This acquire / release step ensures that we do not spin on a lock waiting for release . On error release all vnode locks and decrement references the way tmpfs_rename () would do .
static int
tmpfs_rename_relock(struct vnode *fdvp, struct vnode **fvpp,
    struct vnode *tdvp, struct vnode **tvpp,
    struct componentname *fcnp, struct componentname *tcnp)
{
	struct vnode *nvp;
	struct mount *mp;
	struct tmpfs_dirent *de;
	int error, restarts = 0;
	VOP_UNLOCK(tdvp, 0);
	if (*tvpp != NULL && *tvpp != tdvp)
		VOP_UNLOCK(*tvpp, 0);
	mp = fdvp->v_mount;
relock:
	restarts += 1;
	error = vn_lock(fdvp, LK_EXCLUSIVE);
	if (error)
		goto releout;
	if (vn_lock(tdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) {
		VOP_UNLOCK(fdvp, 0);
		error = vn_lock(tdvp, LK_EXCLUSIVE);
		if (error)
			goto releout;
		VOP_UNLOCK(tdvp, 0);
		goto relock;
	}
	de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(fdvp), NULL, fcnp);
	if (de == NULL) {
		VOP_UNLOCK(fdvp, 0);
		VOP_UNLOCK(tdvp, 0);
		if ((fcnp->cn_flags & ISDOTDOT) != 0 ||
		    (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.'))
			error = EINVAL;
		else
			error = ENOENT;
		goto releout;
	}
	error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE | LK_NOWAIT, &nvp);
	if (error != 0) {
		VOP_UNLOCK(fdvp, 0);
		VOP_UNLOCK(tdvp, 0);
		if (error != EBUSY)
			goto releout;
		error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE, &nvp);
		if (error != 0)
			goto releout;
		VOP_UNLOCK(nvp, 0);
		if (nvp == tdvp) {
			vrele(nvp);
			error = EINVAL;
			goto releout;
		}
		vrele(*fvpp);
		*fvpp = nvp;
		goto relock;
	}
	vrele(*fvpp);
	*fvpp = nvp;
	VOP_UNLOCK(*fvpp, 0);
	de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(tdvp), NULL, tcnp);
	if (de == NULL && *tvpp != NULL) {
		vrele(*tvpp);
		*tvpp = NULL;
	}
	if (de != NULL) {
		nvp = NULL;
		error = tmpfs_alloc_vp(mp, de->td_node,
		    LK_EXCLUSIVE | LK_NOWAIT, &nvp);
		if (*tvpp != NULL)
			vrele(*tvpp);
		*tvpp = nvp;
		if (error != 0) {
			VOP_UNLOCK(fdvp, 0);
			VOP_UNLOCK(tdvp, 0);
			if (error != EBUSY)
				goto releout;
			error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE,
			    &nvp);
			if (error != 0)
				goto releout;
			VOP_UNLOCK(nvp, 0);
			if (nvp == fdvp) {
				error = ENOTEMPTY;
				goto releout;
			}
			goto relock;
		}
	}
	tmpfs_rename_restarts += restarts;
	return (0);
releout:
	vrele(fdvp);
	vrele(*fvpp);
	vrele(tdvp);
	if (*tvpp != NULL)
		vrele(*tvpp);
	tmpfs_rename_restarts += restarts;
	return (error);
}
static int tmpfs_rename_relock ( struct vnode * fdvp , struct vnode * * fvpp , struct vnode * tdvp , struct vnode * * tvpp , struct componentname * fcnp , struct componentname * tcnp ) { struct vnode * nvp ; struct mount * mp ; struct tmpfs_dirent * de ; int error , restarts = 0 ; VOP_UNLOCK ( tdvp , 0 ) ; if ( * tvpp != NULL && * tvpp != tdvp ) VOP_UNLOCK ( * tvpp , 0 ) ; mp = fdvp -> v_mount ; relock : restarts += 1 ; error = vn_lock ( fdvp , LK_EXCLUSIVE ) ; if ( error ) goto releout ; if ( vn_lock ( tdvp , LK_EXCLUSIVE | LK_NOWAIT ) != 0 ) { VOP_UNLOCK ( fdvp , 0 ) ; error = vn_lock ( tdvp , LK_EXCLUSIVE ) ; if ( error ) goto releout ; VOP_UNLOCK ( tdvp , 0 ) ; goto relock ; } de = tmpfs_dir_lookup ( VP_TO_TMPFS_DIR ( fdvp ) , NULL , fcnp ) ; if ( de == NULL ) { VOP_UNLOCK ( fdvp , 0 ) ; VOP_UNLOCK ( tdvp , 0 ) ; if ( ( fcnp -> cn_flags & ISDOTDOT ) != 0 || ( fcnp -> cn_namelen == 1 && fcnp -> cn_nameptr [ 0 ] == ' ' ) ) error = EINVAL ; else error = ENOENT ; goto releout ; } error = tmpfs_alloc_vp ( mp , de -> td_node , LK_EXCLUSIVE | LK_NOWAIT , & nvp ) ; if ( error != 0 ) { VOP_UNLOCK ( fdvp , 0 ) ; VOP_UNLOCK ( tdvp , 0 ) ; if ( error != EBUSY ) goto releout ; error = tmpfs_alloc_vp ( mp , de -> td_node , LK_EXCLUSIVE , & nvp ) ; if ( error != 0 ) goto releout ; VOP_UNLOCK ( nvp , 0 ) ; if ( nvp == tdvp ) { vrele ( nvp ) ; error = EINVAL ; goto releout ; } vrele ( * fvpp ) ; * fvpp = nvp ; goto relock ; } vrele ( * fvpp ) ; * fvpp = nvp ; VOP_UNLOCK ( * fvpp , 0 ) ; de = tmpfs_dir_lookup ( VP_TO_TMPFS_DIR ( tdvp ) , NULL , tcnp ) ; if ( de == NULL && * tvpp != NULL ) { vrele ( * tvpp ) ; * tvpp = NULL ; } if ( de != NULL ) { nvp = NULL ; error = tmpfs_alloc_vp ( mp , de -> td_node , LK_EXCLUSIVE | LK_NOWAIT , & nvp ) ; if ( * tvpp != NULL ) vrele ( * tvpp ) ; * tvpp = nvp ; if ( error != 0 ) { VOP_UNLOCK ( fdvp , 0 ) ; VOP_UNLOCK ( tdvp , 0 ) ; if ( error != EBUSY ) goto releout ; error = tmpfs_alloc_vp ( mp , de -> td_node , LK_EXCLUSIVE , & nvp ) ; if ( error != 0 ) goto releout ; VOP_UNLOCK ( nvp , 0 ) ; if ( nvp == fdvp ) { error = ENOTEMPTY ; goto releout ; } goto relock ; } } tmpfs_rename_restarts += restarts ; return ( 0 ) ; releout : vrele ( fdvp ) ; vrele ( * fvpp ) ; vrele ( tdvp ) ; if ( * tvpp != NULL ) vrele ( * tvpp ) ; tmpfs_rename_restarts += restarts ; return ( error ) ; }
We acquire all but fdvp locks using non-blocking acquisitions.
We acquire all but fdvp locks using non - blocking acquisitions .
/*
	 * Re-resolve fvp to be certain it still exists and fetch the
	 * correct vnode.
	 */ /*
		 * Concurrent rename race.
		 */ /*
	 * Re-resolve tvp and acquire the vnode lock if present.
	 */ /*
	 * If tvp disappeared we just carry on.
	 */ /*
	 * Get the tvp ino if the lookup succeeded.  We may have to restart
	 * if the non-blocking acquire fails.
	 */ /*
			 * fdvp contains fvp, thus tvp (=fdvp) is not empty.
			 */