/* * Unmount the filesystem described by mp. */ int msdosfs_unmount(struct mount *mp, int mntflags) { struct msdosfsmount *pmp; int error, flags; flags = 0; if (mntflags & MNT_FORCE) flags |= FORCECLOSE; if ((error = vflush(mp, NULLVP, flags)) != 0) return (error); pmp = VFSTOMSDOSFS(mp); if (pmp->pm_devvp->v_type != VBAD) spec_node_setmountedfs(pmp->pm_devvp, NULL); #ifdef MSDOSFS_DEBUG { struct vnode *vp = pmp->pm_devvp; printf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); printf("flag %08x, usecount %d, writecount %d, holdcnt %d\n", vp->v_vflag | vp->v_iflag | vp->v_uflag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt); printf("mount %p, op %p\n", vp->v_mount, vp->v_op); printf("freef %p, freeb %p, mount %p\n", vp->v_freelist.tqe_next, vp->v_freelist.tqe_prev, vp->v_mount); printf("cleanblkhd %p, dirtyblkhd %p, numoutput %d, type %d\n", vp->v_cleanblkhd.lh_first, vp->v_dirtyblkhd.lh_first, vp->v_numoutput, vp->v_type); printf("union %p, tag %d, data[0] %08x, data[1] %08x\n", vp->v_socket, vp->v_tag, ((u_int *)vp->v_data)[0], ((u_int *)vp->v_data)[1]); } #endif vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY); (void) VOP_CLOSE(pmp->pm_devvp, pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD|FWRITE, NOCRED); vput(pmp->pm_devvp); msdosfs_fh_destroy(pmp); free(pmp->pm_inusemap, M_MSDOSFSFAT); free(pmp, M_MSDOSFSMNT); mp->mnt_data = NULL; mp->mnt_flag &= ~MNT_LOCAL; fstrans_unmount(mp); return (0); }
/* * This opens /dev/tty. Because multiple opens of /dev/tty only * generate a single open to the actual tty, the file modes are * locked to FREAD|FWRITE. */ static int cttyopen(struct dev_open_args *ap) { struct proc *p = curproc; struct vnode *ttyvp; int error; KKASSERT(p); retry: if ((ttyvp = cttyvp(p)) == NULL) return (ENXIO); if (ttyvp->v_flag & VCTTYISOPEN) return (0); /* * Messy interlock, don't let the vnode go away while we try to * lock it and check for race after we might have blocked. * * WARNING! The device open (devfs_spec_open()) temporarily * releases the vnode lock on ttyvp when issuing the * dev_dopen(), which means that the VCTTYISOPEn flag * can race during the VOP_OPEN(). * * If something does race we have to undo our potentially * extra open. */ vhold(ttyvp); vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY); if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) { kprintf("Warning: cttyopen: race-1 avoided\n"); vn_unlock(ttyvp); vdrop(ttyvp); goto retry; } error = VOP_OPEN(ttyvp, FREAD|FWRITE, ap->a_cred, NULL); if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) { kprintf("Warning: cttyopen: race-2 avoided\n"); if (error == 0) VOP_CLOSE(ttyvp, FREAD|FWRITE); vn_unlock(ttyvp); vdrop(ttyvp); goto retry; } if (error == 0) vsetflags(ttyvp, VCTTYISOPEN); vn_unlock(ttyvp); vdrop(ttyvp); return(error); }
static void spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl) { size_t buflen; char *buf; vnode_t *vp; int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX; char *temp; /* * If the nvlist is empty (NULL), then remove the old cachefile. */ if (nvl == NULL) { (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE); return; } /* * Pack the configuration into a buffer. */ VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0); buf = kmem_alloc(buflen, KM_SLEEP); temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP); VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR, KM_SLEEP) == 0); /* * Write the configuration to disk. We need to do the traditional * 'write to temporary file, sync, move over original' to make sure we * always have a consistent view of the data. */ (void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path); if (vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) == 0) { if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL) == 0 && VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) { (void) vn_rename(temp, dp->scd_path, UIO_SYSSPACE); } (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL); } (void) vn_remove(temp, UIO_SYSSPACE, RMFILE); kmem_free(buf, buflen); kmem_free(temp, MAXPATHLEN); }
/* * Vnode close call * * Note: takes an unlocked vnode, while VOP_CLOSE takes a locked node. */ int vn_close(struct vnode *vp, int flags, kauth_cred_t cred) { int error; if (flags & FWRITE) { mutex_enter(vp->v_interlock); KASSERT(vp->v_writecount > 0); vp->v_writecount--; mutex_exit(vp->v_interlock); } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); error = VOP_CLOSE(vp, flags, cred); vput(vp); return (error); }
static void vdev_file_close(vdev_t *vd) { vdev_file_t *vf = vd->vdev_tsd; if (vf == NULL) return; if (vf->vf_vnode != NULL) { (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred, NULL); (void) VOP_CLOSE(vf->vf_vnode, spa_mode, 1, 0, kcred, NULL); VN_RELE(vf->vf_vnode); } kmem_free(vf, sizeof (vdev_file_t)); vd->vdev_tsd = NULL; }
static void vdev_file_close(vdev_t *vd) { vdev_file_t *vf = vd->vdev_tsd; if (vd->vdev_reopening || vf == NULL) return; if (vf->vf_vnode != NULL) { (void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0, kcred, NULL); } vd->vdev_delayed_close = B_FALSE; kmem_free(vf, sizeof (vdev_file_t)); vd->vdev_tsd = NULL; }
/* * unmount system call */ int ffs_unmount(struct mount *mp, int mntflags, struct proc *p) { struct ufsmount *ump; struct fs *fs; int error, flags; flags = 0; if (mntflags & MNT_FORCE) flags |= FORCECLOSE; ump = VFSTOUFS(mp); fs = ump->um_fs; if (mp->mnt_flag & MNT_SOFTDEP) error = softdep_flushfiles(mp, flags, p); else error = ffs_flushfiles(mp, flags, p); if (error != 0) return (error); if (fs->fs_ronly == 0) { fs->fs_clean = (fs->fs_flags & FS_UNCLEAN) ? 0 : 1; error = ffs_sbupdate(ump, MNT_WAIT); /* ignore write errors if mounted RW on read-only device */ if (error && error != EROFS) { fs->fs_clean = 0; return (error); } free(fs->fs_contigdirs, M_UFSMNT); } ump->um_devvp->v_specmountpoint = NULL; vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0); error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, NOCRED, p); VOP_UNLOCK(ump->um_devvp, 0, p); vrele(ump->um_devvp); free(fs->fs_csp, M_UFSMNT); free(fs, M_UFSMNT); free(ump, M_UFSMNT); mp->mnt_data = (qaddr_t)0; mp->mnt_flag &= ~MNT_LOCAL; return (error); }
/* * If the cpr default file is invalid, then we must not be in reusable mode * if it is valid, it tells us our mode */ int cpr_get_reusable_mode(void) { struct vnode *vp; cmini_t mini; int rc; if (cpr_open(cpr_default_path, FREAD, &vp)) return (0); rc = cpr_rdwr(UIO_READ, vp, &mini, sizeof (mini)); (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL); VN_RELE(vp); if (rc == 0 && mini.magic == CPR_DEFAULT_MAGIC) return (mini.reusable); return (0); }
/* * Helper function for findroot(): * Return non-zero if disk device matches bootinfo. */ static int match_bootdisk(device_t dv, struct btinfo_bootdisk *bid) { struct vnode *tmpvn; int error; struct disklabel label; int found = 0; if (device_is_a(dv, "dk")) return 0; /* * 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); if ((tmpvn = opendisk(dv)) == NULL) 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("findroot: can't get label for dev %s (%d)\n", device_xname(dv), 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); }
/* * Helper function for findroot(): * Return non-zero if wedge device matches bootinfo. */ static int match_bootwedge(device_t dv, struct btinfo_bootwedge *biw) { MD5_CTX ctx; struct vnode *tmpvn; int error; uint8_t bf[DEV_BSIZE]; uint8_t hash[16]; int found = 0; daddr_t blk; uint64_t nblks; /* * If the boot loader didn't specify the sector, abort. */ if (biw->matchblk == -1) return (0); if ((tmpvn = opendisk(dv)) == NULL) return 0; MD5Init(&ctx); for (blk = biw->matchblk, nblks = biw->matchnblks; nblks != 0; nblks--, blk++) { error = vn_rdwr(UIO_READ, tmpvn, (void *) bf, sizeof(bf), blk * DEV_BSIZE, UIO_SYSSPACE, 0, NOCRED, NULL, NULL); if (error) { printf("findroot: unable to read block %" PRId64 " " "of dev %s (%d)\n", blk, device_xname(dv), error); goto closeout; } MD5Update(&ctx, bf, sizeof(bf)); } MD5Final(hash, &ctx); /* Compare with the provided hash. */ found = memcmp(biw->matchhash, hash, sizeof(hash)) == 0; closeout: VOP_CLOSE(tmpvn, FREAD, NOCRED); vput(tmpvn); return (found); }
static int splat_vnode_test6(struct file *file, void *arg) { vnode_t *vp; char buf[32] = "SPL VNode Interface Test File\n"; int rc; if ((rc = splat_vnode_unlink_all(file, arg, SPLAT_VNODE_TEST6_NAME))) return rc; if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, FWRITE | FCREAT | FEXCL, 0644, &vp, 0, 0))) { splat_vprint(file, SPLAT_VNODE_TEST6_NAME, "Failed to vn_open test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW, rc); return -rc; } rc = vn_rdwr(UIO_WRITE, vp, buf, strlen(buf), 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL); if (rc) { splat_vprint(file, SPLAT_VNODE_TEST6_NAME, "Failed vn_rdwr write of test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW, rc); goto out; } rc = vn_fsync(vp, 0, 0, 0); if (rc) { splat_vprint(file, SPLAT_VNODE_TEST6_NAME, "Failed vn_fsync of test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW, rc); goto out; } rc = 0; splat_vprint(file, SPLAT_VNODE_TEST6_NAME, "Successfully " "fsync'ed test file %s\n", SPLAT_VNODE_TEST_FILE_RW); out: VOP_CLOSE(vp, 0, 0, 0, 0, 0); vn_remove(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, RMFILE); return -rc; } /* splat_vnode_test6() */
/* ARGSUSED */ static void acct_shutdown(zoneid_t zoneid, void *arg) { struct acct_globals *ag = arg; mutex_enter(&ag->aclock); if (ag->acctvp) { /* * This needs to be done as a shutdown callback, otherwise this * held vnode may cause filesystems to be busy, and the zone * shutdown operation to fail. */ (void) VOP_CLOSE(ag->acctvp, FWRITE, 1, (offset_t)0, kcred, NULL); VN_RELE(ag->acctvp); } ag->acctvp = NULL; mutex_exit(&ag->aclock); }
int udf_unmount(struct mount *mp, int mntflags, struct proc *p) { struct umount *ump; struct vnode *devvp; int error, flags = 0; ump = VFSTOUDFFS(mp); devvp = ump->um_devvp; if (mntflags & MNT_FORCE) flags |= FORCECLOSE; if ((error = vflush(mp, NULL, flags))) return (error); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); vinvalbuf(devvp, V_SAVE, NOCRED, p, 0, 0); error = VOP_CLOSE(devvp, FREAD, NOCRED, p); VOP_UNLOCK(devvp, 0, p); if (error) return (error); devvp->v_specmountpoint = NULL; vrele(devvp); if (ump->um_flags & UDF_MNT_USES_VAT) free(ump->um_vat, M_UDFMOUNT); if (ump->um_stbl != NULL) free(ump->um_stbl, M_UDFMOUNT); if (ump->um_hashtbl != NULL) free(ump->um_hashtbl, M_UDFMOUNT); free(ump, M_UDFMOUNT); mp->mnt_data = (qaddr_t)0; mp->mnt_flag &= ~MNT_LOCAL; return (0); }
int cnclose(dev_t dev, int flag, int mode, struct lwp *l) { struct vnode *vp; int unit, error; unit = minor(dev); if (cn_tab == NULL) return (0); vp = cn_devvp[unit]; cn_devvp[unit] = NULL; error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if (error == 0) { error = VOP_CLOSE(vp, flag, kauth_cred_get()); VOP_UNLOCK(vp); } return error; }
static void vdev_file_close(vdev_t *vd) { vdev_file_t *vf = vd->vdev_tsd; if (vd->vdev_reopening || vf == NULL) return; if (vf->vf_vnode != NULL) { vnode_getwithvid(vf->vf_vnode, vf->vf_vid); // Also commented out in MacZFS //(void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred, NULL); (void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0, kcred, NULL); } vd->vdev_delayed_close = B_FALSE; kmem_free(vf, sizeof (vdev_file_t)); vd->vdev_tsd = NULL; }
/* * This closes /dev/tty. Because multiple opens of /dev/tty only * generate a single open to the actual tty, the file modes are * locked to FREAD|FWRITE. */ static int cttyclose(struct dev_close_args *ap) { struct proc *p = curproc; struct vnode *ttyvp; int error; KKASSERT(p); retry: /* * The tty may have been TIOCNOTTY'd, don't return an * error on close. We just have nothing to do. */ if ((ttyvp = cttyvp(p)) == NULL) return(0); if (ttyvp->v_flag & VCTTYISOPEN) { /* * Avoid a nasty race if we block while getting the lock. */ vref(ttyvp); error = vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY | LK_FAILRECLAIM); if (error) { vrele(ttyvp); goto retry; } if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN) == 0) { kprintf("Warning: cttyclose: race avoided\n"); vn_unlock(ttyvp); vrele(ttyvp); goto retry; } vclrflags(ttyvp, VCTTYISOPEN); error = VOP_CLOSE(ttyvp, FREAD|FWRITE); vn_unlock(ttyvp); vrele(ttyvp); } else { error = 0; } return(error); }
void hfs_libcb_closedev(hfs_volume* in_vol, hfs_callback_args* cbargs) { struct vnode *devvp; if (in_vol == NULL) return; if (in_vol->cbdata != NULL) { devvp = ((hfs_libcb_data*)in_vol->cbdata)->devvp; if (devvp != NULL) { vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); (void)VOP_CLOSE(devvp, in_vol->readonly ? FREAD : FREAD | FWRITE, NOCRED); /* XXX do we need a VOP_UNLOCK() here? */ } free(in_vol->cbdata, M_HFSMNT); in_vol->cbdata = NULL; } }
/* ARGSUSED */ static int xattr_dir_close(vnode_t *vp, int flags, int count, offset_t off, cred_t *cr, caller_context_t *ct) { vnode_t *realvp; int error; /* * If there is a real extended attribute directory, * let the underlying FS see the VOP_CLOSE call; * otherwise just return zero. */ error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct); if (error == 0) { error = VOP_CLOSE(realvp, flags, count, off, cr, ct); } else { error = 0; } return (error); }
static int splat_vnode_test5(struct file *file, void *arg) { vnode_t *vp; vattr_t vap; int rc; if ((rc = vn_open(SPLAT_VNODE_TEST_FILE, UIO_SYSSPACE, FREAD, 0644, &vp, 0, 0))) { splat_vprint(file, SPLAT_VNODE_TEST5_NAME, "Failed to vn_open test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE, rc); return -rc; } rc = VOP_GETATTR(vp, &vap, 0, 0, NULL); if (rc) { splat_vprint(file, SPLAT_VNODE_TEST5_NAME, "Failed to vn_getattr test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE, rc); goto out; } if (vap.va_type != VREG) { rc = EINVAL; splat_vprint(file, SPLAT_VNODE_TEST5_NAME, "Failed expected regular file type " "(%d != VREG): %s (%d)\n", vap.va_type, SPLAT_VNODE_TEST_FILE, rc); goto out; } splat_vprint(file, SPLAT_VNODE_TEST1_NAME, "Successfully " "vn_getattr'ed test file: %s\n", SPLAT_VNODE_TEST_FILE); out: VOP_CLOSE(vp, 0, 0, 0, 0, 0); return -rc; } /* splat_vnode_test5() */
/* * write cdef_t to disk. This contains the original values of prom * properties that we modify. We fill in the magic number of the file * here as a signal to the booter code that the state file is valid. * Be sure the file gets synced, since we may be shutting down the OS. */ int cpr_write_deffile(cdef_t *cdef) { struct vnode *vp; char *str; int rc; if (rc = cpr_open_deffile(FCREAT|FWRITE, &vp)) return (rc); if (rc = cpr_rdwr(UIO_WRITE, vp, cdef, sizeof (*cdef))) str = "write"; else if (rc = VOP_FSYNC(vp, FSYNC, CRED(), NULL)) str = "fsync"; (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL); VN_RELE(vp); if (rc) { cpr_err(CE_WARN, "%s error %d, file \"%s\"", str, rc, cpr_default_path); } return (rc); }
int i_cpr_check_cprinfo(void) { struct vnode *vp; cmini_t mini; int rc = 0; if (rc = cpr_open_deffile(FREAD, &vp)) { if (rc == ENOENT) cpr_err(CE_NOTE, "cprinfo file does not " "exist. You must run 'uadmin %d %d' " "command while / is mounted writeable,\n" "then reboot and run 'uadmin %d %d' " "to create a reusable statefile", A_FREEZE, AD_REUSEINIT, A_FREEZE, AD_REUSABLE); return (rc); } rc = cpr_rdwr(UIO_READ, vp, &mini, sizeof (mini)); (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL); VN_RELE(vp); if (rc) { cpr_err(CE_WARN, "Failed reading %s, errno = %d", cpr_default_path, rc); } else if (mini.magic != CPR_DEFAULT_MAGIC) { cpr_err(CE_CONT, "bad magic number in cprinfo file.\n" "You must run 'uadmin %d %d' while / is mounted " "writeable, then reboot and run 'uadmin %d %d' " "to create a reusable statefile\n", A_FREEZE, AD_REUSEINIT, A_FREEZE, AD_REUSABLE); rc = EINVAL; } return (rc); }
int v7fs_unmount(struct mount *mp, int mntflags) { struct v7fs_mount *v7fsmount = (void *)mp->mnt_data; int error; DPRINTF("%p\n", v7fsmount); if ((error = vflush(mp, NULLVP, mntflags & MNT_FORCE ? FORCECLOSE : 0)) != 0) return error; vn_lock(v7fsmount->devvp, LK_EXCLUSIVE | LK_RETRY); error = VOP_CLOSE(v7fsmount->devvp, FREAD, NOCRED); vput(v7fsmount->devvp); v7fs_io_fini(v7fsmount->core); kmem_free(v7fsmount, sizeof(*v7fsmount)); mp->mnt_data = NULL; mp->mnt_flag &= ~MNT_LOCAL; return 0; }
/* * Decrement the open count. * Called by VOP_DECOPEN. */ void vnode_decopen(struct vnode *vn) { int opencount, result; assert(vn!=NULL); lock_acquire(vn->vn_countlock); assert(vn->vn_opencount>0); vn->vn_opencount--; opencount = vn->vn_opencount; lock_release(vn->vn_countlock); if (opencount > 0) { return; } result = VOP_CLOSE(vn); if (result) { // XXX: also lame. // The FS should do what it can to make sure this code // doesn't get reached... kprintf("vfs: Warning: VOP_CLOSE: %s\n", strerror(result)); } }
/* * unmount system call */ int cd9660_unmount(struct mount *mp, int mntflags) { struct iso_mnt *isomp; int error, flags = 0; if (mntflags & MNT_FORCE) flags |= FORCECLOSE; if ((error = vflush(mp, NULLVP, flags)) != 0) return (error); isomp = VFSTOISOFS(mp); if (isomp->im_devvp->v_type != VBAD) spec_node_setmountedfs(isomp->im_devvp, NULL); vn_lock(isomp->im_devvp, LK_EXCLUSIVE | LK_RETRY); error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED); vput(isomp->im_devvp); free(isomp, M_ISOFSMNT); mp->mnt_data = NULL; mp->mnt_flag &= ~MNT_LOCAL; return (error); }
/* * reads config data into cprconfig */ static int cpr_get_config(void) { static char config_path[] = CPR_CONFIG; struct cprconfig *cf = &cprconfig; struct vnode *vp; char *fmt; int err; if (cprconfig_loaded) return (0); fmt = "cannot %s config file \"%s\", error %d\n"; if (err = vn_open(config_path, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0)) { cpr_err(CE_CONT, fmt, "open", config_path, err); return (err); } err = cpr_rdwr(UIO_READ, vp, cf, sizeof (*cf)); (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL); VN_RELE(vp); if (err) { cpr_err(CE_CONT, fmt, "read", config_path, err); return (err); } if (cf->cf_magic == CPR_CONFIG_MAGIC) cprconfig_loaded = 1; else { cpr_err(CE_CONT, "invalid config file \"%s\", " "rerun pmconfig(1M)\n", config_path); err = EINVAL; } return (err); }
/* * unmount system call */ int ext2fs_unmount(struct mount *mp, int mntflags, struct proc *p) { struct ufsmount *ump; struct m_ext2fs *fs; int error, flags; size_t gdescs_space; flags = 0; if (mntflags & MNT_FORCE) flags |= FORCECLOSE; if ((error = ext2fs_flushfiles(mp, flags, p)) != 0) return (error); ump = VFSTOUFS(mp); fs = ump->um_e2fs; gdescs_space = fs->e2fs_ngdb * fs->e2fs_bsize; if (!fs->e2fs_ronly && ext2fs_cgupdate(ump, MNT_WAIT) == 0 && (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) { fs->e2fs.e2fs_state = E2FS_ISCLEAN; (void) ext2fs_sbupdate(ump, MNT_WAIT); } if (ump->um_devvp->v_type != VBAD) ump->um_devvp->v_specmountpoint = NULL; vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); (void)VOP_CLOSE(ump->um_devvp, fs->e2fs_ronly ? FREAD : FREAD|FWRITE, NOCRED, p); vput(ump->um_devvp); free(fs->e2fs_gd, M_UFSMNT, gdescs_space); free(fs, M_UFSMNT, sizeof *fs); free(ump, M_UFSMNT, sizeof *ump); mp->mnt_data = NULL; mp->mnt_flag &= ~MNT_LOCAL; return (0); }
/* * Synchronize all pools to disk. This must be called with the namespace lock * held. */ void spa_config_sync(void) { spa_t *spa = NULL; nvlist_t *config; size_t buflen; char *buf; vnode_t *vp; int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX; char pathname[128]; char pathname2[128]; ASSERT(MUTEX_HELD(&spa_namespace_lock)); VERIFY(nvlist_alloc(&config, NV_UNIQUE_NAME, KM_SLEEP) == 0); /* * Add all known pools to the configuration list, ignoring those with * alternate root paths. */ spa = NULL; while ((spa = spa_next(spa)) != NULL) { mutex_enter(&spa->spa_config_cache_lock); if (spa->spa_config && spa->spa_name && spa->spa_root == NULL) VERIFY(nvlist_add_nvlist(config, spa->spa_name, spa->spa_config) == 0); mutex_exit(&spa->spa_config_cache_lock); } /* * Pack the configuration into a buffer. */ VERIFY(nvlist_size(config, &buflen, NV_ENCODE_XDR) == 0); buf = kmem_alloc(buflen, KM_SLEEP); VERIFY(nvlist_pack(config, &buf, &buflen, NV_ENCODE_XDR, KM_SLEEP) == 0); /* * Write the configuration to disk. We need to do the traditional * 'write to temporary file, sync, move over original' to make sure we * always have a consistent view of the data. */ (void) snprintf(pathname, sizeof (pathname), "%s/%s", spa_config_dir, ZPOOL_CACHE_TMP); if (vn_open(pathname, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) != 0) goto out; if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL) == 0 && VOP_FSYNC(vp, FSYNC, kcred) == 0) { (void) snprintf(pathname2, sizeof (pathname2), "%s/%s", spa_config_dir, ZPOOL_CACHE_FILE); (void) vn_rename(pathname, pathname2, UIO_SYSSPACE); } (void) VOP_CLOSE(vp, oflags, 1, 0, kcred); VN_RELE(vp); out: (void) vn_remove(pathname, UIO_SYSSPACE, RMFILE); spa_config_generation++; kmem_free(buf, buflen); nvlist_free(config); }
static void spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl) { size_t buflen; char *buf; vnode_t *vp; int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX; int error; char *temp; /* * If the nvlist is empty (NULL), then remove the old cachefile. */ if (nvl == NULL) { (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE); return; } /* * Pack the configuration into a buffer. */ VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0); buf = vmem_alloc(buflen, KM_SLEEP); temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP); VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR, KM_SLEEP) == 0); #if defined(__linux__) && defined(_KERNEL) /* * Write the configuration to disk. Due to the complexity involved * in performing a rename from within the kernel the file is truncated * and overwritten in place. In the event of an error the file is * unlinked to make sure we always have a consistent view of the data. */ error = vn_open(dp->scd_path, UIO_SYSSPACE, oflags, 0644, &vp, 0, 0); if (error == 0) { error = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL); if (error == 0) error = VOP_FSYNC(vp, FSYNC, kcred, NULL); (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL); if (error) (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE); } #else /* * Write the configuration to disk. We need to do the traditional * 'write to temporary file, sync, move over original' to make sure we * always have a consistent view of the data. */ (void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path); error = vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0); if (error == 0) { if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL) == 0 && VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) { (void) vn_rename(temp, dp->scd_path, UIO_SYSSPACE); } (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL); } (void) vn_remove(temp, UIO_SYSSPACE, RMFILE); #endif vmem_free(buf, buflen); kmem_free(temp, MAXPATHLEN); }
int msdosfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct msdosfs_args *argp) { struct msdosfsmount *pmp; struct buf *bp; dev_t dev = devvp->v_rdev; union bootsector *bsp; struct byte_bpb33 *b33; struct byte_bpb50 *b50; struct byte_bpb710 *b710; extern struct vnode *rootvp; u_int8_t SecPerClust; int ronly, error, bmapsiz; uint32_t fat_max_clusters; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use * (except for root, which might share swap device for miniroot). * Flush out any old buffers remaining from a previous use. */ if ((error = vfs_mountedon(devvp)) != 0) return (error); if (vcount(devvp) > 1 && devvp != rootvp) return (EBUSY); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); VOP_UNLOCK(devvp, 0, p); if (error) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); if (error) return (error); bp = NULL; /* both used in error_exit */ pmp = NULL; /* * Read the boot sector of the filesystem, and then check the * boot signature. If not a dos boot sector then error out. */ if ((error = bread(devvp, 0, 4096, NOCRED, &bp)) != 0) goto error_exit; bp->b_flags |= B_AGE; bsp = (union bootsector *)bp->b_data; b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP; pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO); pmp->pm_mountp = mp; /* * Compute several useful quantities from the bpb in the * bootsector. Copy in the dos 5 variant of the bpb then fix up * the fields that are different between dos 5 and dos 3.3. */ SecPerClust = b50->bpbSecPerClust; pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); pmp->pm_ResSectors = getushort(b50->bpbResSectors); pmp->pm_FATs = b50->bpbFATs; pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); pmp->pm_Sectors = getushort(b50->bpbSectors); pmp->pm_FATsecs = getushort(b50->bpbFATsecs); pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); pmp->pm_Heads = getushort(b50->bpbHeads); pmp->pm_Media = b50->bpbMedia; /* Determine the number of DEV_BSIZE blocks in a MSDOSFS sector */ pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; if (!pmp->pm_BytesPerSec || !SecPerClust || pmp->pm_SecPerTrack > 64) { error = EFTYPE; goto error_exit; } if (pmp->pm_Sectors == 0) { pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); } else { pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); pmp->pm_HugeSectors = pmp->pm_Sectors; } if (pmp->pm_RootDirEnts == 0) { if (pmp->pm_Sectors || pmp->pm_FATsecs || getushort(b710->bpbFSVers)) { error = EINVAL; goto error_exit; } pmp->pm_fatmask = FAT32_MASK; pmp->pm_fatmult = 4; pmp->pm_fatdiv = 1; pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); if (getushort(b710->bpbExtFlags) & FATMIRROR) pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; else pmp->pm_flags |= MSDOSFS_FATMIRROR; } else pmp->pm_flags |= MSDOSFS_FATMIRROR; /* * More sanity checks: * MSDOSFS sectors per cluster: >0 && power of 2 * MSDOSFS sector size: >= DEV_BSIZE && power of 2 * HUGE sector count: >0 * FAT sectors: >0 */ if ((SecPerClust == 0) || (SecPerClust & (SecPerClust - 1)) || (pmp->pm_BytesPerSec < DEV_BSIZE) || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) || (pmp->pm_HugeSectors == 0) || (pmp->pm_FATsecs == 0)) { error = EINVAL; goto error_exit; } pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; pmp->pm_FATsecs *= pmp->pm_BlkPerSec; pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; SecPerClust *= pmp->pm_BlkPerSec; if (FAT32(pmp)) { pmp->pm_rootdirblk = getulong(b710->bpbRootClust); pmp->pm_firstcluster = pmp->pm_fatblk + (pmp->pm_FATs * pmp->pm_FATsecs); pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; } else { pmp->pm_rootdirblk = pmp->pm_fatblk + (pmp->pm_FATs * pmp->pm_FATsecs); pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) + DEV_BSIZE - 1) / DEV_BSIZE; pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; } pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / SecPerClust; pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; if (pmp->pm_fatmask == 0) { if (pmp->pm_maxcluster <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { /* * This will usually be a floppy disk. This size makes * sure that one fat entry will not be split across * multiple blocks. */ pmp->pm_fatmask = FAT12_MASK; pmp->pm_fatmult = 3; pmp->pm_fatdiv = 2; } else { pmp->pm_fatmask = FAT16_MASK; pmp->pm_fatmult = 2; pmp->pm_fatdiv = 1; } } if (FAT12(pmp)) pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; else pmp->pm_fatblocksize = MAXBSIZE; /* * We now have the number of sectors in each FAT, so can work * out how many clusters can be represented in a FAT. Let's * make sure the file system doesn't claim to have more clusters * than this. * * We perform the calculation like we do to avoid integer overflow. * * This will give us a count of clusters. They are numbered * from 0, so the max cluster value is one less than the value * we end up with. */ fat_max_clusters = pmp->pm_fatsize / pmp->pm_fatmult; fat_max_clusters *= pmp->pm_fatdiv; if (pmp->pm_maxcluster >= fat_max_clusters) { #ifndef SMALL_KERNEL printf("msdosfs: reducing max cluster to %d from %d " "due to FAT size\n", fat_max_clusters - 1, pmp->pm_maxcluster); #endif pmp->pm_maxcluster = fat_max_clusters - 1; } pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; /* * Compute mask and shift value for isolating cluster relative byte * offsets and cluster numbers from a file offset. */ pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; pmp->pm_crbomask = pmp->pm_bpcluster - 1; pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; /* * Check for valid cluster size * must be a power of 2 */ if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { error = EFTYPE; goto error_exit; } /* * Release the bootsector buffer. */ brelse(bp); bp = NULL; /* * Check FSInfo */ if (pmp->pm_fsinfo) { struct fsinfo *fp; if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp), NOCRED, &bp)) != 0) goto error_exit; fp = (struct fsinfo *)bp->b_data; if (!bcmp(fp->fsisig1, "RRaA", 4) && !bcmp(fp->fsisig2, "rrAa", 4) && !bcmp(fp->fsisig3, "\0\0\125\252", 4) && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) /* Valid FSInfo. */ ; else pmp->pm_fsinfo = 0; /* XXX make sure this tiny buf doesn't come back in fillinusemap! */ SET(bp->b_flags, B_INVAL); brelse(bp); bp = NULL; } /* * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX */ /* * Allocate memory for the bitmap of allocated clusters, and then * fill it in. */ bmapsiz = (pmp->pm_maxcluster + N_INUSEBITS - 1) / N_INUSEBITS; if (bmapsiz == 0 || SIZE_MAX / bmapsiz < sizeof(*pmp->pm_inusemap)) { /* detect multiplicative integer overflow */ error = EINVAL; goto error_exit; } pmp->pm_inusemap = malloc(bmapsiz * sizeof(*pmp->pm_inusemap), M_MSDOSFSFAT, M_WAITOK | M_CANFAIL); if (pmp->pm_inusemap == NULL) { error = EINVAL; goto error_exit; } /* * fillinusemap() needs pm_devvp. */ pmp->pm_dev = dev; pmp->pm_devvp = devvp; /* * Have the inuse map filled in. */ if ((error = fillinusemap(pmp)) != 0) goto error_exit; /* * If they want fat updates to be synchronous then let them suffer * the performance degradation in exchange for the on disk copy of * the fat being correct just about all the time. I suppose this * would be a good thing to turn on if the kernel is still flakey. */ if (mp->mnt_flag & MNT_SYNCHRONOUS) pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; /* * Finish up. */ if (ronly) pmp->pm_flags |= MSDOSFSMNT_RONLY; else pmp->pm_fmod = 1; mp->mnt_data = (qaddr_t)pmp; mp->mnt_stat.f_fsid.val[0] = (long)dev; mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; #ifdef QUOTA /* * If we ever do quotas for DOS filesystems this would be a place * to fill in the info in the msdosfsmount structure. You dolt, * quotas on dos filesystems make no sense because files have no * owners on dos filesystems. of course there is some empty space * in the directory entry where we could put uid's and gid's. */ #endif devvp->v_specmountpoint = mp; return (0); error_exit: devvp->v_specmountpoint = NULL; if (bp) brelse(bp); vn_lock(devvp, LK_EXCLUSIVE|LK_RETRY, p); (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); VOP_UNLOCK(devvp, 0, p); if (pmp) { if (pmp->pm_inusemap) free(pmp->pm_inusemap, M_MSDOSFSFAT); free(pmp, M_MSDOSFSMNT); mp->mnt_data = (qaddr_t)0; } return (error); }
int udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p) { struct buf *bp = NULL; struct anchor_vdp avdp; struct umount *ump = NULL; struct part_desc *pd; struct logvol_desc *lvd; struct fileset_desc *fsd; struct extfile_entry *xfentry; struct file_entry *fentry; uint32_t sector, size, mvds_start, mvds_end; uint32_t fsd_offset = 0; uint16_t part_num = 0, fsd_part = 0; int error = EINVAL; int logvol_found = 0, part_found = 0, fsd_found = 0; int bsize; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use * (except for root, which might share swap device for miniroot). * Flush out any old buffers remaining from a previous use. */ if ((error = vfs_mountedon(devvp))) return (error); if (vcount(devvp) > 1 && devvp != rootvp) return (EBUSY); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); VOP_UNLOCK(devvp, 0, p); if (error) return (error); error = VOP_OPEN(devvp, FREAD, FSCRED, p); if (error) return (error); ump = malloc(sizeof(*ump), M_UDFMOUNT, M_WAITOK | M_ZERO); mp->mnt_data = (qaddr_t) ump; mp->mnt_stat.f_fsid.val[0] = devvp->v_rdev; mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_UDF); mp->mnt_flag |= MNT_LOCAL; ump->um_mountp = mp; ump->um_dev = devvp->v_rdev; ump->um_devvp = devvp; bsize = 2048; /* Should probe the media for its size. */ /* * Get the Anchor Volume Descriptor Pointer from sector 256. * Should also check sector n - 256, n, and 512. */ sector = 256; if ((error = bread(devvp, sector * btodb(bsize), bsize, NOCRED, &bp)) != 0) goto bail; if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR))) goto bail; bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp)); brelse(bp); bp = NULL; /* * Extract the Partition Descriptor and Logical Volume Descriptor * from the Volume Descriptor Sequence. * Should we care about the partition type right now? * What about multiple partitions? */ mvds_start = letoh32(avdp.main_vds_ex.loc); mvds_end = mvds_start + (letoh32(avdp.main_vds_ex.len) - 1) / bsize; for (sector = mvds_start; sector < mvds_end; sector++) { if ((error = bread(devvp, sector * btodb(bsize), bsize, NOCRED, &bp)) != 0) { printf("Can't read sector %d of VDS\n", sector); goto bail; } lvd = (struct logvol_desc *)bp->b_data; if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) { ump->um_bsize = letoh32(lvd->lb_size); ump->um_bmask = ump->um_bsize - 1; ump->um_bshift = ffs(ump->um_bsize) - 1; fsd_part = letoh16(lvd->_lvd_use.fsd_loc.loc.part_num); fsd_offset = letoh32(lvd->_lvd_use.fsd_loc.loc.lb_num); if (udf_find_partmaps(ump, lvd)) break; logvol_found = 1; } pd = (struct part_desc *)bp->b_data; if (!udf_checktag(&pd->tag, TAGID_PARTITION)) { part_found = 1; part_num = letoh16(pd->part_num); ump->um_len = ump->um_reallen = letoh32(pd->part_len); ump->um_start = ump->um_realstart = letoh32(pd->start_loc); } brelse(bp); bp = NULL; if ((part_found) && (logvol_found)) break; } if (!part_found || !logvol_found) { error = EINVAL; goto bail; } if (ISSET(ump->um_flags, UDF_MNT_USES_META)) { /* Read Metadata File 'File Entry' to find Metadata file. */ struct long_ad *la; sector = ump->um_start + ump->um_meta_start; /* Set in udf_get_mpartmap() */ if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) { printf("Cannot read sector %d for Metadata File Entry\n", sector); error = EINVAL; goto bail; } xfentry = (struct extfile_entry *)bp->b_data; fentry = (struct file_entry *)bp->b_data; if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) la = (struct long_ad *)&xfentry->data[letoh32(xfentry->l_ea)]; else if (udf_checktag(&fentry->tag, TAGID_FENTRY) == 0) la = (struct long_ad *)&fentry->data[letoh32(fentry->l_ea)]; else { printf("Invalid Metadata File FE @ sector %d! (tag.id %d)\n", sector, fentry->tag.id); error = EINVAL; goto bail; } ump->um_meta_start = letoh32(la->loc.lb_num); ump->um_meta_len = letoh32(la->len); if (bp != NULL) { brelse(bp); bp = NULL; } } else if (fsd_part != part_num) { printf("FSD does not lie within the partition!\n"); error = EINVAL; goto bail; } mtx_init(&ump->um_hashmtx, IPL_NONE); ump->um_hashtbl = hashinit(UDF_HASHTBLSIZE, M_UDFMOUNT, M_WAITOK, &ump->um_hashsz); /* Get the VAT, if needed */ if (ump->um_flags & UDF_MNT_FIND_VAT) { error = udf_vat_get(ump, lb); if (error) goto bail; } /* * Grab the Fileset Descriptor * Thanks to Chuck McCrobie <*****@*****.**> for pointing * me in the right direction here. */ if (ISSET(ump->um_flags, UDF_MNT_USES_META)) sector = ump->um_meta_start; else sector = fsd_offset; udf_vat_map(ump, §or); if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) { printf("Cannot read sector %d of FSD\n", sector); goto bail; } fsd = (struct fileset_desc *)bp->b_data; if (!udf_checktag(&fsd->tag, TAGID_FSD)) { fsd_found = 1; bcopy(&fsd->rootdir_icb, &ump->um_root_icb, sizeof(struct long_ad)); if (ISSET(ump->um_flags, UDF_MNT_USES_META)) { ump->um_root_icb.loc.lb_num += ump->um_meta_start; ump->um_root_icb.loc.part_num = part_num; } } brelse(bp); bp = NULL; if (!fsd_found) { printf("Couldn't find the fsd\n"); error = EINVAL; goto bail; } /* * Find the file entry for the root directory. */ sector = letoh32(ump->um_root_icb.loc.lb_num); size = letoh32(ump->um_root_icb.len); udf_vat_map(ump, §or); if ((error = udf_readlblks(ump, sector, size, &bp)) != 0) { printf("Cannot read sector %d\n", sector); goto bail; } xfentry = (struct extfile_entry *)bp->b_data; fentry = (struct file_entry *)bp->b_data; error = udf_checktag(&xfentry->tag, TAGID_EXTFENTRY); if (error) { error = udf_checktag(&fentry->tag, TAGID_FENTRY); if (error) { printf("Invalid root file entry!\n"); goto bail; } } brelse(bp); bp = NULL; devvp->v_specmountpoint = mp; return (0); bail: if (ump->um_hashtbl != NULL) free(ump->um_hashtbl, M_UDFMOUNT); if (ump != NULL) { free(ump, M_UDFMOUNT); mp->mnt_data = NULL; mp->mnt_flag &= ~MNT_LOCAL; } if (bp != NULL) brelse(bp); vn_lock(devvp, LK_EXCLUSIVE|LK_RETRY, p); VOP_CLOSE(devvp, FREAD, FSCRED, p); VOP_UNLOCK(devvp, 0, p); return (error); }