FreeBSD/sys/kern/kern_shutdown.c
/*
 * The system call that results in changing the rootfs.
 */
The system call that results in changing the rootfs.
The system call that results in changing the rootfs .
static int
kern_reroot(void)
{
	struct vnode *oldrootvnode, *vp;
	struct mount *mp, *devmp;
	int error;
	if (curproc != initproc)
		return (EPERM);
	vp = curproc->p_textvp;
	error = vn_lock(vp, LK_SHARED);
	if (error != 0)
		return (error);
	mp = vp->v_mount;
	error = vfs_busy(mp, MBF_NOWAIT);
	if (error != 0) {
		vfs_ref(mp);
		VOP_UNLOCK(vp, 0);
		error = vfs_busy(mp, 0);
		vn_lock(vp, LK_SHARED | LK_RETRY);
		vfs_rel(mp);
		if (error != 0) {
			VOP_UNLOCK(vp, 0);
			return (ENOENT);
		}
		if (vp->v_iflag & VI_DOOMED) {
			VOP_UNLOCK(vp, 0);
			vfs_unbusy(mp);
			return (ENOENT);
		}
	}
	VOP_UNLOCK(vp, 0);
	vfs_ref(rootdevmp);
	devmp = rootdevmp;
	rootdevmp = NULL;
	mtx_lock(&mountlist_mtx);
	TAILQ_REMOVE(&mountlist, mp, mnt_list);
	TAILQ_REMOVE(&mountlist, devmp, mnt_list);
	mtx_unlock(&mountlist_mtx);
	oldrootvnode = rootvnode;
	vfs_unmountall();
	mtx_lock(&mountlist_mtx);
	TAILQ_INSERT_HEAD(&mountlist, devmp, mnt_list);
	mtx_unlock(&mountlist_mtx);
	rootdevmp = devmp;
	vfs_rel(rootdevmp);
	vfs_mountroot();
	mountcheckdirs(oldrootvnode, rootvnode);
	mtx_lock(&mountlist_mtx);
	TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
	mtx_unlock(&mountlist_mtx);
	vfs_unbusy(mp);
	return (0);
}
static int kern_reroot ( void ) { struct vnode * oldrootvnode , * vp ; struct mount * mp , * devmp ; int error ; if ( curproc != initproc ) return ( EPERM ) ; vp = curproc -> p_textvp ; error = vn_lock ( vp , LK_SHARED ) ; if ( error != 0 ) return ( error ) ; mp = vp -> v_mount ; error = vfs_busy ( mp , MBF_NOWAIT ) ; if ( error != 0 ) { vfs_ref ( mp ) ; VOP_UNLOCK ( vp , 0 ) ; error = vfs_busy ( mp , 0 ) ; vn_lock ( vp , LK_SHARED | LK_RETRY ) ; vfs_rel ( mp ) ; if ( error != 0 ) { VOP_UNLOCK ( vp , 0 ) ; return ( ENOENT ) ; } if ( vp -> v_iflag & VI_DOOMED ) { VOP_UNLOCK ( vp , 0 ) ; vfs_unbusy ( mp ) ; return ( ENOENT ) ; } } VOP_UNLOCK ( vp , 0 ) ; vfs_ref ( rootdevmp ) ; devmp = rootdevmp ; rootdevmp = NULL ; mtx_lock ( & mountlist_mtx ) ; TAILQ_REMOVE ( & mountlist , mp , mnt_list ) ; TAILQ_REMOVE ( & mountlist , devmp , mnt_list ) ; mtx_unlock ( & mountlist_mtx ) ; oldrootvnode = rootvnode ; vfs_unmountall ( ) ; mtx_lock ( & mountlist_mtx ) ; TAILQ_INSERT_HEAD ( & mountlist , devmp , mnt_list ) ; mtx_unlock ( & mountlist_mtx ) ; rootdevmp = devmp ; vfs_rel ( rootdevmp ) ; vfs_mountroot ( ) ; mountcheckdirs ( oldrootvnode , rootvnode ) ; mtx_lock ( & mountlist_mtx ) ; TAILQ_INSERT_TAIL ( & mountlist , mp , mnt_list ) ; mtx_unlock ( & mountlist_mtx ) ; vfs_unbusy ( mp ) ; return ( 0 ) ; }
The system call that results in changing the rootfs.
The system call that results in changing the rootfs .
/*
	 * Mark the filesystem containing currently-running executable
	 * (the temporary copy of init(8)) busy.
	 */ /*
	 * Remove the filesystem containing currently-running executable
	 * from the mount list, to prevent it from being unmounted
	 * by vfs_unmountall(), and to avoid confusing vfs_mountroot().
	 *
	 * Also preserve /dev - forcibly unmounting it could cause driver
	 * reinitialization.
	 */ /*
	 * Unmount everything except for the two filesystems preserved above.
	 */ /*
	 * Add /dev back; vfs_mountroot() will move it into its new place.
	 */ /*
	 * Mount the new rootfs.
	 */ /*
	 * Update all references to the old rootvnode.
	 */ /*
	 * Add the temporary filesystem back and unbusy it.
	 */