+__private_extern__ int
+imageboot_mount_image(const char *root_path, int height)
+{
+ dev_t dev;
+ int error;
+ vnode_t old_rootvnode = NULL;
+ vnode_t newdp;
+ mount_t new_rootfs;
+
+ error = di_root_image(root_path, rootdevice, &dev);
+ if (error) {
+ panic("%s: di_root_image failed: %d\n", __FUNCTION__, error);
+ }
+
+ rootdev = dev;
+ mountroot = NULL;
+ printf("%s: root device 0x%x\n", __FUNCTION__, rootdev);
+ error = vfs_mountroot();
+ if (error != 0) {
+ panic("vfs_mountroot() failed.\n");
+ }
+
+ /*
+ * Get the vnode for '/'.
+ * Set fdp->fd_fd.fd_cdir to reference it.
+ */
+ if (VFS_ROOT(TAILQ_LAST(&mountlist,mntlist), &newdp, vfs_context_kernel()))
+ panic("%s: cannot find root vnode", __FUNCTION__);
+
+ if (rootvnode != NULL) {
+ /* remember the old rootvnode, but remove it from mountlist */
+ mount_t old_rootfs;
+
+ old_rootvnode = rootvnode;
+ old_rootfs = rootvnode->v_mount;
+
+ mount_list_remove(old_rootfs);
+
+ mount_lock(old_rootfs);
+#ifdef CONFIG_IMGSRC_ACCESS
+ old_rootfs->mnt_kern_flag |= MNTK_BACKS_ROOT;
+#endif /* CONFIG_IMGSRC_ACCESS */
+ old_rootfs->mnt_flag &= ~MNT_ROOTFS;
+ mount_unlock(old_rootfs);
+ }
+
+ /* switch to the new rootvnode */
+ rootvnode = newdp;
+
+ new_rootfs = rootvnode->v_mount;
+ mount_lock(new_rootfs);
+ new_rootfs->mnt_flag |= MNT_ROOTFS;
+ mount_unlock(new_rootfs);
+
+ vnode_ref(newdp);
+ vnode_put(newdp);
+ filedesc0.fd_cdir = newdp;
+ DBG_TRACE("%s: root switched\n", __FUNCTION__);
+
+ if (old_rootvnode != NULL) {
+#ifdef CONFIG_IMGSRC_ACCESS
+ if (height >= 0 && PE_imgsrc_mount_supported()) {
+ imgsrc_rootvnodes[height] = old_rootvnode;
+ } else {
+ vnode_get_and_drop_always(old_rootvnode);
+ }
+#else
+ height = 0; /* keep the compiler from complaining */
+ vnode_get_and_drop_always(old_rootvnode);
+#endif /* CONFIG_IMGSRC_ACCESS */
+ }
+ return 0;
+}