/* * Called by main() when ufs is going to be mounted as root. */ lfs_mountroot() { extern struct vnode *rootvp; struct fs *fs; struct mount *mp; struct proc *p = curproc; /* XXX */ int error; /* * Get vnodes for swapdev and rootdev. */ if ((error = bdevvp(swapdev, &swapdev_vp)) || (error = bdevvp(rootdev, &rootvp))) { printf("lfs_mountroot: can't setup bdevvp's"); return (error); } if (error = vfs_rootmountalloc("lfs", "root_device", &mp)) return (error); if (error = lfs_mountfs(rootvp, mp, p)) { mp->mnt_vfc->vfc_refcount--; vfs_unbusy(mp, p); free(mp, M_MOUNT); return (error); } simple_lock(&mountlist_slock); CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); simple_unlock(&mountlist_slock); (void)lfs_statfs(mp, &mp->mnt_stat, p); vfs_unbusy(mp, p); return (0); }
int cd9660_mountroot(void) { struct mount *mp; extern struct vnode *rootvp; struct proc *p = curproc; /* XXX */ int error; struct iso_args args; /* * Get vnodes for swapdev and rootdev. */ if ((error = bdevvp(swapdev, &swapdev_vp)) || (error = bdevvp(rootdev, &rootvp))) { printf("cd9660_mountroot: can't setup bdevvp's"); return (error); } if ((error = vfs_rootmountalloc("cd9660", "root_device", &mp)) != 0) return (error); args.flags = ISOFSMNT_ROOT; if ((error = iso_mountfs(rootvp, mp, p, &args)) != 0) { mp->mnt_vfc->vfc_refcount--; vfs_unbusy(mp); free(mp, M_MOUNT, 0); return (error); } TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); (void)cd9660_statfs(mp, &mp->mnt_stat, p); vfs_unbusy(mp); inittodr(0); return (0); }
static int ext2_mountroot() { #if !defined(__FreeBSD__) extern struct vnode *rootvp; #endif register struct ext2_sb_info *fs; register struct mount *mp; #if defined(__FreeBSD__) struct proc *p = curproc; #else struct proc *p = get_proc(); /* XXX */ #endif struct ufsmount *ump; u_int size; int error; /* * Get vnodes for swapdev and rootdev. */ if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp)) panic("ext2_mountroot: can't setup bdevvp's"); mp = bsd_malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); bzero((char *)mp, (u_long)sizeof(struct mount)); mp->mnt_op = &ext2fs_vfsops; mp->mnt_flag = MNT_RDONLY; if (error = ext2_mountfs(rootvp, mp, p)) { bsd_free(mp, M_MOUNT); return (error); } if (error = vfs_lock(mp)) { (void)ext2_unmount(mp, 0, p); bsd_free(mp, M_MOUNT); return (error); } #if defined(__FreeBSD__) CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); #else TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); #endif mp->mnt_flag |= MNT_ROOTFS; mp->mnt_vnodecovered = NULLVP; ump = VFSTOUFS(mp); fs = ump->um_e2fs; bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); fs->fs_fsmnt[0] = '/'; bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, MNAMELEN); (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); (void)ext2_statfs(mp, &mp->mnt_stat, p); vfs_unlock(mp); inittodr(fs->s_es->s_wtime); /* this helps to set the time */ return (0); }
static int iso_mountroot(struct mount *mp) { struct iso_args args; struct vnode *rootvp; int error; if ((error = bdevvp(rootdev, &rootvp))) { kprintf("iso_mountroot: can't find rootvp\n"); return (error); } args.flags = ISOFSMNT_ROOT; vn_lock(rootvp, LK_EXCLUSIVE | LK_RETRY); error = VOP_OPEN(rootvp, FREAD, FSCRED, NULL); vn_unlock(rootvp); if (error) return (error); args.ssector = iso_get_ssector(rootdev); vn_lock(rootvp, LK_EXCLUSIVE | LK_RETRY); VOP_CLOSE(rootvp, FREAD, NULL); vn_unlock(rootvp); if (bootverbose) kprintf("iso_mountroot(): using session at block %d\n", args.ssector); if ((error = iso_mountfs(rootvp, mp, &args)) != 0) return (error); cd9660_statfs(mp, &mp->mnt_stat, proc0.p_ucred); return (0); }
int ffs_mountroot(void) { struct fs *fs; struct mount *mp; struct proc *p = curproc; /* XXX */ struct ufsmount *ump; int error; /* * Get vnodes for swapdev and rootdev. */ swapdev_vp = NULL; if ((error = bdevvp(swapdev, &swapdev_vp)) || (error = bdevvp(rootdev, &rootvp))) { printf("ffs_mountroot: can't setup bdevvp's\n"); if (swapdev_vp) vrele(swapdev_vp); return (error); } if ((error = vfs_rootmountalloc("ffs", "root_device", &mp)) != 0) { vrele(swapdev_vp); vrele(rootvp); return (error); } if ((error = ffs_mountfs(rootvp, mp, p)) != 0) { mp->mnt_vfc->vfc_refcount--; vfs_unbusy(mp); free(mp, M_MOUNT); vrele(swapdev_vp); vrele(rootvp); return (error); } CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); ump = VFSTOUFS(mp); fs = ump->um_fs; (void) copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0); (void)ffs_statfs(mp, &mp->mnt_stat, p); vfs_unbusy(mp); inittodr(fs->fs_time); return (0); }
int mfs_mountroot(void) { struct fs *fs; struct mount *mp; struct proc *p = curproc; struct ufsmount *ump; struct mfsnode *mfsp; int error; if ((error = bdevvp(swapdev, &swapdev_vp)) || (error = bdevvp(rootdev, &rootvp))) { printf("mfs_mountroot: can't setup bdevvp's"); return (error); } if ((error = vfs_rootmountalloc("mfs", "mfs_root", &mp)) != 0) return (error); mfsp = malloc(sizeof *mfsp, M_MFSNODE, M_WAITOK); rootvp->v_data = mfsp; rootvp->v_op = mfs_vnodeop_p; rootvp->v_tag = VT_MFS; mfsp->mfs_baseoff = mfs_rootbase; mfsp->mfs_size = mfs_rootsize; mfsp->mfs_vnode = rootvp; mfsp->mfs_pid = p->p_pid; mfsp->mfs_buflist = (struct buf *)0; if ((error = ffs_mountfs(rootvp, mp, p)) != 0) { mp->mnt_vfc->vfc_refcount--; vfs_unbusy(mp); free(mp, M_MOUNT); free(mfsp, M_MFSNODE); return (error); } CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); ump = VFSTOUFS(mp); fs = ump->um_fs; (void) copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0); (void)ffs_statfs(mp, &mp->mnt_stat, p); vfs_unbusy(mp); inittodr((time_t)0); return (0); }
int ext2fs_mountroot(void) { struct m_ext2fs *fs; struct mount *mp; struct proc *p = curproc; /* XXX */ struct ufsmount *ump; int error; /* * Get vnodes for swapdev and rootdev. */ if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp)) panic("ext2fs_mountroot: can't setup bdevvp's"); if ((error = vfs_rootmountalloc("ext2fs", "root_device", &mp)) != 0) { vrele(rootvp); return (error); } if ((error = ext2fs_mountfs(rootvp, mp, p)) != 0) { mp->mnt_vfc->vfc_refcount--; vfs_unbusy(mp); free(mp, M_MOUNT); vrele(rootvp); return (error); } TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); ump = VFSTOUFS(mp); fs = ump->um_e2fs; memset(fs->e2fs_fsmnt, 0, sizeof(fs->e2fs_fsmnt)); strlcpy(fs->e2fs_fsmnt, mp->mnt_stat.f_mntonname, sizeof(fs->e2fs_fsmnt)); if (fs->e2fs.e2fs_rev > E2FS_REV0) { memset(fs->e2fs.e2fs_fsmnt, 0, sizeof(fs->e2fs.e2fs_fsmnt)); strlcpy(fs->e2fs.e2fs_fsmnt, mp->mnt_stat.f_mntonname, sizeof(fs->e2fs.e2fs_fsmnt)); } (void)ext2fs_statfs(mp, &mp->mnt_stat, p); vfs_unbusy(mp); inittodr(fs->e2fs.e2fs_wtime); return (0); }
int cd9660_mountroot() { register struct mount *mp; extern struct vnode *rootvp; struct proc *p = current_proc(); /* XXX */ struct iso_mnt *imp; size_t size; int error; struct iso_args args; /* * Get vnodes for swapdev and rootdev. */ if ( bdevvp(rootdev, &rootvp)) panic("cd9660_mountroot: can't setup bdevvp's"); MALLOC_ZONE(mp, struct mount *, sizeof(struct mount), M_MOUNT, M_WAITOK); bzero((char *)mp, (u_long)sizeof(struct mount)); /* Initialize the default IO constraints */ mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS; mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32; mp->mnt_op = &cd9660_vfsops; mp->mnt_flag = MNT_RDONLY; LIST_INIT(&mp->mnt_vnodelist); args.flags = ISOFSMNT_ROOT; args.ssector = 0; args.fspec = 0; args.toc_length = 0; args.toc = 0; if ((error = iso_mountfs(rootvp, mp, p, &args))) { vrele(rootvp); /* release the reference from bdevvp() */ if (mp->mnt_kern_flag & MNTK_IO_XINFO) FREE(mp->mnt_xinfo_ptr, M_TEMP); FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); return (error); } simple_lock(&mountlist_slock); CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); simple_unlock(&mountlist_slock); mp->mnt_vnodecovered = NULLVP; imp = VFSTOISOFS(mp); (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); (void)cd9660_statfs(mp, &mp->mnt_stat, p); return (0); }
/* * Called by main() when ufs is going to be mounted as root. */ ffs_mountroot() { extern struct vnode *rootvp; struct fs *fs; struct mount *mp; struct proc *p = current_proc(); /* XXX */ struct ufsmount *ump; u_int size; int error; /* * Get vnode for rootdev. */ if (error = bdevvp(rootdev, &rootvp)) { printf("ffs_mountroot: can't setup bdevvp"); return (error); } if (error = vfs_rootmountalloc("ufs", "root_device", &mp)) { vrele(rootvp); /* release the reference from bdevvp() */ return (error); } /* Must set the MNT_ROOTFS flag before doing the actual mount */ mp->mnt_flag |= MNT_ROOTFS; /* Set asynchronous flag by default */ mp->mnt_flag |= MNT_ASYNC; if (error = ffs_mountfs(rootvp, mp, p)) { mp->mnt_vfc->vfc_refcount--; if (mp->mnt_kern_flag & MNTK_IO_XINFO) FREE(mp->mnt_xinfo_ptr, M_TEMP); vfs_unbusy(mp, p); vrele(rootvp); /* release the reference from bdevvp() */ FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); return (error); } simple_lock(&mountlist_slock); CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); simple_unlock(&mountlist_slock); ump = VFSTOUFS(mp); fs = ump->um_fs; (void) copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0); (void)ffs_statfs(mp, &mp->mnt_stat, p); vfs_unbusy(mp, p); inittodr(fs->fs_time); return (0); }
/* * Lookup the provided name in the filesystem. If the file exists, * is a valid block device, and isn't being used by anyone else, * set *vpp to the file's vnode. */ int dk_lookup(struct pathbuf *pb, struct lwp *l, struct vnode **vpp) { struct nameidata nd; struct vnode *vp; int error; if (l == NULL) return ESRCH; /* Is ESRCH the best choice? */ NDINIT(&nd, LOOKUP, FOLLOW, pb); if ((error = vn_open(&nd, FREAD | FWRITE, 0)) != 0) { DPRINTF((DKDB_FOLLOW|DKDB_INIT), ("%s: vn_open error = %d\n", __func__, error)); return error; } vp = nd.ni_vp; if (vp->v_type != VBLK) { error = ENOTBLK; goto out; } /* Reopen as anonymous vnode to protect against forced unmount. */ if ((error = bdevvp(vp->v_rdev, vpp)) != 0) goto out; VOP_UNLOCK(vp); if ((error = vn_close(vp, FREAD | FWRITE, l->l_cred)) != 0) { vrele(*vpp); return error; } if ((error = VOP_OPEN(*vpp, FREAD | FWRITE, l->l_cred)) != 0) { vrele(*vpp); return error; } mutex_enter((*vpp)->v_interlock); (*vpp)->v_writecount++; mutex_exit((*vpp)->v_interlock); IFDEBUG(DKDB_VNODE, vprint("dk_lookup: vnode info", *vpp)); return 0; out: VOP_UNLOCK(vp); (void) vn_close(vp, FREAD | FWRITE, l->l_cred); return error; }
static int ext2_mountroot() { register struct ext2_sb_info *fs; register struct mount *mp; struct proc *p = curproc; struct ufsmount *ump; u_int size; int error; if ((error = bdevvp(rootdev, &rootvp))) { printf("ext2_mountroot: can't find rootvp\n"); return (error); } mp = bsd_malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); bzero((char *)mp, (u_long)sizeof(struct mount)); mp->mnt_op = &ext2fs_vfsops; mp->mnt_flag = MNT_RDONLY; if (error = ext2_mountfs(rootvp, mp, p)) { bsd_free(mp, M_MOUNT); return (error); } if (error = vfs_lock(mp)) { (void)ext2_unmount(mp, 0, p); bsd_free(mp, M_MOUNT); return (error); } TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list); mp->mnt_flag |= MNT_ROOTFS; mp->mnt_vnodecovered = NULLVP; ump = VFSTOUFS(mp); fs = ump->um_e2fs; bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); fs->fs_fsmnt[0] = '/'; bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, MNAMELEN); (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); (void)ext2_statfs(mp, &mp->mnt_stat, p); vfs_unlock(mp); inittodr(fs->s_es->s_wtime); /* this helps to set the time */ return (0); }
/* * ffs_mount * * Called when mounting local physical media * * PARAMETERS: * mountroot * mp mount point structure * path NULL (flag for root mount!!!) * data <unused> * p process (user credentials check [statfs]) * * mount * mp mount point structure * path path to mount point * data pointer to argument struct in user space * p process (user credentials check) * * RETURNS: 0 Success * !0 error number (errno.h) * * LOCK STATE: * * ENTRY * mount point is locked * EXIT * mount point is locked * * NOTES: * A NULL path can be used for a flag since the mount * system call will fail with EFAULT in copyinstr in * nlookup() if it is a genuine NULL from the user. */ static int ffs_mount(struct mount *mp, /* mount struct pointer */ char *path, /* path to mount point */ caddr_t data, /* arguments to FS specific mount */ struct ucred *cred) /* process requesting mount */ { size_t size; int error; struct vnode *devvp; struct ufs_args args; struct ufsmount *ump = NULL; struct fs *fs; int flags, ronly = 0; mode_t accessmode; struct nlookupdata nd; struct vnode *rootvp; devvp = NULL; error = 0; /* * Use NULL path to flag a root mount */ if (path == NULL) { /* *** * Mounting root filesystem *** */ if ((error = bdevvp(rootdev, &rootvp))) { kprintf("ffs_mountroot: can't find rootvp\n"); return (error); } if( ( error = ffs_mountfs(rootvp, mp, M_FFSNODE)) != 0) { /* fs specific cleanup (if any)*/ goto error_1; } devvp = rootvp; goto dostatfs; /* success*/ } /* *** * Mounting non-root filesystem or updating a filesystem *** */ /* copy in user arguments*/ error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)); if (error) goto error_1; /* can't get arguments*/ /* * If updating, check whether changing from read-only to * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { ump = VFSTOUFS(mp); fs = ump->um_fs; devvp = ump->um_devvp; error = 0; ronly = fs->fs_ronly; /* MNT_RELOAD might change this */ if (ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { /* * Flush any dirty data. */ VFS_SYNC(mp, MNT_WAIT); /* * Check for and optionally get rid of files open * for writing. */ flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; if (mp->mnt_flag & MNT_SOFTDEP) { error = softdep_flushfiles(mp, flags); } else { error = ffs_flushfiles(mp, flags); } ronly = 1; } if (!error && (mp->mnt_flag & MNT_RELOAD)) { error = ffs_reload(mp, NULL); } if (error) { goto error_1; } if (ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { /* * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. */ if (cred->cr_uid != 0) { vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); if ((error = VOP_EACCESS(devvp, VREAD | VWRITE, cred)) != 0) { vn_unlock(devvp); return (error); } vn_unlock(devvp); } fs->fs_flags &= ~FS_UNCLEAN; if (fs->fs_clean == 0) { fs->fs_flags |= FS_UNCLEAN; if (mp->mnt_flag & MNT_FORCE) { kprintf( "WARNING: %s was not properly dismounted\n", fs->fs_fsmnt); } else { kprintf( "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", fs->fs_fsmnt); error = EPERM; goto error_1; } } /* check to see if we need to start softdep */ if (fs->fs_flags & FS_DOSOFTDEP) { error = softdep_mount(devvp, mp, fs); if (error) goto error_1; } ronly = 0; } /* * Soft updates is incompatible with "async", * so if we are doing softupdates stop the user * from setting the async flag in an update. * Softdep_mount() clears it in an initial mount * or ro->rw remount. */ if (mp->mnt_flag & MNT_SOFTDEP) { mp->mnt_flag &= ~MNT_ASYNC; } /* if not updating name...*/ if (args.fspec == 0) { /* * Process export requests. Jumping to "success" * will return the vfs_export() error code. */ error = vfs_export(mp, &ump->um_export, &args.export); goto success; }
static int hammer_vfs_mount(struct mount *mp, char *mntpt, caddr_t data, struct ucred *cred) { struct hammer_mount_info info; hammer_mount_t hmp; hammer_volume_t rootvol; struct vnode *rootvp; struct vnode *devvp = NULL; const char *upath; /* volume name in userspace */ char *path; /* volume name in system space */ int error; int i; int master_id; char *next_volume_ptr = NULL; /* * Accept hammer_mount_info. mntpt is NULL for root mounts at boot. */ if (mntpt == NULL) { bzero(&info, sizeof(info)); info.asof = 0; info.hflags = 0; info.nvolumes = 1; next_volume_ptr = mp->mnt_stat.f_mntfromname; /* Count number of volumes separated by ':' */ for (char *p = next_volume_ptr; *p != '\0'; ++p) { if (*p == ':') { ++info.nvolumes; } } mp->mnt_flag &= ~MNT_RDONLY; /* mount R/W */ } else { if ((error = copyin(data, &info, sizeof(info))) != 0) return (error); } /* * updating or new mount */ if (mp->mnt_flag & MNT_UPDATE) { hmp = (void *)mp->mnt_data; KKASSERT(hmp != NULL); } else { if (info.nvolumes <= 0 || info.nvolumes > HAMMER_MAX_VOLUMES) return (EINVAL); hmp = NULL; } /* * master-id validation. The master id may not be changed by a * mount update. */ if (info.hflags & HMNT_MASTERID) { if (hmp && hmp->master_id != info.master_id) { kprintf("hammer: cannot change master id " "with mount update\n"); return(EINVAL); } master_id = info.master_id; if (master_id < -1 || master_id >= HAMMER_MAX_MASTERS) return (EINVAL); } else { if (hmp) master_id = hmp->master_id; else master_id = 0; } /* * Internal mount data structure */ if (hmp == NULL) { hmp = kmalloc(sizeof(*hmp), M_HAMMER, M_WAITOK | M_ZERO); mp->mnt_data = (qaddr_t)hmp; hmp->mp = mp; /*TAILQ_INIT(&hmp->recycle_list);*/ /* * Make sure kmalloc type limits are set appropriately. * * Our inode kmalloc group is sized based on maxvnodes * (controlled by the system, not us). */ kmalloc_create(&hmp->m_misc, "HAMMER-others"); kmalloc_create(&hmp->m_inodes, "HAMMER-inodes"); kmalloc_raise_limit(hmp->m_inodes, 0); /* unlimited */ hmp->root_btree_beg.localization = 0x00000000U; hmp->root_btree_beg.obj_id = -0x8000000000000000LL; hmp->root_btree_beg.key = -0x8000000000000000LL; hmp->root_btree_beg.create_tid = 1; hmp->root_btree_beg.delete_tid = 1; hmp->root_btree_beg.rec_type = 0; hmp->root_btree_beg.obj_type = 0; hmp->root_btree_end.localization = 0xFFFFFFFFU; hmp->root_btree_end.obj_id = 0x7FFFFFFFFFFFFFFFLL; hmp->root_btree_end.key = 0x7FFFFFFFFFFFFFFFLL; hmp->root_btree_end.create_tid = 0xFFFFFFFFFFFFFFFFULL; hmp->root_btree_end.delete_tid = 0; /* special case */ hmp->root_btree_end.rec_type = 0xFFFFU; hmp->root_btree_end.obj_type = 0; hmp->krate.freq = 1; /* maximum reporting rate (hz) */ hmp->krate.count = -16; /* initial burst */ hmp->sync_lock.refs = 1; hmp->free_lock.refs = 1; hmp->undo_lock.refs = 1; hmp->blkmap_lock.refs = 1; hmp->snapshot_lock.refs = 1; hmp->volume_lock.refs = 1; TAILQ_INIT(&hmp->delay_list); TAILQ_INIT(&hmp->flush_group_list); TAILQ_INIT(&hmp->objid_cache_list); TAILQ_INIT(&hmp->undo_lru_list); TAILQ_INIT(&hmp->reclaim_list); RB_INIT(&hmp->rb_dedup_crc_root); RB_INIT(&hmp->rb_dedup_off_root); TAILQ_INIT(&hmp->dedup_lru_list); } hmp->hflags &= ~HMNT_USERFLAGS; hmp->hflags |= info.hflags & HMNT_USERFLAGS; hmp->master_id = master_id; if (info.asof) { mp->mnt_flag |= MNT_RDONLY; hmp->asof = info.asof; } else { hmp->asof = HAMMER_MAX_TID; } hmp->volume_to_remove = -1; /* * Re-open read-write if originally read-only, or vise-versa. * * When going from read-only to read-write execute the stage2 * recovery if it has not already been run. */ if (mp->mnt_flag & MNT_UPDATE) { lwkt_gettoken(&hmp->fs_token); error = 0; if (hmp->ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { kprintf("HAMMER read-only -> read-write\n"); hmp->ronly = 0; RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, hammer_adjust_volume_mode, NULL); rootvol = hammer_get_root_volume(hmp, &error); if (rootvol) { hammer_recover_flush_buffers(hmp, rootvol, 1); error = hammer_recover_stage2(hmp, rootvol); bcopy(rootvol->ondisk->vol0_blockmap, hmp->blockmap, sizeof(hmp->blockmap)); hammer_rel_volume(rootvol, 0); } RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL, hammer_reload_inode, NULL); /* kernel clears MNT_RDONLY */ } else if (hmp->ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { kprintf("HAMMER read-write -> read-only\n"); hmp->ronly = 1; /* messy */ RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL, hammer_reload_inode, NULL); hmp->ronly = 0; hammer_flusher_sync(hmp); hammer_flusher_sync(hmp); hammer_flusher_sync(hmp); hmp->ronly = 1; RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, hammer_adjust_volume_mode, NULL); } lwkt_reltoken(&hmp->fs_token); return(error); } RB_INIT(&hmp->rb_vols_root); RB_INIT(&hmp->rb_inos_root); RB_INIT(&hmp->rb_redo_root); RB_INIT(&hmp->rb_nods_root); RB_INIT(&hmp->rb_undo_root); RB_INIT(&hmp->rb_resv_root); RB_INIT(&hmp->rb_bufs_root); RB_INIT(&hmp->rb_pfsm_root); hmp->ronly = ((mp->mnt_flag & MNT_RDONLY) != 0); RB_INIT(&hmp->volu_root); RB_INIT(&hmp->undo_root); RB_INIT(&hmp->data_root); RB_INIT(&hmp->meta_root); RB_INIT(&hmp->lose_root); TAILQ_INIT(&hmp->iorun_list); lwkt_token_init(&hmp->fs_token, "hammerfs"); lwkt_token_init(&hmp->io_token, "hammerio"); lwkt_gettoken(&hmp->fs_token); /* * Load volumes */ path = objcache_get(namei_oc, M_WAITOK); hmp->nvolumes = -1; for (i = 0; i < info.nvolumes; ++i) { if (mntpt == NULL) { /* * Root mount. */ KKASSERT(next_volume_ptr != NULL); strcpy(path, ""); if (*next_volume_ptr != '/') { /* relative path */ strcpy(path, "/dev/"); } int k; for (k = strlen(path); k < MAXPATHLEN-1; ++k) { if (*next_volume_ptr == '\0') { break; } else if (*next_volume_ptr == ':') { ++next_volume_ptr; break; } else { path[k] = *next_volume_ptr; ++next_volume_ptr; } } path[k] = '\0'; error = 0; cdev_t dev = kgetdiskbyname(path); error = bdevvp(dev, &devvp); if (error) { kprintf("hammer_mountroot: can't find devvp\n"); } } else { error = copyin(&info.volumes[i], &upath, sizeof(char *)); if (error == 0) error = copyinstr(upath, path, MAXPATHLEN, NULL); } if (error == 0) error = hammer_install_volume(hmp, path, devvp); if (error) break; } objcache_put(namei_oc, path); /* * Make sure we found a root volume */ if (error == 0 && hmp->rootvol == NULL) { kprintf("hammer_mount: No root volume found!\n"); error = EINVAL; } /* * Check that all required volumes are available */ if (error == 0 && hammer_mountcheck_volumes(hmp)) { kprintf("hammer_mount: Missing volumes, cannot mount!\n"); error = EINVAL; } if (error) { /* called with fs_token held */ hammer_free_hmp(mp); return (error); } /* * No errors, setup enough of the mount point so we can lookup the * root vnode. */ mp->mnt_iosize_max = MAXPHYS; mp->mnt_kern_flag |= MNTK_FSMID; mp->mnt_kern_flag |= MNTK_THR_SYNC; /* new vsyncscan semantics */ /* * MPSAFE code. Note that VOPs and VFSops which are not MPSAFE * will acquire a per-mount token prior to entry and release it * on return, so even if we do not specify it we no longer get * the BGL regardlless of how we are flagged. */ mp->mnt_kern_flag |= MNTK_ALL_MPSAFE; /*MNTK_RD_MPSAFE | MNTK_GA_MPSAFE | MNTK_IN_MPSAFE;*/ /* * note: f_iosize is used by vnode_pager_haspage() when constructing * its VOP_BMAP call. */ mp->mnt_stat.f_iosize = HAMMER_BUFSIZE; mp->mnt_stat.f_bsize = HAMMER_BUFSIZE; mp->mnt_vstat.f_frsize = HAMMER_BUFSIZE; mp->mnt_vstat.f_bsize = HAMMER_BUFSIZE; mp->mnt_maxsymlinklen = 255; mp->mnt_flag |= MNT_LOCAL; vfs_add_vnodeops(mp, &hammer_vnode_vops, &mp->mnt_vn_norm_ops); vfs_add_vnodeops(mp, &hammer_spec_vops, &mp->mnt_vn_spec_ops); vfs_add_vnodeops(mp, &hammer_fifo_vops, &mp->mnt_vn_fifo_ops); /* * The root volume's ondisk pointer is only valid if we hold a * reference to it. */ rootvol = hammer_get_root_volume(hmp, &error); if (error) goto failed; /* * Perform any necessary UNDO operations. The recovery code does * call hammer_undo_lookup() so we have to pre-cache the blockmap, * and then re-copy it again after recovery is complete. * * If this is a read-only mount the UNDO information is retained * in memory in the form of dirty buffer cache buffers, and not * written back to the media. */ bcopy(rootvol->ondisk->vol0_blockmap, hmp->blockmap, sizeof(hmp->blockmap)); /* * Check filesystem version */ hmp->version = rootvol->ondisk->vol_version; if (hmp->version < HAMMER_VOL_VERSION_MIN || hmp->version > HAMMER_VOL_VERSION_MAX) { kprintf("HAMMER: mount unsupported fs version %d\n", hmp->version); error = ERANGE; goto done; } /* * The undo_rec_limit limits the size of flush groups to avoid * blowing out the UNDO FIFO. This calculation is typically in * the tens of thousands and is designed primarily when small * HAMMER filesystems are created. */ hmp->undo_rec_limit = hammer_undo_max(hmp) / 8192 + 100; if (hammer_debug_general & 0x0001) kprintf("HAMMER: undo_rec_limit %d\n", hmp->undo_rec_limit); /* * NOTE: Recover stage1 not only handles meta-data recovery, it * also sets hmp->undo_seqno for HAMMER VERSION 4+ filesystems. */ error = hammer_recover_stage1(hmp, rootvol); if (error) { kprintf("Failed to recover HAMMER filesystem on mount\n"); goto done; } /* * Finish setup now that we have a good root volume. * * The top 16 bits of fsid.val[1] is a pfs id. */ ksnprintf(mp->mnt_stat.f_mntfromname, sizeof(mp->mnt_stat.f_mntfromname), "%s", rootvol->ondisk->vol_name); mp->mnt_stat.f_fsid.val[0] = crc32((char *)&rootvol->ondisk->vol_fsid + 0, 8); mp->mnt_stat.f_fsid.val[1] = crc32((char *)&rootvol->ondisk->vol_fsid + 8, 8); mp->mnt_stat.f_fsid.val[1] &= 0x0000FFFF; mp->mnt_vstat.f_fsid_uuid = rootvol->ondisk->vol_fsid; mp->mnt_vstat.f_fsid = crc32(&mp->mnt_vstat.f_fsid_uuid, sizeof(mp->mnt_vstat.f_fsid_uuid)); /* * Certain often-modified fields in the root volume are cached in * the hammer_mount structure so we do not have to generate lots * of little UNDO structures for them. * * Recopy after recovery. This also has the side effect of * setting our cached undo FIFO's first_offset, which serves to * placemark the FIFO start for the NEXT flush cycle while the * on-disk first_offset represents the LAST flush cycle. */ hmp->next_tid = rootvol->ondisk->vol0_next_tid; hmp->flush_tid1 = hmp->next_tid; hmp->flush_tid2 = hmp->next_tid; bcopy(rootvol->ondisk->vol0_blockmap, hmp->blockmap, sizeof(hmp->blockmap)); hmp->copy_stat_freebigblocks = rootvol->ondisk->vol0_stat_freebigblocks; hammer_flusher_create(hmp); /* * Locate the root directory using the root cluster's B-Tree as a * starting point. The root directory uses an obj_id of 1. * * FUTURE: Leave the root directory cached referenced but unlocked * in hmp->rootvp (need to flush it on unmount). */ error = hammer_vfs_vget(mp, NULL, 1, &rootvp); if (error) goto done; vput(rootvp); /*vn_unlock(hmp->rootvp);*/ if (hmp->ronly == 0) error = hammer_recover_stage2(hmp, rootvol); /* * If the stage2 recovery fails be sure to clean out all cached * vnodes before throwing away the mount structure or bad things * will happen. */ if (error) vflush(mp, 0, 0); done: if ((mp->mnt_flag & MNT_UPDATE) == 0) { /* New mount */ /* Populate info for mount point (NULL pad)*/ bzero(mp->mnt_stat.f_mntonname, MNAMELEN); size_t size; if (mntpt) { copyinstr(mntpt, mp->mnt_stat.f_mntonname, MNAMELEN -1, &size); } else { /* Root mount */ mp->mnt_stat.f_mntonname[0] = '/'; } } (void)VFS_STATFS(mp, &mp->mnt_stat, cred); hammer_rel_volume(rootvol, 0); failed: /* * Cleanup and return. */ if (error) { /* called with fs_token held */ hammer_free_hmp(mp); } else { lwkt_reltoken(&hmp->fs_token); } return (error); }
/* * Set up swap devices. * Initialize linked list of free swap * headers. These do not actually point * to buffers, but rather to pages that * are being swapped in and out. */ void swapinit() { register int i; register struct buf *sp = swbuf; register struct proc *p = &proc0; /* XXX */ struct swdevt *swp; int error; /* * Count swap devices, and adjust total swap space available. * Some of the space will not be countable until later (dynamically * configurable devices) and some of the counted space will not be * available until a swapon() system call is issued, both usually * happen when the system goes multi-user. * * If using NFS for swap, swdevt[0] will already be bdevvp'd. XXX */ #ifdef SEQSWAP nswdev = niswdev = 0; nswap = niswap = 0; /* * All interleaved devices must come first */ for (swp = swdevt; swp->sw_dev != NODEV || swp->sw_vp != NULL; swp++) { if (swp->sw_flags & SW_SEQUENTIAL) break; niswdev++; if (swp->sw_nblks > niswap) niswap = swp->sw_nblks; } niswap = roundup(niswap, dmmax); niswap *= niswdev; if (swdevt[0].sw_vp == NULL && bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp)) panic("swapvp"); /* * The remainder must be sequential */ for ( ; swp->sw_dev != NODEV; swp++) { if ((swp->sw_flags & SW_SEQUENTIAL) == 0) panic("binit: mis-ordered swap devices"); nswdev++; if (swp->sw_nblks > 0) { if (swp->sw_nblks % dmmax) swp->sw_nblks -= (swp->sw_nblks % dmmax); nswap += swp->sw_nblks; } } nswdev += niswdev; if (nswdev == 0) panic("swapinit"); nswap += niswap; #else nswdev = 0; nswap = 0; for (swp = swdevt; swp->sw_dev != NODEV || swp->sw_vp != NULL; swp++) { nswdev++; if (swp->sw_nblks > nswap) nswap = swp->sw_nblks; } if (nswdev == 0) panic("swapinit"); if (nswdev > 1) nswap = ((nswap + dmmax - 1) / dmmax) * dmmax; nswap *= nswdev; if (swdevt[0].sw_vp == NULL && bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp)) panic("swapvp"); #endif if (nswap == 0) printf("WARNING: no swap space found\n"); else if (error = swfree(p, 0)) { printf("swfree errno %d\n", error); /* XXX */ panic("swapinit swfree 0"); } /* * Now set up swap buffer headers. */ bswlist.b_actf = sp; for (i = 0; i < nswbuf - 1; i++, sp++) { sp->b_actf = sp + 1; sp->b_rcred = sp->b_wcred = p->p_ucred; sp->b_vnbufs.le_next = NOLIST; } sp->b_rcred = sp->b_wcred = p->p_ucred; sp->b_vnbufs.le_next = NOLIST; sp->b_actf = NULL; }
/* * Helper function for findroot(): * Return non-zero if disk device matches bootinfo. */ static int match_bootdisk(struct device *dv, struct btinfo_bootdisk *bid) { struct vnode *tmpvn; int error; struct disklabel label; int found = 0; int bmajor; /* * A disklabel is required here. The boot loader doesn't refuse * to boot from a disk without a label, but this is normally not * wanted. */ if (bid->labelsector == -1) return (0); /* * Lookup major number for disk block device. */ bmajor = devsw_name2blk(dv->dv_xname, NULL, 0); if (bmajor == -1) return (0); /* XXX panic ??? */ /* * Fake a temporary vnode for the disk, open it, and read * the disklabel for comparison. */ if (bdevvp(MAKEDISKDEV(bmajor, dv->dv_unit, RAW_PART), &tmpvn)) panic("match_bootdisk: can't alloc vnode"); error = VOP_OPEN(tmpvn, FREAD, NOCRED); if (error) { #ifndef DEBUG /* * Ignore errors caused by missing device, partition, * or medium. */ if (error != ENXIO && error != ENODEV) #endif printf("match_bootdisk: can't open dev %s (%d)\n", dv->dv_xname, error); vput(tmpvn); return (0); } error = VOP_IOCTL(tmpvn, DIOCGDINFO, &label, FREAD, NOCRED); if (error) { /* * XXX Can't happen -- open() would have errored out * or faked one up. */ printf("match_bootdisk: can't get label for dev %s (%d)\n", dv->dv_xname, error); goto closeout; } /* Compare with our data. */ if (label.d_type == bid->label.type && label.d_checksum == bid->label.checksum && strncmp(label.d_packname, bid->label.packname, 16) == 0) found = 1; closeout: VOP_CLOSE(tmpvn, FREAD, NOCRED); vput(tmpvn); return (found); }
static int ntfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) { size_t size; int error; struct vnode *devvp; struct ntfs_args args; struct nlookupdata nd; struct vnode *rootvp; error = 0; /* * Use NULL path to flag a root mount */ if( path == NULL) { /* *** * Mounting root file system *** */ /* Get vnode for root device*/ if( bdevvp( rootdev, &rootvp)) panic("ffs_mountroot: can't setup bdevvp for root"); /* * FS specific handling */ mp->mnt_flag |= MNT_RDONLY; /* XXX globally applicable?*/ /* * Attempt mount */ if( ( error = ntfs_mountfs(rootvp, mp, &args, cred)) != 0) { /* fs specific cleanup (if any)*/ goto error_1; } goto dostatfs; /* success*/ } /* *** * Mounting non-root file system or updating a file system *** */ /* copy in user arguments*/ error = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args)); if (error) goto error_1; /* can't get arguments*/ /* * If updating, check whether changing from read-only to * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { /* if not updating name...*/ if (args.fspec == NULL) { /* * Process export requests. Jumping to "success" * will return the vfs_export() error code. */ struct ntfsmount *ntm = VFSTONTFS(mp); error = vfs_export(mp, &ntm->ntm_export, &args.export); goto success; } kprintf("ntfs_mount(): MNT_UPDATE not supported\n"); error = EINVAL; goto error_1; } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ devvp = NULL; error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); if (error == 0) error = nlookup(&nd); if (error == 0) error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp); nlookup_done(&nd); if (error) goto error_1; if (!vn_isdisk(devvp, &error)) goto error_2; if (mp->mnt_flag & MNT_UPDATE) { #if 0 /* ******************** * UPDATE ******************** */ if (devvp != ntmp->um_devvp) error = EINVAL; /* needs translation */ else vrele(devvp); /* * Update device name only on success */ if( !error) { /* Save "mounted from" info for mount point (NULL pad)*/ copyinstr( args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); } #endif } else { /* ******************** * NEW MOUNT ******************** */ /* Save "mounted from" info for mount point (NULL pad)*/ copyinstr( args.fspec, /* device name*/ mp->mnt_stat.f_mntfromname, /* save area*/ MNAMELEN - 1, /* max size*/ &size); /* real size*/ bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); error = ntfs_mountfs(devvp, mp, &args, cred); } if (error) { goto error_2; } dostatfs: /* * Initialize FS stat information in mount struct; uses * mp->mnt_stat.f_mntfromname. * * This code is common to root and non-root mounts */ (void)VFS_STATFS(mp, &mp->mnt_stat, cred); goto success; error_2: /* error with devvp held*/ /* release devvp before failing*/ vrele(devvp); error_1: /* no state to back out*/ success: return(error); }
static int ntfs_mount ( struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct proc *p ) { u_int size; int err = 0; struct vnode *devvp; struct ntfs_args args; /* * Use NULL path to flag a root mount */ if( path == NULL) { /* *** * Mounting root file system *** */ /* Get vnode for root device*/ if( bdevvp( rootdev, &rootvp)) panic("ffs_mountroot: can't setup bdevvp for root"); /* * FS specific handling */ mp->mnt_flag |= MNT_RDONLY; /* XXX globally applicable?*/ /* * Attempt mount */ if( ( err = ntfs_mountfs(rootvp, mp, &args, p)) != 0) { /* fs specific cleanup (if any)*/ goto error_1; } goto dostatfs; /* success*/ } /* *** * Mounting non-root file system or updating a file system *** */ /* copy in user arguments*/ err = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args)); if (err) goto error_1; /* can't get arguments*/ /* * If updating, check whether changing from read-only to * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { printf("ntfs_mount(): MNT_UPDATE not supported\n"); err = EINVAL; goto error_1; #if 0 ump = VFSTOUFS(mp); fs = ump->um_fs; err = 0; if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; if (vfs_busy(mp)) { err = EBUSY; goto error_1; } err = ffs_flushfiles(mp, flags, p); vfs_unbusy(mp); } if (!err && (mp->mnt_flag & MNT_RELOAD)) err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); if (err) { goto error_1; } if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { if (!fs->fs_clean) { if (mp->mnt_flag & MNT_FORCE) { printf("WARNING: %s was not properly dismounted.\n",fs->fs_fsmnt); } else { printf("WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck.\n", fs->fs_fsmnt); err = EPERM; goto error_1; } } fs->fs_ronly = 0; } if (fs->fs_ronly == 0) { fs->fs_clean = 0; ffs_sbupdate(ump, MNT_WAIT); } /* if not updating name...*/ if (args.fspec == 0) { /* * Process export requests. Jumping to "success" * will return the vfs_export() error code. */ err = vfs_export(mp, &ump->um_export, &args.export); goto success; }
/* * XXX ugly bit of code. But, this is the only safe time that the * match between BIOS disks and native disks can be done. */ static void matchbiosdisks() { struct btinfo_biosgeom *big; struct bi_biosgeom_entry *be; struct device *dv; struct devnametobdevmaj *d; int i, ck, error, m, n; struct vnode *tv; char mbr[DEV_BSIZE]; big = lookup_bootinfo(BTINFO_BIOSGEOM); if (big == NULL) return; /* * First, count all native disks */ for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) if (dv->dv_class == DV_DISK && (!strcmp(dv->dv_cfdata->cf_driver->cd_name, "sd") || !strcmp(dv->dv_cfdata->cf_driver->cd_name, "wd"))) i386_ndisks++; if (i386_ndisks == 0) return; /* XXX M_TEMP is wrong */ i386_alldisks = malloc(sizeof (struct disklist) + (i386_ndisks - 1) * sizeof (struct nativedisk_info), M_TEMP, M_NOWAIT); if (i386_alldisks == NULL) return; i386_alldisks->dl_nnativedisks = i386_ndisks; i386_alldisks->dl_nbiosdisks = big->num; for (i = 0; i < big->num; i++) { i386_alldisks->dl_biosdisks[i].bi_dev = big->disk[i].dev; i386_alldisks->dl_biosdisks[i].bi_sec = big->disk[i].sec; i386_alldisks->dl_biosdisks[i].bi_head = big->disk[i].head; i386_alldisks->dl_biosdisks[i].bi_cyl = big->disk[i].cyl; i386_alldisks->dl_biosdisks[i].bi_lbasecs = big->disk[i].totsec; i386_alldisks->dl_biosdisks[i].bi_flags = big->disk[i].flags; } /* * XXX code duplication from findroot() */ n = -1; for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) { if (dv->dv_class != DV_DISK) continue; #ifdef GEOM_DEBUG printf("matchbiosdisks: trying to match (%s) %s\n", dv->dv_xname, dv->dv_cfdata->cf_driver->cd_name); #endif if (!strcmp(dv->dv_cfdata->cf_driver->cd_name, "sd") || !strcmp(dv->dv_cfdata->cf_driver->cd_name, "wd")) { n++; sprintf(i386_alldisks->dl_nativedisks[n].ni_devname, "%s%d", dv->dv_cfdata->cf_driver->cd_name, dv->dv_unit); for (d = i386_nam2blk; d->d_name && strcmp(d->d_name, dv->dv_cfdata->cf_driver->cd_name); d++); if (d->d_name == NULL) return; if (bdevvp(MAKEDISKDEV(d->d_maj, dv->dv_unit, RAW_PART), &tv)) panic("matchbiosdisks: can't alloc vnode"); error = VOP_OPEN(tv, FREAD, NOCRED, 0); if (error) { vrele(tv); continue; } error = vn_rdwr(UIO_READ, tv, mbr, DEV_BSIZE, 0, UIO_SYSSPACE, 0, NOCRED, NULL, 0); VOP_CLOSE(tv, FREAD, NOCRED, 0); if (error) { #ifdef GEOM_DEBUG printf("matchbiosdisks: %s: MBR read failure\n", dv->dv_xname); #endif continue; } for (ck = i = 0; i < DEV_BSIZE; i++) ck += mbr[i]; for (m = i = 0; i < big->num; i++) { be = &big->disk[i]; #ifdef GEOM_DEBUG printf("match %s with %d\n", dv->dv_xname, i); printf("dev ck %x bios ck %x\n", ck, be->cksum); #endif if (be->flags & BI_GEOM_INVALID) continue; if (be->cksum == ck && !memcmp(&mbr[MBR_PARTOFF], be->dosparts, NMBRPART * sizeof (struct mbr_partition))) { #ifdef GEOM_DEBUG printf("matched bios disk %x with %s\n", be->dev, be->devname); #endif i386_alldisks->dl_nativedisks[n]. ni_biosmatches[m++] = i; } } i386_alldisks->dl_nativedisks[n].ni_nmatches = m; vrele(tv); } } }